具有外键复合键错误的实体框架

时间:2019-03-14 21:51:07

标签: c# database entity-framework composite-primary-key

我对Entity Framework有点陌生。我有一个如下定义的类,该类对应于具有由两列组成的复合外键的数据库表:GroupIDCompanyID,以及名为RegionID的第三个外键:

[Table("GroupMembers")]
public class GroupMember
{
    [Key, ForeignKey("GroupID"), Column(Order = 1)]
    public int GroupCompanyID { get; set; }

    [Key, ForeignKey("CompanyID"), Column(Order = 2)]
    public int MemberCompanyID { get; set; }

    [Column("MemberCode")]
    public string MemberCompanyCode { get; set; }

    [Column("RegionID")]
    public int RegionId { get; set; }
}

当我拥有MemberCodeGroupID的值时,我尝试以下查询来检索MemberCompanyID

var GroupMember = await repository.GroupMembers
                                  .FirstOrDefaultAsync(x => x.MemberID == memberId && 
                                                            x.CompanyID == manufacturerId);

我收到以下异常:

  

不能将属性“ GroupID”配置为导航属性。该属性必须是有效的实体类型,并且该属性应具有非抽象的getter和setter。对于集合属性,该类型必须实现ICollection,其中T是有效的实体类型

我认为我在OnModelCreating方法中丢失了一些内容,我尝试了以下操作,但没有用:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<GroupMember>()
            .HasKey(gm => new {gm.GroupID, gm.MemberID});            
}

要注意的另一件事是GroupIDMemberID都引用相同的主键列,在名为OrganizationID的表中称为Organizations,只是不同的值。我不确定这是否会影响任何事情。

有人能指出我正确的方向吗?谢谢!

1 个答案:

答案 0 :(得分:1)

该代码有点令人困惑,我不确定该如何编译。 :)我的想法是,您正在寻找更类似的东西:

[Table("GroupMembers")]
public class GroupMember
{
    [Key, ForeignKey("Group"), Column(Order = 1)]
    public int GroupCompanyID { get; set; }

    [Key, ForeignKey("Company"), Column(Order = 2)]
    public int MemberCompanyID { get; set; }

    [Column("MemberCode")]
    public string MemberCompanyCode { get; set; }

    [Column("RegionID")]
    public int RegionId { get; set; }

    public virtual Company Company { get; set; }
    public virtual Group Group { get; set; }
}

[Table("Companies")]
public class Company
{
    [Key]
    public int CompanyID { get; set; }
    public string Name { get; set; }
    // ...
}

[Table("Groups")]
public class Group
{
    [Key]
    public int GroupID { get; set; }
    // ...
}

导航属性指向相关实体,EF会将它们关联起来,以便您可以加载它们的数据并通过这些属性引用它们。

延迟加载:(注意,这可能意味着会对数据库运行额外的查询)

var groupMember = context.GroupMembers.FirstOrDefault(x => x.RegionId == 4);
var companyName = groupMember.Company.Name; // Context will check if the company is loaded and load it if needed.

急于加载:

var groupMember = context.GroupMembers
    .Include(x => x.Company)
    .Include(x => x.Group)
    .FirstOrDefault(x => x.RegionId == 4);
var companyName = groupMember.Company.Name; // Member's company (and group) already loaded above.

选择地图:(匿名类型示例)

var groupMemberDetails = context.GroupMembers
    .Where(x=> x.RegionId == 4)
    .Select(x => new 
    { 
        x.GroupId,
        x.CompanyId,
        x.RegionId,
        CompanyName = x.Company.Name
    }).FirstOrDefault();

Select可用于填充诸如ViewModel或DTO之类的东西,这是利用EF的非常强大的选项,而不会触发延迟的惰性调用。这种方法的优势在于,发送到数据库的查询仅返回填充数据所需的字段,而不是实体和相关导航属性中的所有内容。