エンティティフレームワークに挿入されたエンティティのIDを取得するにはどうすればよいですか?[閉まっている]


611

Asp.netのEntity Frameworkに問題があります。オブジェクトをデータベースに追加するたびにId値を取得したい。これどうやってするの?


16
以下のLadislav Mrnkaの答えは正解であり、そのように受け入れる必要があります。
CShark 2016年

3
OPは自分のアカウントで一度だけ投稿しました。この質問はより具体的です。これにより、彼の評判はほぼ2kになりました(!)。その日からアカウントが中止されたため、回答は承認済みとしてマークされません。
MurariAlex 2017

1
Idが外部キー関係で使用するためだけに必要な場合は、代わりに依存エンティティのナビゲーションプロパティを以前に追加したエンティティに設定することを検討できます。これによりSaveChanges、IDを取得するためだけにすぐに電話をかける必要がなくなります。詳細はこちら
B12Toaster

Entity Framework Core 3.0の場合、acceptAllChangesOnSuccessパラメーターをtrueとして追加します。await _context.SaveChangesAsync(true);
マイク

回答:


1006

とても簡単です。あなたはDBを使用している場合(のようなのIdsを生成したIDENTITYあなただけにエンティティを追加する必要があるMS SQLでの)ObjectSetおよびSaveChanges関連でObjectContextId自動的に入力されます:

using (var context = new MyContext())
{
  context.MyEntities.Add(myNewObject);
  context.SaveChanges();

  int id = myNewObject.Id; // Yes it's here
}

エンティティフレームワークは、デフォルトINSERTではSELECT SCOPE_IDENTITY()、自動生成されたIdが使用されるときにそれぞれ従います。


34
だからあなたは間違った質問をしています。例外に問題がある場合は、例外(および内部例外)とそのエラーの原因となるコードスニペットを示す質問をする必要があります。
Ladislav Mrnka、2011年

3
ことを確認し、追加するエンティティが有効なエンティティなどで、「NOT NULL」のデータベースの制約を使って何がなどが満たされなければならないこと。
フラン

4
@LadislavMrnka:新しく作成されたオブジェクトのナビゲーションプロパティはどうですか?変更を保存した後、自動的に入力されていないようです。
Isaac Kleinman 2014

4
次のシナリオを考えてみましょう:table1は、@@ identityを生成してtable2で使用することになっています。たとえば、1つのSaveChange操作で両方のテーブルのデータを保存する必要がある場合、table1とtable2の両方が同じトランザクション内にあると想定されます。@@ identityは、「SaveChanges」が呼び出されない限り生成されません。この状況にどのように対処できますか?
アラッシュ2014年

7
@Djeroen:データベースで生成されたIDを使用する場合、最初にそれらのオブジェクトをデータベースに挿入する必要があります。挿入前にIDが必要な場合は、データを挿入する前に独自のロジックを構築して一意のIDを取得し、データベースでID列を使用しないでください。
Ladislav Mrnka、2015

124

私はエンティティフレームワークを使用するときに、Idsを正常に取得するためにLadislav Mrnkaの回答を使用していました。人々は私が抱えていた問題を「解決」しようとしています。

Customerとの外部キー関係を持つOrderオブジェクトを考えてみます。新しい顧客と新しい注文を同時に追加したとき、私はこのようなことをしていました。

var customer = new Customer(); //no Id yet;
var order = new Order(); //requires Customer.Id to link it to customer;
context.Customers.Add(customer);
context.SaveChanges();//this generates the Id for customer
order.CustomerId = customer.Id;//finally I can set the Id

ただし、私の場合、customer.Idとorder.CustomerIdの間に外部キー関係があったため、これは必要ありませんでした。

私がしなければならなかったすべてはこれでした。

var customer = new Customer(); //no Id yet;
var order = new Order{Customer = customer}; 
context.SaveChanges();//adds customer.Id to customer and the correct CustomerId to order

変更を保存すると、顧客用に生成されたIDも注文に追加されます。追加の手順は必要ありません

これは元の質問に答えないことは承知していますが、EFに慣れていない開発者が、必要のないものに対して上位投票の回答を使いすぎないようにするのに役立つと考えました。

これは、更新が単一のトランザクションで完了することを意味し、orphinデータを回避する可能性があります(すべての更新が完了するか、まったく行われないかのいずれか)。


8
よろしくお願いします!重要なベストプラクティスのヒント:var order = new Order {Customer = customer}; これは、関連するオブジェクトを割り当てるEntity Frameworkの能力を示しており、IDは自動的に更新されます。
LA Guy 88

回答に対するこの追加情報をありがとう。EFを使用する場合、DBラウンドトリップの節約に非常に役立ちました。
Prasad Korhale、

本当にありがとうございました。これはまさに私が探していたものです。私は「SaveChanges」を2回呼び出すよりも良い方法があると信じていました
Josh

1
回答の中で(できれば太字で)トランザクションの動作が解決されることも明記してください。オブジェクトの1つが追加に失敗した場合、トランザクションの一部は成功しません。たとえば、人と生徒を追加します。人は成功し、学生は失敗します。今、人は冗長です。この素晴らしい解決策をありがとう!
Imran Faruqi

32

変更を保存した後、エンティティをリロードする必要があります。EFで追跡できないデータベーストリガーによって変更されたためです。したがって、DBからエンティティを再度リロードする必要があります。

db.Entry(MyNewObject).GetDatabaseValues();

その後

int id = myNewObject.Id;

以下の質問で@jayanthaの回答を見てください:

defaultValueを使用しているときに、エンティティフレームワークに挿入されたエンティティのIDを取得するにはどうすればよいですか?

以下の質問で@christianの回答を探すことも役立ちます:

エンティティフレームワークの更新コンテキスト?


2
こんにちは、このようにすると、次のようなコンパイルエラーが発生します。たとえば、IdやNameなどのプロパティを解決できません。手伝ってくれませんか?
Morteza Azizi 2014年

1
@MortezaAzizi処理されていないか、nullプロパティの問題のエラーのようですが、説明を追加したり、コードの一部を記述したりできますか?
QMaster、2014年

3
.GetDatabaseValues();モデルをDBに保存しただけの場合は、何もする必要はありません。IDはモデルに自動的に再入力されます。
vapcguy 2018

3
@QMaster EFが同じSQLステートメントを実行することもできることを除いて、オブジェクトのIDを入力します。それ以外の場合、複数の依存オブジェクトを同時に保存するにはどうすればよいですか?GetDatabaseValues()データベースで検索するオブジェクトのIDがわからない場合はどうすればよいでしょうか。
krillgar '26

2
@vapcguyなるほど。ご清聴ありがとうございました。EF ASAPの両方のバージョンでそれを確認します。
QMaster、2018

16

こちらのリンクをご参照ください。

http://www.ladislavmrnka.com/2011/03/the-bug-in-storegeneratedpattern-fixed-in-vs-2010-sp1/

StoreGeneratedPatternのプロパティをidentityに設定してから、独自のコードを試す必要があります。

または、これも使用できます。

using (var context = new MyContext())
{
  context.MyEntities.AddObject(myNewObject);
  context.SaveChanges();

  int id = myNewObject.Id; // Your Identity column ID
}

7
上位投票の回答と同じです。
Lewis86

2
StoreGeneratedPattern私にとって欠けていた部分でした。
BurnsBA

1
これが、ORACLEとON-Insert Triggerを使用する場合の方法です
Karl

リンクが壊れている-ドメインパーキング
t.durden

こんにちはOracleで、エンティティにStoreGeneratedPatternを設定する必要がありました。モデルビューアに移動し、テーブルとPKを見つけ、StoreGeneratedPatternプロパティを選択してIdentityに設定しました。上記の答えが示すように動作します。これは、挿入時にシーケンスからPKを生成するトリガーがある場合です。
ロブ

15

保存するオブジェクトは、Id変更をデータベースに反映した後に正しいものになるはずです。


27
内側の例外を見ましたか?;-)
Snowbear


4

データベースにデータを挿入する必要があり、同時にエンティティフレームワークを使用してプライマリIDが必要な状況に遭遇しました。解決 :

long id;
IGenericQueryRepository<myentityclass, Entityname> InfoBase = null;
try
 {
    InfoBase = new GenericQueryRepository<myentityclass, Entityname>();
    InfoBase.Add(generalinfo);
    InfoBase.Context.SaveChanges();
    id = entityclassobj.ID;
    return id;
 }

4

すべての答えはそれぞれのシナリオに非常に適しています。私が違ったのは、Add()がこのようなint変数に返したオブジェクト(TEntity)から直接int PKを割り当てたことです。

using (Entities entities = new Entities())
{
      int employeeId = entities.Employee.Add(new Employee
                        {
                            EmployeeName = employeeComplexModel.EmployeeName,
                            EmployeeCreatedDate = DateTime.Now,
                            EmployeeUpdatedDate = DateTime.Now,
                            EmployeeStatus = true
                        }).EmployeeId;

      //...use id for other work
}

新しいオブジェクト全体を作成するのではなく、必要なものだけを取得します。

@GertArnold氏の編集:

ここに画像の説明を入力してください


3
IDを割り当てるために非公開のメソッドを追加することは、実際には役に立ちません。これはEntity Frameworkにも関係していません。
Gert Arnold

1
@GertArnold .. OPと同じ質問があり、答えを見つけて1行のステートメントにしましたが、非開示メソッドの説明という用語について聞いたことはありませんか?
IteratioN7T 2018

3
それはあなたがすることすべてを見せない(開示する)ことを意味します。多分それは単に明確に説明されていないかもしれません、私は知りません。私が知っていることは、Add(これがそうである場合DbSet.Add)魔法のように値をに割り当てないことEmployeeIdです。
Gert Arnold

3
なしではないSaveChanges。無理だよ。EmployeeIdたとえばEmployeeのコンストラクターなど、を割り当てる他のプロセスがない限り。または、を使用してEFコアを使用していForSqlServerUseSequenceHiLoます。とにかく、全体像を示しているわけではありません。
ガートアーノルド

3
最後に、これは標準のEFの動作ではありません。環境の詳細を説明する必要があります。EFバージョン、データベースのブランドとバージョン、従業員クラス、そのマッピングの詳細。
ガートアーノルド

3
Repository.addorupdate(entity, entity.id);
Repository.savechanges();
Var id = entity.id;

これは機能します。


4
リポジトリは、変更をデータベースに保存する責任を負いません。それはUnitOfWorkの仕事です。
tchelidze 2017

5
さらに、それが何であるかRepositoryは完全に不明確です。そして、「これでうまくいく」というのは説明です!。
Gert Arnold

2

2つの戦略があります。

  1. データベース生成IDintまたはGUID)を使用する

    短所:

    保存したエンティティのSaveChanges()を取得するIDために実行する必要があります。

    長所:

    intIDを使用できます。

  2. 生成されたクライアントを使用ID-GUIDのみ。

    長所:SaveChanges運用の縮小。1回の操作で新しいオブジェクトの大きなグラフを挿入できます。

    短所:

    のみ許可 GUID


1

最初にEF 6.xコードを使用する場合

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

データベーステーブルを初期化すると、

(newsequentialid())

ヘッダーの[Default Value]または[Binding]の下のテーブルプロパティ内で、挿入時にIDを入力できます。

問題は、テーブルを作成して、

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

後で、将来の更新データベースは(newsequentialid())を追加しません

適切な方法を修正するには、移行をワイプしてデータベースを削除してから再移行します...または、(newsequentialid())をテーブルデザイナーに追加するだけです。


newsequentialid()がどこに行くのか詳しく説明できますか?私はすでにEFコードを使用せずに手動で作成されたデータベースモデルを持っています。これは、自分の主キーではないため、IDを満たしません。そのための解決策を見つけたいと思います。
ジョシュ

1
@josh最初のコードがGuidタイプであると想定して、Sql Server Management Studioでテーブルを右クリックし、Id列をクリックすると、(一般)内の[列のプロパティ]タブの下に、デフォルト値またはバインディングが表示されます。手動でDBテーブルを作成する場合は、NewSequentialIdまたはNewIdを参照してください。一般的な使用例は次のようなものですwhen -column- is NULL, then NEWID()
Jeff Li
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.