エンティティフレームワーク:主キーのないテーブル


165

を使用して新しいアプリを構築したい既存のDBがあります EF4.0

一部のテーブルには主キーが定義されていないため、新しいエンティティデータモデルを作成すると、次のメッセージが表示されます。

The table/view TABLE_NAME does not have a primary key defined 
and no valid primary key could be inferred. This table/view has 
been excluded. To use the entity, you will need to review your schema, 
add the correct keys, and uncomment it.

それらを使用してデータを変更する場合、それらのテーブルに必ずPKを追加する必要がありますか、それとも回避するための回避策はありますか?


21
Joe Celkoを引用すると、主キーがない場合、それはテーブルではありません。いったい誰が主キーなしで「通常の」テーブルを作成するのでしょうか?それらのPKを追加するだけです!あなたはそれらを必要とするでしょう
遅くなる

4
そのaがこのHAVAに見て、この場合は、表示した場合stackoverflow.com/a/10302066/413032
DavutGürbüz

50
すべてのテーブルが主キーを必要とするわけではないことは完全に有効です。多くの場合、有用ではありませんが、有効です。EFの混乱は1つの理由であり、それほど時間がかかるわけではありません。;-)。
Suncat2000 2013年

25
私の会社ではDB構造を変更できず、テーブル構造を変更しない誰かが作成したと想像してください。このシナリオは可能です。
ティト

4
これがまさに私たちがいるところです。主キーのないサードパーティのOracleデータベースを使用する必要があります。
David Brower、2016年

回答:


58

エラーはそれが言っていることを正確に意味します。

これを回避できたとしても、私を信じてください。導入される可能性のある紛らわしいバグの数は驚異的で恐ろしいものです。もちろん、パフォーマンスが低下する可能性があるという事実は言うまでもありません。

これを回避しないでください。データモデルを修正します。

編集:私は多くの人々がこの質問に反対票を投じているのを見てきました。それは問題ないと思いますが、OPはビューではなく主キーなしでテーブルをマッピングすることについて尋ねたことを覚えておいてください。答えは同じです。テーブルにPKが必要なEFの必要性を回避することは、管理性、データの整合性、およびパフォーマンスの観点からは悪い考えです。

サードパーティのアプリケーションにマッピングしているため、基になるデータモデルを修正する機能がないとコメントした人もいます。モデルはあなたの下から変わる可能性があるので、それは良い考えではありません。おそらく、その場合、ビューにマップする必要がありますが、これもOPが要求したものではありません。


44
一般的なシナリオでは同意しますが、LOGテーブルのようなまれなシナリオでは、できるだけ早くレコードを挿入する必要があります。一意性のチェックとインデックス作成が行われる場合、PKが問題になることがあります。また、PKがIDENTITYの場合、生成された値をEFに返すことも別の問題です。代わりにGUIDを使用しますか?生成時間とインデックス作成/並べ替えは別の問題です!...一部の重要なOLTPシナリオ(Loggingなど)では、PKがないことはポイントであり、それを持つことには肯定的なポイントがありません。
Mahmoud Moravej 2012年

5
@MahmoudMoravej:まず、クラスター化インデックスと主キーのアイデアを混同しないでください。それらは同じものではありません。IDENTITY列にクラスター化されたインデックスを持つテーブルで、非常にパフォーマンスの高い挿入を行うことができます。インデックスのメンテナンスで問題が発生した場合は、テーブルを適切にパーティション分割する必要があります。クラスタ化インデックスのないテーブルを残すことは、削除後にスペースを再利用するために効果的にデフラグできないことも意味します。ロギングテーブルにインデックスがない場合にクエリを実行しようとする貧しい人に同情しています。
Dave Markle、2012年

149
「データモデルを修正する」というのは現実的な答えではありません。時には、私たちが作成しなかった、変更できない理想的ではない状況で生活しなければなりません。そして、@ Colinが言ったように、OPが要求していたことを正確に行う方法があります。
TheSmurf、

