Entity framework 使用实体框架将两个相关表连接到单个实体中

Entity framework 使用实体框架将两个相关表连接到单个实体中,entity-framework,entity-framework-4,Entity Framework,Entity Framework 4,我的问题与ADO.NET实体框架中的“表连接”功能有关。 假设一个数据库包含一个表“Product”和另一个表“ProductPrice”。价格表存储产品所有价格变化的历史记录,包括开始日期和结束日期,其中包含当前价格的行由结束日期列中的空值表示。该数据库结构可用于统计目的,例如,平均每日销售量可映射到产品价格的每次变化。但是,对于在线订购网站,只需要当前价格 以下是两个表的结构: Product ProductID (PK, int, NOT NULL, auto increment) Nam

我的问题与ADO.NET实体框架中的“表连接”功能有关。 假设一个数据库包含一个表“Product”和另一个表“ProductPrice”。价格表存储产品所有价格变化的历史记录,包括开始日期和结束日期,其中包含当前价格的行由结束日期列中的空值表示。该数据库结构可用于统计目的,例如,平均每日销售量可映射到产品价格的每次变化。但是,对于在线订购网站,只需要当前价格

以下是两个表的结构:

Product
ProductID (PK, int, NOT NULL, auto increment)
Name (varchar 50, NOT NULL)

ProductPrice
ProductPriceID (PK, int, NOT NULL, auto increment)
ProductID (INT, NOT NULL)
StartDate (DATETIME, NOT NULL)
EndDate (DATETIME)
Price (MONEY, NOT NULL)
下面是一个SQL语句示例,用于检索产品加上当前价格:

SELECT Product.ProductID, Product.Name, ProductPrice.Price AS CurrentPrice
FROM Product
LEFT JOIN ProductPrice
ON Product.ProductID = ProductPrice.ProductID
AND ProductPrice.EndDate IS NULL
我想使用实体框架将实体Product和ProductPrice连接在一起,这样我就可以直接从产品实体访问当前价格,如下例所示:

var product = (from p in context.Product where p.ProductID == 2 select p).FirstOrDefault();
Console.WriteLine(product.Name);
Console.WriteLine(product.CurrentPrice);
不幸的是,我陷入了无法解决的错误中

以下是存储模型中的实体:

<EntityType Name="Product">
  <Key>
    <PropertyRef Name="ProductID" />
  </Key>
  <Property Name="ProductID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
  <Property Name="Name" Type="varchar" Nullable="false" MaxLength="50" />
</EntityType>
<EntityType Name="ProductPrice">
  <Key>
    <PropertyRef Name="ProductPriceID" />
  </Key>
  <Property Name="ProductPriceID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
  <Property Name="ProductID" Type="int" Nullable="false" />
  <Property Name="Price" Type="money" Nullable="false" />
  <Property Name="StartDate" Type="datetime" Nullable="false" />
  <Property Name="EndDate" Type="datetime" />
</EntityType>
<Association Name="FK_ProductPrice_Product">
  <End Role="Product" Type="TestingModel.Store.Product" Multiplicity="1" />
  <End Role="ProductPrice" Type="TestingModel.Store.ProductPrice" Multiplicity="*" />
  <ReferentialConstraint>
    <Principal Role="Product">
      <PropertyRef Name="ProductID" />
    </Principal>
    <Dependent Role="ProductPrice">
      <PropertyRef Name="ProductID" />
    </Dependent>
  </ReferentialConstraint>
</Association>
我不确定这在实体框架中是否可行,也许我应该自己在LINQ中手动进行连接


如果您有任何建议,我们将不胜感激。

您需要在两个表之间设置一个外键(即在ProductID列上)

然后,要检索所有产品及其价格,您需要执行以下操作:

var x = from p in context.Product where p.ProductID == 2 && p.ProductPrice.EndDate == null select new { p.ProductID, p.Name, p.ProductPrice.Price }.FirstOrDefault();
您不符合以下条件:

如果满足以下条件,则应仅将实体类型映射到多个表:

  • 要映射到的表共享一个公共键

  • 正在映射的实体类型在每个基础表中都有条目。换句话说,实体类型表示两个表之间具有一对一对应关系的数据;实体类型表示两个表的内部联接

你比EF聪明。您知道条件
EndDate==null
生成一条记录。EF不知道这一点,因此永远不知道它可以从两个表中创建一个对象。在异常消息方面:
PriceId
EndDate==null
应该以某种方式传递
ProductPrice
记录的所有关键属性,这显然是不可能的

选择: A.您可以在二者之间创建一对多关联并查询:

products.Where(p => p.ProductId == 2)
    .Select(p => new
      {
        Product = p,
        CurrentPrice = p.ProductPrices.Where(pp => pp.EndDate == null)
                       .FirstOrDefault()
      })
虽然没有您希望的那么方便,但如果包装在存储库中,可能也不会太糟糕


B.创建一个数据库视图,并使用单独的路径进行查看和更新(这不是一件不常见的事情)。

这是LINQ中的手动连接。我想要实现的是将两个表连接到概念模型中的单个实体中。这将消除在任何需要当前价格的地方重复加入的需要。我真诚地感谢您的详细回复。这就消除了歧义。
Error   1   Error 3024: Problem in mapping fragments starting at line 76:Must specify mapping for all key properties (Product.ProductID) of the EntitySet Product.
Error   2   Error 3025: Problem in mapping fragments starting at line 76:Must specify mapping for all key properties (ProductPrice.ProductPriceID) of table ProductPrice.
var x = from p in context.Product where p.ProductID == 2 && p.ProductPrice.EndDate == null select new { p.ProductID, p.Name, p.ProductPrice.Price }.FirstOrDefault();
products.Where(p => p.ProductId == 2)
    .Select(p => new
      {
        Product = p,
        CurrentPrice = p.ProductPrices.Where(pp => pp.EndDate == null)
                       .FirstOrDefault()
      })