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


132

私が話す自由がないいくつかの理由により、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を使用してモデルを生成しています。エンティティフレームワークにこのビューのフィールドを主キーとして含めないようにする方法はありますか?

回答:


245

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

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

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

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

例:

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

2
これが期待される最高のことだと思います。要点はそれが機能することです。
MvcCmsJon 2010年

1
ありがとうございました!それは完全に機能しました。@sabanito定義を解析すると思います。そのため、IsNull()でキープロパティを具体的にラップする必要があります。nullを返さない(そしてnullを返せない)ビューがありますが、ロジックの記述方法が原因で、EFは、IsNull()でキーをラップするまで、そうであると判断できませんでした。
ラビ

3
ここで私が目にする唯一の問題は、ビューが正当に空の文字列 ''を返す必要があるかもしれないということです。私がしたことは、単に列を独自のデータ型にキャストバックすることでした。たとえば、AnotherPropertyのデータ型がvarchar(50)だった場合、「CONVERT(VARCHAR(50)、AnotherProperty)AS [AnotherProperty]」のようにキャストします。これにより、EFのnull可能性がマスクされ、空の文字列も許可されました。
バート

2
はい、これはたとえば、EFが列を主キーとして使用するように機能しますisnull(CONVERT(VARCHAR(50)、newid())、 '')AS [PK]
dc2009

2
ソリューションに迷惑なメッセージがあるだけでなく、これを修正しないと害がありますか?私はあなたの解決策に同意しますが、率直に言って、私はこれを行う必要があるとは思いません。
dyslexicanaboko 2013

67

私はこれをデザイナーを使って解決することができました。

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

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


9
確認しました。警告を消すには、VS2013を再起動する必要があります。
Michael Logutov、2014年

5
「オフにしてからもう一度オンにしてみましたか?」;-)ありがとう、魅力のように動作します!
Obl Tobl 2014

4
ビューを作成しているとき、モデルダイアグラムに表示されません。それらはxmlファイルでコメントされています
ggderas

シンプルで簡単な解決策であり、ビューを操作するほどの大げさな修正ではないようです。ありがとうございました。
LuqJensen 2016年

2
警告が消えるには、VS2017を再起動する必要があることを確認しました。
Marc Levesque

46

@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)が正しいインデックスを計画に含めるようにします。

もし


2
OPの質問に対する解決策を提供しないため、これはTillitoの回答に対するコメントであり、回答自体ではありません。
zimdanen、2012年

6
担当者の担当者は1人ですが、まだコメントを追加することはできません。
jrcs3

@zimdanenこのすべての情報をコメントに含める方法はありません。別の回答に含める方が理にかなっています。
Contango 2014年

2
@Contango:この回答は投稿されてから6日後に編集され、コメントを投稿しました。改訂履歴をご覧ください。
zimdanen 14年

9

この方法は私にはうまくいきます。主キーフィールドには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を使用して1つを偽装し、コードで無視される疑似キーを生成できます。例えば:

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

ええ、私はで浮気しましたNEWID() as idが、それは同じ考えです。そして、正当なユースケースがあります-たとえば、読み取り専用のビューがある場合。醜い、EF、醜い。
ruffin

4

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


推論されたPKにも同じ問題があります。エンティティは重複したレコードを返し、完全に迷惑です。あなたが実行した場合Context.Entity.ToList()、重複レコードを、しかし、あなたは(LINQPadで得られた)直接EFによって生成されたSQLクエリを実行した場合、何の記録重複は起こりません。説明されたロジック(null許容不可の列)を使用してPKが推定されるため、データベースレコードをエンティティオブジェクト(POCO)にマッピングする際に問題が発生しているようです。
DavidOlivánUbieto 2015

3

EdmGenの既知の問題のようです:http ://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/12aaac4d-2be8-44f3-9448-d7c659585945/


それは理にかなっている。それで、ビューで列をnullでないかnullとして定義する方法はありますか?
Sergio Romero、

1
申し訳ありませんが、私はすでにエンティティフレームワークの専門知識のレベルを超えています。:-)
RBarryYoung 2009年

1
この問題がいつ修正されるか知っている人はいますか?主キーではない非null列がある場合にこれを回避する必要があるのは面倒です。
live-love

3

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

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


3

主キーとなるものを台無しにしたくない場合は、以下をお勧めします。

  1. ROW_NUMBER選択に組み込む
  2. 主キーとして設定します
  3. 他のすべての列/メンバーをモデルの非プライマリとして設定します

1

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

これがあれば:

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

これを作成:

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

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


2
このアプローチでエンティティ間の関連付けをどのように作成しますか?出来ますか?
ggderas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.