13
EFを満たすためにコードを変更すること自体が回避策です。すべてのテーブルが主キーを必要とするわけでも、強制される必要もありません。たとえば、トピックがあり、キーワードが0個または多数あるとします。キーワードテーブルには、親トピックIDと対応するキーワードを含めることができます。EFが私を無理にさせるので、DBを改造する必要があると言います。
Mrchief

14
これは質問に答えないため、反対票を投じるべきです。多くの場合、変更できないサードパーティのデータベースを使用する必要があります。
Kurren 2014

104

これはTillitoによって解決されると思います:

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

以下に彼のエントリーを引用します。

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

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

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

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

例:

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

追加された26 4月2010〜で17:00ティリート


6
+1これは正しい答えです。完璧な世界では、すべてのレガシーデータベースにアクセスして変更し、参照整合性を持たせるのは素晴らしいことですが、実際には常にそうであるとは限りません。
ディランヘイズ2013年

9
これはお勧めしません。特にISNULL部分。EFが2つのPKを同じように検出した場合、一意のレコードをレンダリングせず、代わりに共有オブジェクトを返すことがあります。これは以前に私に起こりました。
トッド

@Todd-MyPrimaryIDがNOT NULL列である場合、どうしてこれが起こるでしょうか?
JoeCool 2014年

@JoeCool、それがNULLではないからといって、それが一意であることを意味しません。「THIS SOLUTION WORKS ...」を賛成しました。使用されるコンテキストに関係なく、一意性が保証されます。今考えていますが、レコードを削除すると次のレコードの「PK」が実質的に変わります。
トッド、

1
-1。これは、エンティティフレームワーク/ C#コードを構成して、IDシードのないテーブルにマップする方法を処理する方法に答えないためです。一部のサードパーティソフトウェアは、(何らかの理由で)このように記述されています。
Andrew Grey

27

それらを使用してデータを変更する場合、それらのテーブルに必ずPKを追加する必要がありますか、それとも回避するための回避策はありますか?

この質問に到達し、Entity Framework Coreを使用している場合、これらのテーブルにPKを追加したり、回避策を実行したりする必要はありません。EF Core 2.1以降、クエリタイプに新機能が追加されました

クエリタイプは次の場合に使用する必要があります。

  • アドホックFromSql()クエリの戻り型として機能します。
  • データベースビューへのマッピング。
  • 主キーが定義されていないテーブルへのマッピング。
  • モデルで定義されたクエリへのマッピング。

したがって、DbContextには、以下DbQuery<T>DbSet<T>ようにではなく、typeの次のプロパティを追加するだけです。あなたのテーブル名がMyTable

public DbQuery<MyTable> MyTables { get; set; }

1
EF Coreを使用している場合は、ベストアンサーです。
Jay

17

複合キーはEntity Framework Fluent APIでも実行できます

public class MyModelConfiguration : EntityTypeConfiguration<MyModel>
{
     public MyModelConfiguration()
     {
        ToTable("MY_MODEL_TABLE");
        HasKey(x => new { x.SourceId, x.StartDate, x.EndDate, x.GmsDate });
        ...
     }
}

この種の「手動マッピング」のケースでは、表示されているカスタムキーを指定することが効果的であることがわかりました。さらに、(この回答に示されているように)複合キーの利点がない場合は、自然または複合ではないが信頼できるそれらの非常に特殊なキーのmodelBuilder.Entity<T>()チェーン呼び出しにタグを付ける.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)ことができます。 (通常、とにかく)ユニークになる
Andrew Grey

5

私の場合、エンティティをビューにマップする必要がありましたが、ビューには主キーがありませんでした。さらに、このビューを変更することはできませんでした。幸い、このビューには一意の文字列である列がありました。私の解決策は、この列を主キーとしてマークすることでした:

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[StringLength(255)]
public string UserSID { get; set; }

EFをだましました。完璧に動作し、誰も気づかなかった... :)


いいえ。CodeFirst UserIDアプローチを使用すると、列が作成されます。
Deepak Sharma

