Description:
I want to map my many-to-many relationship to the existing tables but cannot find how to setup mapping to my table and columns. Is this possible?
Answer:
Many-to-many relationship is implemented via an intermediate type, which has a specific name and properties. Names of the class and its properties are composed from the many-to-many association name and collection property names. Though you cannot change XPO's naming rules, you can change names in metadata of persistent classes. Here is some sample code:
C#using DevExpress.Xpo;
public class User : XPObject {
...
[Association("Users-Roles", typeof(Role))]
public XPCollection Roles { get { return GetCollection(nameof(Roles)); } }
}
public class Role : XPObject {
...
[Association("Users-Roles", typeof(User))]
public XPCollection Users { get { return GetCollection(nameof(Users)); } }
}
...
using DevExpress.Xpo;
using DevExpress.Xpo.Metadata;
ReflectionDictionary dictionary = new ReflectionDictionary();
XpoDefault.DataLayer = ...
XpoDefault.Dictionary = dictionary;
XPClassInfo classInfo = dictionary.GetClassInfo(typeof(User));
XPMemberInfo memberInfo = classInfo.GetMember(nameof(User.Roles));
memberInfo.IntermediateClass.AddAttribute(new PersistentAttribute("RolesToUsers"));
memberInfo.IntermediateClass.GetMember(nameof(User.Roles)).AddAttribute(new PersistentAttribute("RoleID"));
memberInfo.IntermediateClass.GetMember(nameof(Role.Users)).AddAttribute(new PersistentAttribute("UserID"));
memberInfo.IntermediateClass.KeyProperty.AddAttribute(new PersistentAttribute("ID"));
Visual BasicImports DevExpress.Xpo
Class User
Inherits XPObject
...
<Association("Users-Roles")> _
Public ReadOnly Property Roles As XPCollection(Of Role)
Get
Return GetCollection(Of Role)(NameOf(Roles))
End Get
End Property
End Class
Class User
Inherits XPObject
...
<Association("Users-Roles")> _
Public ReadOnly Property Users As XPCollection(Of User)
Get
Return GetCollection(Of User)(NameOf(Users))
End Get
End Property
End Class
...
Imports DevExpress.Xpo
Imports DevExpress.Xpo.Metadata
Dim dictionary As New ReflectionDictionary()
XpoDefault.DataLayer = ...
XpoDefault.Dictionary = dictionary
Dim classInfo As XPClassInfo = dictionary.GetClassInfo(GetType(User))
Dim memberInfo As XPMemberInfo = classInfo.GetMember(NameOf(User.Roles))
memberInfo.IntermediateClass.AddAttribute(New PersistentAttribute("RolesToUsers"))
memberInfo.IntermediateClass.GetMember(NameOf(User.Roles)).AddAttribute(New PersistentAttribute("RoleID"))
memberInfo.IntermediateClass.GetMember(NameOf(Role.Users)).AddAttribute(New PersistentAttribute("UserID"))
memberInfo.IntermediateClass.KeyProperty.AddAttribute(New PersistentAttribute("ID"))
Metadata is stored in a dictionary. Each Session has a dictionary by default (for backward compatibility with XPO 1.x). It's recommended that you explicitly create a data layer or a dictionary for the XpoDefault object to make all sessions use one and the same dictionary. In this case, you can patch metadata only once as shown above.
If you only need to change the name of the intermediate table and don't care about columns' names, there is a simpler solution: the UseAssociationNameAsIntermediateTableName property of the Association attribute. If you use it, please make sure that the association name exactly matches the intermediate table name in your database.
C#using DevExpress.Xpo;
public class User : XPObject {
...
[Association("RolesToUsers", typeof(Role), UseAssociationNameAsIntermediateTableName=true)]
public XPCollection Roles { get { return GetCollection("Roles"); } }
}
public class Role : XPObject {
...
[Association("RolesToUsers", typeof(User), UseAssociationNameAsIntermediateTableName=true)]
public XPCollection Users { get { return GetCollection("Users"); } }
}
Visual BasicImports DevExpress.Xpo
Class User
...
<Association("RolesToUsers", UseAssociationNameAsIntermediateTableName:=True)> _
Public ReadOnly Property Roles As XPCollection(Of Role)
...
End Property
End Class
Class User
...
<Association("RolesToUsers", UseAssociationNameAsIntermediateTableName:=True)> _
Public ReadOnly Property Users As XPCollection(Of User)
...
End Property
End Class
See Also:
What is the best solution for mapping a many-to-many relation to an existing database?
How to introduce some properties and logic into my many-to-many relation
where the above code should be added in window AFX application?
Could you please explain what AFX application is? Do you mean MFC (originally "Application Framework Extensions")? XPO cannot be used in MFC applications directly, because XPO is based on the .NET Framework.
If you meant the XAF application (eXpressApp Framework), you can add a custom controller and override its CustomizeTypesInfo method to modify metadata. Feel free to ask a question in our Support Center if you need further assistance in this regard.
What I means XAF, sorry, I want to know where the following code should be:
…
using DevExpress.Xpo;
using DevExpress.Xpo.Metadata;
ReflectionDictionary dictionary = new ReflectionDictionary();
XpoDefault.DataLayer = …
XpoDefault.Dictionary = dictionary;
XPClassInfo classInfo = dictionary.GetClassInfo(typeof(User));
XPMemberInfo memberInfo = classInfo.GetMember("Roles");
memberInfo.IntermediateClass.AddAttribute(new PersistentAttribute("RolesToUsers"));
membe
Hi;
In fact I have a following senerio:
There two table in existing database: Account and Exchange each one represent an entity, also there is table new_account_new_exchange, this one store a many to many relationship between Account and Exchange, there are 4 coloumn in this table: they are: [new_account_new_exchangeId],
[VersionNumber],
[accountid],
[new_exchangeid]
here accountid is the ID of Account, and new_exchangeid is the ID of Exchange.
Thw question now is to
Thank you for the clarification. You can modify metadata within the CustomizeTypesInfo method as I said above. You can find a code snippet here: CustomizeTypesInfo: change or modify attributes. If you need further clarification, please create a new Support Centerticket.