2

私の質問は、ADO.NETEntityFrameworkの「テーブル結合」機能に関するものです。テーブル「Product」と別のテーブル「ProductPrice」を含むデータベースを想像してみてください。価格テーブルには、製品のすべての価格変更の履歴が開始日と終了日とともに格納されます。現在の価格を含む行は、終了日列にNULL値で示されます。このデータベース構造は、統計目的に役立つ可能性があります。たとえば、1日の平均販売量を、製品価格の各変化にマッピングできます。ただし、オンライン注文Webサイトの場合、現在の価格のみが必要です。

2つのテーブルの構造は次のとおりです。

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

次の例のように、Entity Frameworkを使用してエンティティ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>

そして最後に、2つの間のマッピング:

<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.

これがEntityFrameworkでも可能かどうかはわかりませんが、LINQで自分で手動で結合する必要があるかもしれません。

任意の提案をいただければ幸いです。

4

2 に答える 2

3

エンティティ分割の条件を満たしていません:

次の条件に該当する場合にのみ、エンティティ タイプを複数のテーブルにマップする必要があります。

  • マッピング先のテーブルは共通のキーを共有しています。

  • マップされているエンティティ タイプには、基になる各テーブルにエントリがあります。つまり、エンティティ タイプは、2 つのテーブル間で 1 対 1 で対応するデータを表します。エンティティ タイプは、2 つのテーブルの内部結合を表します。

あなたは EF より賢いです。EndDate == null条件によって1 つのレコードが生成されることがわかっています。EF はそれを知る手がかりがないため、2 つのテーブルから 1 つのオブジェクトを作成できることを決して知りません。例外メッセージに関しては、どうにかしてレコードのすべての主要なプロパティPriceIdを提供する必要がありますが、これは明らかに不可能です。EndDate == nullProductPrice

代替案:

A. 2 つのクエリとの間に 1 対多の関連付けを作成できます。

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

2つのテーブル間(つまり、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 に答える