1
あなたはEFをだましていません。Itentity機能をオフにするように命令しました。基本的に、私が正しい場合、UserIDPKとして列が作成されますがUserID、新しいレコードを作成するときに、デフォルトのように列が自動的に増加することはありません。また、引き続きに個別の値を保持する必要がありますUserID
セルドール2015年

1
@Celdor UserSIDは文字列であり、「自動的に増加」することはありません。整数のID列の場合、データベースはEntity Frameworkではなく、挿入時に列を増分します。
reggaeguitar 2017

4

EFでは、データベースに主キーは必要ありません。存在する場合、エンティティをビューにバインドできません。

SSDL(およびCSDL)を変更して、一意のフィールドを主キーとして指定できます。あなたがユニークなフィールドを持っていないなら、私はあなたが夢中になっていると信じています。ただし、実際には固有のフィールド(およびPK)が必要です。そうしないと、後で問題が発生します。

エリック


これにより、ISNULLハックが回避されます。しかし、状況によっては、他の回答が必要になる場合があります。たとえば、EFのPKでは一部のデータ型がサポートされていないと感じています。
トッド

3

役に立たないIDキーがあっても意味がない場合があります。IDが使用されていない場合は、なぜ追加するのですか?ただし、エンティティはそれほど寛容ではないため、IDフィールドを追加することをお勧めします。使用されていない場合でも、欠落しているIDキーに関するエンティティの継続的なエラーを処理するよりも優れています。


3

このソリューションは機能します

PKがない場合でも、手動でマップする必要はありません。EFに、列の1つがインデックスであり、インデックス列はnullにできないことを通知するだけです。

これを行うには、次のようなisNull関数を使用してビューに行番号を追加します。

select 
    ISNULL(ROW_NUMBER() OVER (ORDER BY xxx), - 9999) AS id
from a

ISNULL(id, number) この列が主キーになる可能性があることをEFに通知するため、ここで重要なポイントです


2
ただし、ISNULLの部分はお勧めしません。EFが同じ2つのPKを検出した場合、一意のレコードをレンダリングせず、代わりに共有オブジェクトを返すことがあります。これは以前に私に起こりました。
トッド

1
isnullを使用する必要があります。そうしないと、EFはnullを使用できないことを許容しません。
Archlight 2014

2

上記の答えは、本当にPKがない場合に正解です。

しかし、1つはあるがDBのインデックスで指定されていないだけで、DBを変更できない場合(そう、私はディルバートの世界で働いています)、フィールドを手動でキーにマップできます。


2

これは、@ Erick Tの回答への追加にすぎません。一意の値を持つ単一の列がない場合の回避策は、次のように複合キーを使用することです。

[Key]
[Column("LAST_NAME", Order = 1)]
public string LastName { get; set; }

[Key]
[Column("FIRST_NAME", Order = 2)]
public string FirstName { get; set; }

繰り返しますが、これは単なる回避策です。実際の解決策は、データモデルを修正することです。


2

これはたぶん返信が遅くなるかもしれません...しかし...

テーブルに主キーがない場合、EFを適切に機能させるために分析する必要があるシナリオはほとんどありません。ルールは次のとおりです。EFは主キーを持つテーブル/クラスで機能します。これが追跡の方法です...

たとえば、テーブル1.レコードは一意です。一意性は単一の外部キー列によって作成されます。2。レコードは一意です。一意性は複数の列の組み合わせによって作成されます。3.レコードは一意ではありません(ほとんどの場合*)。

シナリオ#1と#2の場合、DbContextモジュールのOnModelCreatingメソッドに次の行を追加できます。//レコードを一意にするために必要な数の列。

シナリオ#3の場合、テーブルを調べた後も上記のソリューション(#1 +#2)を使用できます(*すべてのレコードが一意になる理由)。すべてのレコードを一意にするためにALL列を含める必要がある場合は、テーブルに主キー列を追加することができます。このテーブルがサードパーティベンダーのものである場合は、このテーブルをローカルデータベースに(夜間または必要な回数だけ)クローンし、クローンスクリプトを使用して任意の主キー列を追加します。


