Wie kann ich die ID der eingefügten Entität im Entitätsframework abrufen? [geschlossen]

611

Ich habe ein Problem mit Entity Framework in Asp.net. Ich möchte den ID-Wert erhalten, wenn ich der Datenbank ein Objekt hinzufüge. Wie kann ich das machen?

ahmet
quelle
16
Die Antwort von Ladislav Mrnka unten ist die richtige Antwort und sollte als solche akzeptiert werden.
CShark
3
Das OP hat nur einmal mit seinem Konto gepostet, genauer gesagt mit dieser Frage. Dies gewährte ihm / ihr einen Ruf von fast 2k (!). Die Antwort wird nicht als akzeptiert markiert, da das Konto seit diesem Tag aufgegeben wurde.
MurariAlex
1
Wenn Sie die ID nur benötigen, um sie in einer Fremdschlüsselbeziehung zu verwenden, können Sie stattdessen nur die Navigationseigenschaft Ihrer abhängigen Entität auf die zuvor hinzugefügte Entität setzen. Auf diese Weise müssen Sie nicht SaveChangessofort anrufen , um die ID zu erhalten. Lesen Sie hier weiter .
B12Toaster
Fügen Sie für Entity Framework Core 3.0 den Parameter acceptAllChangesOnSuccess als true hinzu: wait _context.SaveChangesAsync (true);
Mike

Antworten:

1006

Es ist ziemlich einfach. Wenn Sie DB-generierte IDs verwenden (wie IDENTITYin MS SQL), müssen Sie nur Entitäten zu ObjectSetund SaveChangesauf verwandten hinzufügen ObjectContext. Idwird automatisch für Sie ausgefüllt:

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

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

Das Entity Framework folgt standardmäßig jeweils INSERTmit SELECT SCOPE_IDENTITY()automatisch generierten Ids.

Ladislav Mrnka
quelle
34
Sie stellen also eine falsche Frage. Wenn Sie ein Problem mit der Ausnahme haben, sollten Sie eine Frage stellen, die Ihre Ausnahme (und innere Ausnahme) und das Codefragment zeigt, das diesen Fehler verursacht.
Ladislav Mrnka
3
. Stellen Sie sicher , dass die Entity Sie hinzufügen, ein gültiger Entity zB ist, irgendetwas mit einer Datenbank Beschränkung „nicht null“ muss usw. gefüllt werden
fran
4
@LadislavMrnka: Was ist mit den Navigationseigenschaften des neu erstellten Objekts? Sie scheinen nach dem Speichern von Änderungen nicht automatisch ausgefüllt zu werden.
Isaac Kleinman
4
Betrachten wir das folgende Szenario: Tabelle1 soll eine @@ Identität generieren, um sie in Tabelle2 zu verwenden. Sowohl Tabelle1 als auch Tabelle2 sollen sich in derselben Transaktion befinden, z. B. muss eine SaveChange-Operation die Daten beider Tabellen speichern. @@ Identität wird erst generiert, wenn ein 'SaveChanges' aufgerufen wird. Wie können wir diese Situation angehen?
Arash
7
@Djeroen: Wenn Sie eine datenbankgenerierte ID verwenden, müssen Sie diese Objekte zuerst in die Datenbank einfügen. Wenn Sie vor dem Einfügen IDs benötigen, müssen Sie Ihre eigene Logik erstellen, um eindeutige IDs zu erhalten, bevor Daten eingefügt werden, und keine Identitätsspalte in der Datenbank verwenden.
Ladislav Mrnka
124

Ich habe die Antwort von Ladislav Mrnka verwendet, um bei Verwendung des Entity Frameworks erfolgreich IDs abzurufen. Ich poste jedoch hier, weil ich es nicht verwendet habe (dh dort verwendet habe, wo es nicht erforderlich war), und dachte, ich würde meine Ergebnisse hier veröffentlichen Fall Leute versuchen, das Problem, das ich hatte, zu "lösen".

Stellen Sie sich ein Bestellobjekt vor, das eine Fremdschlüsselbeziehung zum Kunden hat. Als ich gleichzeitig einen neuen Kunden und eine neue Bestellung hinzufügte, tat ich so etwas.

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

In meinem Fall war dies jedoch nicht erforderlich, da ich eine Fremdschlüsselbeziehung zwischen customer.Id und order.CustomerId hatte

Alles was ich tun musste war das;

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

Wenn ich jetzt die Änderungen speichere, wird die für den Kunden generierte ID ebenfalls zur Bestellung hinzugefügt. Ich brauche keine zusätzlichen Schritte

Ich bin mir bewusst, dass dies die ursprüngliche Frage nicht beantwortet, dachte aber, dass es Entwicklern, die EF noch nicht kennen, helfen könnte, die am häufigsten gewählte Antwort für etwas zu verwenden, das möglicherweise nicht erforderlich ist.

