【问题标题】:Mapping association tables in EF 4.1 code first首先在 EF 4.1 代码中映射关联表
【发布时间】:2011-11-03 17:48:32
【问题描述】:

我不确定如何在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);
}

我的Product class(部分):

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; }
}

我的Specification class

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 英寸。我将如何修改代码以检索此值?我需要在我的视图上显示它。

【问题讨论】:

  • 这种“我忘了说”真的应该算“不受欢迎”。有人花时间回答您的问题,然后您输入“我忘了提及”并更改问题的形式,因此答案和花费在答案上的时间不会得到尊重。如果您忘记提及某事,请接受此问题中的答案,并提出一个新的与此相关的问题。
  • 拉迪斯拉夫是对的。您的编辑 2 使这是一个全新的问题。您现在可以在我的回答中忘记一切并从头开始映射,因为您修改后的连接表使多对多关系变得不可能。更好地提出一个新问题,或者看看这里是否有帮助:stackoverflow.com/questions/7050404/…
  • 帅哥。我会问一个新问题。我真的忘记问了。这是最初问题的一部分:)

标签: entity-framework ado.net entity-framework-4.1


【解决方案1】:

在多对多关系中,您只需为要关联的实体定义类,而不为关联表定义实体。此表在您的模型中“隐藏”并由实体框架自动管理。所以你可以定义这些类:

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 的命名约定,您可以在 Fluent 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 假定为 depends on the order of the DbSets in your context。通过更改这些集合的顺序,连接表可以是SpecificationProducts。如果没有到固定表名的显式映射,上下文中的集合交换(通常不重要)可能会破坏您的工作应用程序。

【讨论】:

    猜你喜欢
    • 2011-10-06
    • 2011-12-14
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    相关资源
    最近更新 更多