1
  1. テーブル構造を変更し、プライマリ列を追加します。モデルを更新する
  2. XMLエディターで.EDMXファイルを変更し、この特定のテーブルのタグの下に新しい列を追加してみてください(機能しません)
  3. 既存の列に新しいプライマリ列を作成する代わりに、既存のすべての列を含めることで複合キーを作成します(WORKED

エンティティフレームワーク:主キーのないDataTableをエンティティモデルに追加します。


EF 4.0で複合キーアプローチを試しましたが、機能しませんでした。
ラルフウィルゴス

このアプローチは私にとっては完璧に機能しましたが、「時々」レガシーシステムを
操作するのは面倒かもしれませ

1

@CodeNotFoundの回答を更新します。

EF Core 3.0 DbQuery<T>では非推奨になりました。代わりに、おそらく同じことを行うキーレスエンティティタイプを使用する必要があります。これらは、ModelBuilder HasNoKey()メソッドで構成されます。DbContextクラスで、これを行います

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<YourEntityType>(eb =>
        {
            eb.HasNoKey();
        });

}

ただし、特に制限があります。

  • DbContextの変更が追跡されることはないため、データベースで挿入、更新、削除されることはありません。
  • ナビゲーションマッピング機能のサブセットのみをサポートします。具体的には次のとおりです。
    • 彼らは関係の主要な終わりとして決して行動しないかもしれません。
    • 所有エンティティへのナビゲーションがない可能性があります
    • 通常のエンティティを指す参照ナビゲーションプロパティのみを含めることができます。
    • エンティティには、キーレスエンティティタイプへのナビゲーションプロパティを含めることはできません。

これは、

それらを使用してデータを変更する場合、それらのテーブルに必ずPKを追加する必要がありますか、それとも回避するための回避策はありますか?

この方法でデータを変更することはできませんが、読み取ることはできます。ただし、別の方法(ADO.NET、Dapperなど)を使用してデータを変更することを想定することもできます。これは、読み取り以外の操作をほとんど行う必要がなく、大多数のケースでEF Coreを使い続けたい場合の解決策になります。

また、ヒープ(キーレス)テーブルを本当に操作する必要がある場合は、EFを破棄し、別の方法でデータベースと通信することを検討してください。


0

実用的な観点からは、ウェアハウステーブルのような非正規化テーブルであっても、すべてのテーブルに主キーが必要です。または、これに失敗すると、少なくとも一意でnullにできないインデックスが必要です。

なんらかの一意のキーがないと、重複したレコードがテーブルに表示される可能性があり、また表示されます。これは、ORMレイヤーとデータの基本的な理解の両方に非常に問題があります。レコードが重複しているテーブルは、おそらく設計が悪い兆候です。

少なくとも、テーブルには少なくともID列が必要です。自動生成ID列の追加には、SQL Serverでは約2分、Oracleでは5分かかります。その余分な努力により、多くの問題が回避されます。


私のアプリケーションはデータウェアハウスの設定(Oracleを使用)にあり、インデックスを追加するために5分間実行するように説得されました。実際には5分しかかかりません(それを調べたり、ETLを変更する必要がある場合は、わずかに長くかかります)。
トレント

0

この問題も発生しました。ヌルのある列がある場合、重要なのは、ヌルのない従属列があり、これら2つの列の組み合わせが一意であることです。

したがって、Pratap Reddyの回答を引用すると、それはうまく機能しました。


0

私の問題が解決されてとても嬉しいです。

EntitySetを更新できません-DefiningQueryがあり、<UpdateFunction>要素が存在しないため

そしてこれを行います:その行の下を見て、タグを見つけます。それには大きな古いselectステートメントが含まれます。タグを削除すると、その内容がわかります。

DBを変更せずに、TIはPKがないテーブルに挿入できます

すべてに感謝し、ファリロンに感謝



弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.