Entity Framework с составным ключом внешних ключей ошибка

#c# #database #entity-framework #composite-primary-key

#c# #База данных #entity-framework #составной первичный ключ

Вопрос:

Я немного новичок в Entity Framework. У меня есть класс, определенный следующим образом, соответствующий таблице базы данных с составным внешним ключом, состоящим из двух столбцов: GroupID и CompanyID , а также с третьим внешним ключом, называемым 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; }
}
  

Я попытался выполнить следующий запрос, чтобы получить MemberCode когда у меня будут значения для GroupID и MemberCompanyID :

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

Я получаю следующее исключение:

Свойство ‘groupId’ не может быть настроено как свойство навигации. Свойство должно быть допустимым типом сущности, и у свойства должны быть неабстрактные средства получения и установки. Для свойств коллекции тип должен реализовывать ICollection, где T — допустимый тип сущности

Я думаю, что я что-то упускаю в OnModelCreating методе, я попробовал со следующим, но это не сработало:

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

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

Еще одна вещь, на которую следует обратить внимание, это то, что оба они GroupID и MemberID оба ссылаются на один и тот же столбец первичного ключа, который вызывается OrganizationID в таблице с именем Organizations , просто разные значения. Я не уверен, влияет ли это на что-либо.

Кто-нибудь может указать мне правильное направление? Спасибо!

Комментарии:

1. Что такое repository.CompanyGroupMembers ?

2. Извините, это была опечатка с моей стороны, я внес коррективы в GroupMembers. Спасибо!

Ответ №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.
  

Выберите Map: (пример анонимного типа)

 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 без риска отключения вызовов отложенной загрузки. Преимущество этого подхода заключается в том, что запрос, отправляемый в базу данных, возвращает только поля, необходимые для заполнения данных, а не все из объекта и связанных с ним свойств навигации.