在EF 4.1代码优先模式下映射关联表

7

我不确定如何在EF 4.1 Code First中映射以下表格,以及需要代表这些表格的对象。如何检索产品规格列表?

目前我只有一个Product类。

Products Table:
Id
Name
IsActive

ProductSpecification Table:
ProductId
SpecificationId

Specifications Table:
Id
Name
IsActive

ProductSpecifications是一个关联表。我的上下文类中还定义了以下内容:

public DbSet<Product> Products { get; set; }

编辑

请查看我更新后的原帖。我更改了产品和规格表的Id。

在我的上下文类中,我有以下内容:

public DbSet<Product> Products { get; set; }
public DbSet<Specification> Specifications { get; set; }

在我的代码库中,我有以下内容:

public Product GetById(int id)
{
     return db.Products
          .Include("Specifications")
          .SingleOrDefault(x => x.Id == id);
}

我这里展示的是我的产品类(部分代码):

public class Product : IEntity
{
     public int Id { get; set; }
     public string Name { get; set; }
     public bool IsActive { get; set; }
     public ICollection<Specification> Specifications { get; set; }
}

我的规范类

public class Specification : IEntity
{
     public int Id { get; set; }
     public string Name { get; set; }
     public bool IsActive { get; set; }
     public ICollection<Product> Products { get; set; }
}

这是我从Slauma的答案中采用的所有内容。 我没有像他说的那样手动进行映射,但首先需要了解以下内容:
考虑到上面的我的类和表,EF 4.1命名约定确切地说明它如何处理关联表?我之所以问这个问题,是因为在我的GetById方法中会出现以下错误:
Invalid object name 'dbo.SpecificationProducts'.

编辑2

我忘记提到以下内容了 :) 一个产品可以有一个规格高度的值。对于这个高度,我需要指定一个值。比如100英寸。因此,我修改了ProductSpecifications表,添加了一个称为SpecificationValue的值列,该列将包含值100英寸。我应该如何修改代码以检索这个值呢?我需要在我的视图上显示它。


1
这种“我忘了提到”的行为应该被视为“不受欢迎”。有人花时间回答你的问题,然后你说“我忘了提到”,改变了问题的形式,导致回答和花费在回答上的时间没有得到尊重。如果你忘记了提到某些事情,请在这个问题中接受答案,并提出一个新的问题,参考这个问题。 - Ladislav Mrnka
1
Ladislav是正确的。您的Edit 2使这成为一个全新的问题。您现在可以忘记我在答案中提到的所有内容,从头开始进行映射,因为您修改后的连接表使得多对多关系不可能。最好提出一个新问题或者看看这里是否有帮助:https://dev59.com/zGw05IYBdhLWcg3wwEYS#7053393 - Slauma
酷哥们,我要问一个新问题。我真的忘了问它。它是最初的问题的一部分 :) - Brendan Vogt
1个回答

12
在多对多的关系中,您只需定义要关联的实体类,而不需要为关联表定义一个实体。这个表在您的模型中是“隐藏”的,并由Entity Framework自动管理。因此,您可以定义这些类:
public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }

    public ICollection<Specification> Specifications { get; set; }
}

public class Specification
{
    public int SpecificationId { get; set; }
    public string Name { get; set; }

    public ICollection<Product> Products { get; set; }
}

这通常足以定义多对多关系。EF将从此映射创建联接表。如果您已经在数据库中拥有这样的表,且其命名不完全遵循Entity Framework的命名约定,则可以在流畅API中手动定义映射:

modelBuilder.Entity<Product>()
    .HasMany(p => p.Specifications)
    .WithMany(s => s.Products)
    .Map(c =>
        {
            c.MapLeftKey("ProductId");
            c.MapRightKey("SpecificationId");
            c.ToTable("ProductSpecification");
        });

编辑

你可以使用Include来加载产品的规格,例如:

var productWithSpecifications = context.Products
    .Include(p => p.Specifications)
    .SingleOrDefault(p => p.ProductId == givenProductId);

这将加载与规格一起的产品。如果您只想获取给定产品ID的规格,可以使用以下内容:

var specificationsOfProduct = context.Products
    .Where(p => p.ProductId == givenProductId)
    .Select(p => p.Specifications)
    .SingleOrDefault();

...它返回一个规范集合。

编辑2

EF Code-First的命名约定假设联结表的名称是相关类名称的组合,然后将其复数化。因此,如果没有映射到您的表名ProductSpecification,EF将假定ProductSpecifications(复数形式)并使用该名称作为表名构建查询。因为这个表在数据库中不存在,所以运行查询时会出现异常"Invalid object name 'dbo.SpecificationProducts'."。因此,您必须重命名数据库中的表或使用上面的映射代码。

编辑3

我强烈建议在任何情况下都使用显式映射,因为EF假定的联结表名称取决于上下文中DbSets的顺序。通过更改这些集合的顺序,联结表可能会变成SpecificationProducts。如果没有映射到固定表名,上下文中集合的(通常不重要的)交换可能会破坏您的应用程序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接