Сначала извлекается значение из таблицы ассоциации в коде Entity Framework - PullRequest
4 голосов
/ 04 ноября 2011

Я использую EF 4.1 code first, и я борюсь с объектом ассоциации и получаю значение, которое было установлено в таблице ассоциации. Я попытался подписаться на пост: Сначала создайте код, многие ко многим, с дополнительными полями в таблице ассоциаций .

Мои таблицы следующие (все в форме множественного числа):

Таблица: Продукция

Id int
Name varchar(50)

Таблица: Технические характеристики

Id int
Name varchar(50)

Таблица: технические характеристики изделия

ProductId int
SpecificationId int
SpecificationValue varchar(50)

Мои родственные классы:

public class Product : IEntity
{
     public int Id { get; set; }
     public string Name { get; set; }
     public virtual ICollection<ProductSpecification> ProductSpecifications { get; set; }
}

public class Specification : IEntity
{
     public int Id { get; set; }
     public string Name { get; set; }
     public virtual ICollection<ProductSpecification> ProductSpecifications { get; set; }
}

public class ProductSpecification
{
     public int ProductId { get; set; }
     public virtual Product Product { get; set; }
     public int SpecificationId { get; set; }
     public virtual Specification Specification { get; set; }
     public string SpecificationValue { get; set; }
}

Мой контекстный класс:

public class MyContext : DbContext
{
     public DbSet<Product> Products { get; set; }
     public DbSet<Specification> Specifications { get; set; }
     public DbSet<ProductSpecification> ProductSpecifications { get; set; }

     protected override void OnModelCreating(DbModelBuilder dbModelBuilder)
     {
     }
}

Мой метод хранилища, в котором я выполняю вызов (не уверен, что он правильный):

public class ProductRepository : IProductRepository
{
     MyContext db = new MyContext();

     public Product GetById(int id)
     {
          var product = db.Products
               .Where(x => x.Id == id)
               .Select(p => new
               {
                    Product = p,
                    Specifications = p.ProductSpecifications.Select(s => s.Specification)
               })
               .SingleOrDefault();

          return null;  // It returns null because I don't know how to return a Product object?
     }
}

Вот ошибка, которую я получаю:

One or more validation errors were detected during model generation:

System.Data.Edm.EdmEntityType: : EntityType 'ProductSpecification' has no key defined. Define the key for this EntityType.
 System.Data.Edm.EdmEntitySet: EntityType: EntitySet �ProductSpecifications� is based on type �ProductSpecification� that has no keys defined.

Что означает, что ключи не определены? Разве ProductId и SpecificationId не будут соответствовать Id продукта и Id спецификации соответственно?

Как бы я вернул один продукт со всеми спецификациями для него?

1 Ответ

1 голос
/ 04 ноября 2011

Entity Framework распознает, что ProductId является внешним ключом для свойства навигации Product, а SpecificationId является внешним ключом для навигации Specification имущество. Но исключение жалуется на отсутствующий первичный ключ ("Ключ" = "Первичный ключ") в вашей сущности ProductSpecification. Каждой сущности необходимо определить ключевое свойство. Это может происходить либо по соглашениям - по конкретному именованию свойства ключа - либо по простоте с аннотациями данных или Fluent API.

Ваш ProductSpecification класс не имеет свойства, которое EF распознает как ключ по соглашению: нет Id свойства и нет ProductSpecificationId (имя класса + "Id").

Так что вы должны определить это явно. Определение этого с помощью аннотации данных показано в сообщении, которое вы связали:

public class ProductSpecification
{
    [Key, Column(Order = 0)]
    public int ProductId { get; set; }
    public virtual Product Product { get; set; }

    [Key, Column(Order = 1)]
    public int SpecificationId { get; set; }
    public virtual Specification Specification { get; set; }

    public string SpecificationValue { get; set; }
}

А в Fluent API это будет:

modelBuilder.Entity<ProductSpecification>()
    .HasKey(ps => new { ps.ProductId, ps.SpecificationId });

Оба способа определяют составной ключ, и каждая из частей является внешним ключом для таблицы Product или Specification одновременно. (Вам не нужно задавать свойства FK явно, потому что EF распознает их из-за их удобных имен.)

Вы можете вернуть товар со всеми техническими характеристиками со стремительной загрузкой, например:

var product = db.Products
    .Include(p => p.ProductSpecifications.Select(ps => ps.Specification))
    .SingleOrDefault(x => x.Id == id);
...