Dies bedeutet auch, dass Aktualisierungen in einer einzigen Transaktion abgeschlossen werden, wodurch möglicherweise Waisen-Daten vermieden werden (entweder alle Aktualisierungen sind abgeschlossen oder keine).

mark_h
quelle
8
Vielen Dank ! WICHTIGER Best-Practice-Tipp: var order = new Order {Kunde = Kunde}; Dies zeigt die Fähigkeit von Entity Framework, verwandte Objekte zuzuweisen, und die ID wird automatisch aktualisiert.
LA Guy 88
Vielen Dank für diese zusätzlichen Informationen zur Antwort. War sehr hilfreich beim Speichern eines DB-Roundtrips bei Verwendung von EF.
Prasad Korhale
Vielen Dank dafür. Genau das habe ich gesucht. Ich habe nur geglaubt, es könnte einen besseren Weg geben, als zweimal "SaveChanges" anzurufen
Josh
1
Bitte erwähnen Sie in Ihrer Antwort auch (vorzugsweise in Fettdruck), dass dies ein Transaktionsverhalten behebt. Wenn eines der Objekte nicht hinzugefügt werden kann, ist ein Teil der Transaktion nicht erfolgreich. ZB Person und Schüler hinzufügen. Person erfolgreich und Schüler scheitert. Jetzt ist die Person überflüssig. Vielen Dank für diese großartige Lösung!
Imran Faruqi
32

Sie müssen die Entität nach dem Speichern der Änderungen neu laden. Weil es durch einen Datenbank-Trigger geändert wurde, der von EF nicht verfolgt werden kann. Also müssen wir die Entität erneut aus der Datenbank laden.

db.Entry(MyNewObject).GetDatabaseValues();

Dann

int id = myNewObject.Id;

Schauen Sie sich die Antwort von @jayantha in der folgenden Frage an:

Wie kann ich bei Verwendung von defaultValue die ID der eingefügten Entität im Entity Framework ermitteln?

Die Antwort von @christian in der folgenden Frage kann ebenfalls hilfreich sein:

Entity Framework Kontext aktualisieren?

QMaster
quelle
2
Hallo, wenn mir das gefällt, erhalte ich den Kompilierungsfehler, der besagt: Kann die Eigenschaften zum Beispiel ID oder Name nicht auflösen, können Sie mir bitte helfen?
Morteza Azizi
1
@MortezaAzizi Es scheint sich um einen Fehler zu handeln, der nicht behandelt wurde, oder um ein Problem mit Null-Eigenschaften. Können Sie uns bitte mehr erklären oder einen Codeausschnitt schreiben?
QMaster
3
Sollte nicht nötig sein, .GetDatabaseValues();wenn Sie Ihr Modell gerade in der Datenbank gespeichert haben. Die ID sollte automatisch in das Modell übernommen werden.
Vapcguy
3
@QMaster Außer dass EF auch dieselbe SQL-Anweisung ausführen kann (und tut) und die ID Ihres Objekts auffüllt. Wie kann es sonst möglich sein, mehrere abhängige Objekte gleichzeitig zu speichern? Wie wäre es möglich, GetDatabaseValues()wenn es die ID des zu suchenden Objekts in der Datenbank nicht kennt?
Krillgar
2
@ Vapcguy Ich verstehe. Vielen Dank für Ihre Aufmerksamkeit. Ich werde das in beiden Versionen von EF ASAP überprüfen.
QMaster
16

Bitte beziehen Sie sich auf diesen Link.

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

Sie müssen die Eigenschaft von StoreGeneratedPattern auf Identität setzen und dann Ihren eigenen Code ausprobieren.

Oder Sie können dies auch verwenden.

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

  int id = myNewObject.Id; // Your Identity column ID
}
Azhar Mansuri
quelle
7
Gleich wie die am besten gewählte Antwort.
Lewis86
2
StoreGeneratedPatternwar das fehlende Stück für mich.
BurnsBA
1
Das ist der richtige Weg, wenn Sie mit ORACLE und ON-Insert Trigger arbeiten
Karl
Link ist defekt - geparkte Domain
t.durden
Hallo mit Oracle, ich musste das StoreGeneratedPattern in Entity festlegen - gehen Sie zum Modell-Viewer, suchen Sie Ihre Tabelle und PK, wählen Sie die StoreGeneratedPattern-Eigenschaft aus und setzen Sie auf Identity. Es funktioniert wie oben angegeben. Dies ist der Fall, wenn Sie einen Trigger haben, der Ihre PK aus einer Sequenz beim Einfügen auffüllt.
Rob
15

Das Objekt, das Sie speichern, sollte Idnach der Weitergabe von Änderungen in die Datenbank korrekt sein .

Schneebär
quelle
27
Hast du die innere Ausnahme gesehen? ;-)
Snowbear
6

Sie können die ID erst nach dem Speichern erhalten. Stattdessen können Sie eine neue Guid erstellen und vor dem Speichern zuweisen.

Vaduganathan Pillappan
quelle
4

Ich stoße auf eine Situation, in der ich die Daten in die Datenbank einfügen und gleichzeitig die primäre ID mithilfe des Entity Frameworks benötigen muss. Lösung:

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

Alle Antworten sind sehr gut für ihre eigenen Szenarien geeignet. Was ich anders gemacht habe, ist, dass ich die int PK direkt vom Objekt (TEntity) zugewiesen habe, das Add () an eine int-Variable wie diese zurückgegeben hat.

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
}

Anstatt ein ganz neues Objekt zu erstellen, nimmst du einfach, was du willst :)

BEARBEITEN Für Herrn @GertArnold:

Geben Sie hier die Bildbeschreibung ein

IteratioN7T
quelle
3
Es ist nicht wirklich nützlich, eine nicht offenbarte Methode zum Zuweisen einer ID hinzuzufügen. Dies hängt nicht einmal mit Entity Framework zusammen.
Gert Arnold
1
@GertArnold .. Ich hatte die gleiche Frage wie das OP. Ich fand die Antworten und machte daraus eine einzeilige Aussage. Ich habe noch nie von dem Begriff " Nicht offenbarte Methode" gehört .
IteratioN7T
3
Das bedeutet nur, dass Sie nicht alles zeigen, was Sie tun. Vielleicht ist es einfach nicht klar beschrieben, ich weiß es nicht. Was ich weiß ist, dass Add(wenn dies der DbSet.AddFall ist ) kein magischer Wert zugewiesen wird EmployeeId.
Gert Arnold
3
Nicht ohne SaveChanges. Unmöglich. Es sei denn, Sie haben einen anderen Prozess, der zugewiesen wird EmployeeId, z. B. im EmployeeKonstruktor. ODER Sie verwenden EF Core ForSqlServerUseSequenceHiLo. Wie auch immer, Sie geben nicht das ganze Bild.
Gert Arnold
3
Meine letzte Bemerkung wird sein: Dies ist kein Standard-EF-Verhalten. Sie sollten mehr Details Ihrer Umgebung angeben. EF-Version, Datenbankmarke und -version, Mitarbeiterklasse, Zuordnungsdetails.
Gert Arnold
3
Repository.addorupdate(entity, entity.id);
Repository.savechanges();
Var id = entity.id;

Das wird funktionieren.

Saket Choubey
quelle
4
Das Repository ist nicht für das Speichern von Änderungen in der Datenbank verantwortlich. Es ist eine Aufgabe von UnitOfWork.
Tchelidze
5
Darüber hinaus ist es absolut unklar, was Repositoryist. Und "das wird funktionieren" ist eine Erklärung!.
Gert Arnold
2

Es gibt zwei Strategien:

  1. Verwenden Sie die von der Datenbank generierte ID( intoder GUID)

    Nachteile:

    Sie sollten ausführen SaveChanges(), um die IDgerade gespeicherten Entitäten abzurufen.

    Vorteile:

    Kann intIdentität verwenden.

  2. Client generiert verwenden ID- nur GUID.

    Vorteile: Minimierung der SaveChangesOperationen. Kann pro Operation einen großen Graphen neuer Objekte einfügen.

    Nachteile:

    Nur erlaubt für GUID

Vladislav Furdak
quelle
1

Wenn Sie zuerst EF 6.x-Code verwenden

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

und initialisieren Sie eine Datenbanktabelle, es wird ein setzen

(newsequentialid())

innerhalb der Tabelleneigenschaften unter der Überschrift Standardwert oder Bindung, sodass die ID beim Einfügen ausgefüllt werden kann.

Das Problem ist, wenn Sie eine Tabelle erstellen und die hinzufügen

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

Teil später werden zukünftige Update-Datenbanken die (newsequentialid ()) nicht mehr hinzufügen.

Um den richtigen Weg zu finden, müssen Sie die Migration löschen, die Datenbank löschen und erneut migrieren ... oder Sie können einfach (newsequentialid ()) zum Tabellen-Designer hinzufügen.

Jeff Li
quelle
Können Sie näher erläutern, wohin newsequentialid () geht? Ich habe bereits von Hand erstellte Datenbankmodelle, die nicht zuerst EF-Code verwenden, und die ID wird nicht ausgefüllt, da dies nicht mein Primärschlüssel ist. Würde gerne eine Lösung dafür finden.
Josh
1
@josh Angenommen, der Code ist zuerst Guid-Typ, klicken Sie mit der rechten Maustaste auf Ihre Tabelle in SQL Server Management Studio, klicken Sie auf die Spalte ID, und auf der Registerkarte Spalteneigenschaften in (Allgemein) wird Standardwert oder Bindung angezeigt. Wenn Sie DB-Tabellen manuell erstellen , lesen Sie NewSequentialId oder NewId . Der allgemeine Anwendungsfall ist so etwas wiewhen -column- is NULL, then NEWID()
Jeff Li