2

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

这是两个表的结构:

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 连接在一起,这样我就可以直接从 Product 实体访问当前价格,如下例所示:

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>

从概念模型:

<EntityType Name="Product">
  <Key>
    <PropertyRef Name="ProductID" />
  </Key>
  <Property Name="ProductID" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
  <Property Name="Name" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="false" />
  <Property Name="SKU" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="false" />
  <Property Type="Decimal" Name="CurrentPrice" Nullable="false" Precision="19" Scale="4" />
</EntityType>

最后是两者之间的映射:

<EntitySetMapping Name="Product">
  <EntityTypeMapping TypeName="TestingModel.Product">
    <MappingFragment StoreEntitySet="Product">
      <ScalarProperty Name="ProductID" ColumnName="ProductID" />
      <ScalarProperty Name="Name" ColumnName="Name" />
      <ScalarProperty Name="SKU" ColumnName="SKU" />
    </MappingFragment>
  </EntityTypeMapping>
  <EntityTypeMapping TypeName="IsTypeOf(TestingModel.Product)">
    <MappingFragment StoreEntitySet="ProductPrice">
      <ScalarProperty Name="CurrentPrice" ColumnName="Price" />
      <Condition ColumnName="EndDate" IsNull="true" />
    </MappingFragment>
  </EntityTypeMapping>
</EntitySetMapping>

以下是我目前正在努力解决的错误消息:

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.

我不确定实体框架是否可以做到这一点,也许我应该自己在 LINQ 中手动进行连接。

任何建议将不胜感激。

4

2 回答 2

3

您不符合实体拆分条件

仅当满足以下条件时,才应将实体类型映射到多个表:

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

  • 被映射的实体类型在每个基础表中都有条目。也就是说,实体类型表示的是两个表之间一一对应的数据;实体类型表示两个表的内部连接。

你比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. 创建数据库视图并使用单独的路径进行查看和更新​​(这并不罕见)。

于 2012-04-17T20:35:18.807 回答
0

您需要在两个表之间做一个外键(即在列 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();
于 2012-04-15T14:24:08.567 回答