web-dev-qa-db-ja.com

エンティティフレームワークとSQL Serverビュー

私が話す自由がないいくつかの理由で、SQL Server 2005データベースのビューを次のように定義しています。

CREATE VIEW [dbo].[MeterProvingStatisticsPoint]
AS
SELECT
    CAST(0 AS BIGINT) AS 'RowNumber',
    CAST(0 AS BIGINT) AS 'ProverTicketId',
    CAST(0 AS INT) AS 'ReportNumber',
    GETDATE() AS 'CompletedDateTime',
    CAST(1.1 AS float) AS 'MeterFactor',
    CAST(1.1 AS float) AS 'Density',
    CAST(1.1 AS float) AS 'FlowRate',
    CAST(1.1 AS float) AS 'Average',
    CAST(1.1 AS float) AS 'StandardDeviation',
    CAST(1.1 AS float) AS 'MeanPlus2XStandardDeviation',
    CAST(1.1 AS float) AS 'MeanMinus2XStandardDeviation'
WHERE 0 = 1

アイデアは、Entity Frameworkがこのクエリに基づいてエンティティを作成するというものですが、それを実行しますが、次のことを示すエラーでエンティティを生成します。

警告6002:テーブル/ビュー 'Keystone_Local.dbo.MeterProvingStatisticsPoint'には、定義された主キーがありません。キーが推測され、定義は読み取り専用のテーブル/ビューとして作成されました。

そして、CompletedDateTimeフィールドがこのエンティティの主キーになることを決定します。

EdmGenを使用してモデルを生成しています。エンティティフレームワークにこのビューのフィールドを主キーとして含めない方法はありますか?

130
Sergio Romero

同じ問題があり、これが解決策です。

エンティティフレームワークで列を主キーとして使用するには、ISNULLを使用します。

エンティティフレームワークで列を主キーとして使用しないようにするには、NULLIFを使用します。

これを適用する簡単な方法は、ビューの選択ステートメントを別の選択でラップすることです。

例:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp
237
Tillito

デザイナーを使用してこれを解決できました。

  1. モデルブラウザを開きます。
  2. 図でビューを見つけます。
  3. 主キーを右クリックし、「エンティティキー」がチェックされていることを確認します。
  4. すべての非主キーを複数選択します。 CtrlキーまたはShiftキーを使用します。
  5. [プロパティ]ウィンドウ(表示する必要がある場合はF4キーを押します)で、[エンティティキー]ドロップダウンをFalseに変更します。
  6. 変更内容を保存。
  7. Visual Studioを閉じて、再度開きます。私はEF 6でVisual Studio 2013を使用していますが、警告を消すにはこれを行う必要がありました。

ISNULL、NULLIF、またはCOALESCEの回避策を使用するために、ビューを変更する必要はありませんでした。データベースからモデルを更新すると、警告が再び表示されますが、VSを閉じて再度開くと消えます。デザイナで行った変更は保持され、更新の影響を受けません。

65
Casey

@Tillitoに同意しますが、ほとんどの場合、SQLオプティマイザーを汚し、正しいインデックスを使用しません。

誰にとっても明らかなことかもしれませんが、Tillitoソリューションを使用してパフォーマンスの問題を解決するのに何時間も費やしました。テーブルがあるとしましょう:

 Create table OrderDetail
    (  
       Id int primary key,
       CustomerId int references Customer(Id),
       Amount decimal default(0)
    );
 Create index ix_customer on OrderDetail(CustomerId);

あなたの見解はこのようなものです

 Create view CustomerView
    As
      Select 
          IsNull(CustomerId, -1) as CustomerId, -- forcing EF to use it as key
          Sum(Amount) as Amount
      From OrderDetail
      Group by CustomerId

SQLオプティマイザーはインデックスix_customerを使用せず、プライマリインデックスでテーブルスキャンを実行しますが、次の場合は:

Group by CustomerId

あなたが使う

Group by IsNull(CustomerId, -1)

mS SQL(少なくとも2008)に正しいインデックスを計画に含めるようにします。

もし

45
Val Bakhtin

この方法は私に適しています。主キーフィールドにはISNULL()を使用し、フィールドが主キーではなく、null不可の値を持つ必要がある場合はCOALESCE()を使用します。この例では、nullできない主キーを持つIDフィールドが生成されます。他のフィールドはキーではなく、Nullable属性として(None)があります。

SELECT      
ISNULL(P.ID, - 1) AS ID,  
COALESCE (P.PurchaseAgent, U.[User Nickname]) AS PurchaseAgent,  
COALESCE (P.PurchaseAuthority, 0) AS PurchaseAuthority,  
COALESCE (P.AgencyCode, '') AS AgencyCode,  
COALESCE (P.UserID, U.ID) AS UserID,  
COALESCE (P.AssignPOs, 'false') AS AssignPOs,  
COALESCE (P.AuthString, '') AS AuthString,  
COALESCE (P.AssignVendors, 'false') AS AssignVendors 
FROM Users AS U  
INNER JOIN Users AS AU ON U.Login = AU.UserName  
LEFT OUTER JOIN PurchaseAgents AS P ON U.ID = P.UserID

本当に主キーがない場合は、ROW_NUMBERを使用して、コードで無視される擬似キーを生成することで、主キーを偽装できます。例えば:

SELECT
ROW_NUMBER() OVER(ORDER BY A,B) AS Id,
A, B
FROM SOMETABLE
8
SpazDude

現在のEntity Framework EDMジェネレーターは、ビュー内のすべてのNULL不可フィールドから複合キーを作成します。これを制御するには、ビューと基になるテーブル列を変更して、列を主キーの一部にしたくない場合に列をNULL可能に設定する必要があります。私が遭遇したように、EDMで生成されたキーがデータ複製の問題を引き起こしていたので、その反対も真実です。そのため、EDMの複合キーにその列を含めるようにnull可能列をnull不可として定義する必要がありました。

4
Annagram
3
RBarryYoung

ビューを取得するには、one主キー列のみを表示する必要がありました。最初のビューを指す2番目のビューを作成し、NULLIFを使用して型をNULL可能にしました。これは、ビューに単一の主キーがあるとEFに思わせるのに役立ちました。

EFが主キーを持たないエンティティを受け入れるとは思わないので、これが役立つかどうかはわかりません。

3
Nick Gotch

ROW_NUMBERを選択に組み込み、それを主キーとして設定し、モデル内の他のすべての列/メンバーを非主キーとして設定するために、主キーとなるものをいじりたくない場合もお勧めします。

2
Santhos

上記の問題のため、テーブル値関数を好みます。

これがある場合:

CREATE VIEW [dbo].[MyView] AS SELECT A, B FROM dbo.Something

これを作成します:

CREATE FUNCTION MyFunction() RETURNS TABLE AS RETURN (SELECT * FROM [dbo].[MyView])

次に、ビューではなく関数をインポートします。

1
Ray