简体   繁体   中英

Confusion using CompositeId / Composite Keys in Fluent NHibernate

Please can someone explain how composite Ids work in NHibernate?

I think I am missing something. This is what I am doing.

I have a TeamMember class, called TeamMemberUnified because I am trying to link two different databases with views to create a unified database. Each TeamMember instance relates to the role a person plays at a building.

public class TeamMemberUnified: DataItem
{
    public virtual int Id { get; set; }

    // person / contact details
    public virtual byte[] ContactId { get; set; }
    public virtual Contact Contact { get; set; }        

    /// property id 
    public virtual string PropIdUnified { get; set; }
    public virtual string UnifiedDbCode { get; set; }            
    public virtual int RoleId { get; set; }

    // role the person plays at this property
    public virtual TeamRoleUnified TeamRole { get; set; }
}

The role a person plays at a building is represented by the TeamRole class. Pretty much static data / a lookup class

public class TeamRoleUnified: DataItem
{
    public virtual int RoleId { get; set; }
    public virtual string Title{ get; set; }
    public virtual string UnifiedDbCode { get; set; }

    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }

        var that = (TeamRoleUnified)obj;

        return this.RoleId == that.RoleId &&
            this.UnifiedDbCode == that.UnifiedDbCode;
    }

    public override int GetHashCode()
    {
        return RoleId.GetHashCode() ^
            UnifiedDbCode.GetHashCode();
    }
}

This is the map for TeamMember

public class TeamMemberUnifiedMap : ClassMap<TeamMemberUnified>
{
    public TeamMemberUnifiedMap()
    {
        Id(x => x.Id, "Id");
        Map(x => x.ContactId);
        Map(x => x.PropIdUnified);
        Map(x => x.UnifiedDbCode);

        // team member has one role at this building
        References(t => t.TeamRole)
           .Columns(new string[] {"RoleId", "UnifiedDbCode"});

        Table("dbo.TeamMembers");
    }
}

While the TeamRole is mapped with this class. The RoleId was a unique Id, but now I have "merged" two databases / referenced tables from two dbs in one view the RoleId is only unique within rows from each Db. The Db is qualified by the UnifiedDbCode.

public class TeamRoleUnifiedMap : ClassMap<TeamRoleUnified>
{
    public TeamRoleUnifiedMap()
    {
        CompositeId()
            .KeyProperty(x => x.RoleId)
            .KeyProperty(x => x.UnifiedDbCode);

        //References(x => x.)

        Map(x => x.RoleId);
        Map(x => x.Title);
        Map(x => x.UnifiedDbCode);

        Table("dbo.TeamRoles");
    }
}

My understanding is that I need to define a composite Id on the TeamRole to define how a row is uniquely identified.

However when I try to run the code I get this error:

{"Foreign key (FK8FB93FCE3B0D5D3E:dbo.TeamMembers [RoleId])) must have same number of columns as the referenced primary key (dbo.TeamRoles [RoleId, UnifiedDbCode])"}

A composite ID is a primary jey with multiple parts for example. Lets say we have a table:

|ID|StudentID|Name|Class|
-------------------------
|1 |10023    |Jon |FR   |
|1 |10024    |Bob |FR   |
|2 |10023    |Jon |SO   |
|3 |12234    |Joe |FR   |

In this case lets say you want to select Jon only, but for some reson JOn and Bob have an ID of 1 and that isn't uniquely identifying Jon alone. There for we have to create a composite key. So instead of a primary key being Just ID we need to use the composite primary key which would be the (ID,StudentID) Because if we just used the Student ID you see we would get two Jons but if we use the composite key of (ID,StudentID) we would get a unique identifier there is only one row with ID 1 and Student ID 10023 together. Hope this helps. So in the end you may have a two or more coluns with repeating values but those columns together may not have a uniqe value together. Hope this helps. Sorry if the table looks a little wonky.

For reference, this is working now.

This is the TeamRole Mapping on the Primary Key (The One side of the one-to-many):

  CompositeId()
     .KeyProperty(x => x.RoleId)
     .KeyProperty(x => x.UnifiedDbCode);

This is the Foreign key mapping (The Many side of the one-to-many):

  // team member has one role at this building
       References(t => t.TeamRole)
           .ForeignKey("TeamRoleFK")                                
           .Columns(new string[] {"RoleId", "UnifiedDbCode"})
           .Not.Update()
           .Not.Insert();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM