我的问题与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中手动连接。
任何建议都将不胜感激。
答案 0 :(得分:3)
您没有遇到conditions for entity splitting:
如果满足以下条件,则只应将实体类型映射到多个表:
您要映射的表共享一个公用密钥。
正在映射的实体类型在每个基础表中都有条目。换句话说,实体类型表示在两个表之间具有一对一对应关系的数据;实体类型表示两个表的内部联接。
你比EF聪明。您知道条件EndDate == null
会产生一条记录。 EF无法知道这一点,因此永远不会知道它可以从两个表中创建一个对象。就异常消息而言:PriceId
和EndDate == null
应以某种方式提供 ProductPrice
记录的所有关键属性,这显然是不可能的。
一个。您可以在两者之间创建一对多关联并进行查询:
products.Where(p => p.ProductId == 2)
.Select(p => new
{
Product = p,
CurrentPrice = p.ProductPrices.Where(pp => pp.EndDate == null)
.FirstOrDefault()
})
不像你想的那样方便,但在包装在存储库中时可能不会太糟糕。
B中。创建数据库视图并使用单独的路径进行查看和更新(这不是一件不常见的事情)。
答案 1 :(得分: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();