KB Article A958
Visible to All Users

How to change the name of the underlying table and columns for a many-to-many relationship

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 Basic
Imports 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 Basic
Imports 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

Show previous comments (2)

    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

      DevExpress Support Team 13 years ago

        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.

        Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

        Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.