it-swarm.com.de

Entity Framework - ID vor 'SaveChanges' in einer Transaktion abrufen

In Entity Framework - Gibt es eine Möglichkeit, eine neu erstellte ID (Identität) in einer Transaktion abzurufen, bevor 'SaveChanges' aufgerufen wird?

Ich brauche die ID für ein zweites Insert, es wird jedoch immer als 0 zurückgegeben ...

        ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;

        objectContext.Connection.Open();

        using (var transaction = objectContext.Connection.BeginTransaction())
        {
            foreach (tblTest entity in saveItems)
            {
                this.context.Entry(entity).State = System.Data.EntityState.Added;
                this.context.Set<tblTest>().Add(entity);

                int testId = entity.TestID;

                .... Add another item using testId
            }

            try
            {
                context.SaveChanges();
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();
                objectContext.Connection.Close();
                throw ex;
            }
        }

        objectContext.Connection.Close();
50
user1948635

Die ID wird von der Datenbank generiert, nachdem die Zeile in die Tabelle eingefügt wurde. Sie können die Datenbank nicht nach dem Wert fragen, bevor die Zeile eingefügt wird.

Sie haben zwei Möglichkeiten, um dies zu erreichen. Am einfachsten wäre es, SaveChanges aufzurufen. Da Sie sich in einer Transaktion befinden, können Sie einen Rollback durchführen, falls nach der ID ein Problem auftritt.

Der zweite Weg wäre, die eingebauten IDENTITY-Felder der Datenbank nicht zu verwenden, sondern sie selbst zu implementieren. Dies kann sehr nützlich sein, wenn Sie viele Bulk-Insert-Vorgänge haben, aber dies ist mit einem Preis verbunden, der nicht einfach zu implementieren ist.

BEARBEITEN: SQL Server 2012 verfügt über einen integrierten SEQUENCE-Typ, der anstelle einer IDENTITY-Spalte verwendet werden kann. Sie müssen sie nicht selbst implementieren.

43
zmbq

@zmbq ist richtig, Sie können die ID nur nach dem Aufruf von Save Changes erhalten.

Mein Vorschlag ist, dass Sie sich NICHT auf die generierten IDs der Datenbank verlassen sollten .. Die Datenbank sollte nur ein Detail Ihrer Anwendung sein, kein integraler und nicht veränderbarer Teil.

Wenn Sie dieses Problem nicht umgehen können, verwenden Sie GUID als Bezeichner, da es eindeutig ist . MSSQL unterstützt GUID als nativen Spaltentyp und ist schnell (wenn auch nicht schneller als INT.).

Prost

7
SeriousM

Wenn Ihre TblTest-Entität mit anderen Entitäten verbunden ist, die Sie anfügen möchten, benötigen Sie keine ID, um die Beziehung zu erstellen. Nehmen wir an, TblTest ist an ein anderesTest-Objekt angehängt, so wie in einem anderenTest-Objekt das TblTest-Objekt und die TblTestId-Eigenschaften vorhanden sind. In diesem Fall können Sie folgenden Code verwenden:

using (var transaction = objectContext.Connection.BeginTransaction())
    {
        foreach (tblTest entity in saveItems)
        {
            this.context.Entry(entity).State = System.Data.EntityState.Added;
            this.context.Set<tblTest>().Add(entity);

            anotherTest.tblTest = entity;
            ....
        }
    }

Nach dem Absenden der Beziehung würde die Beziehung erstellt und Sie müssen sich keine Gedanken über IDs usw. machen.

4
Armen

Eine einfache Umgehung dafür wäre

var ParentRecord = new ParentTable () {
SomeProperty = "Some Value",
AnotherProperty = "Another Property Value"
};

ParentRecord.ChildTable.Add(new ChildTable () {
ChildTableProperty = "Some Value",
ChildTableAnotherProperty = "Some Another Value"
});

db.ParentTable.Add(ParentRecord);

db.SaveChanges();

Dabei sind ParentTable und ChildTable zwei mit dem Foregin-Schlüssel verbundene Tabellen.

0
Hamza Khanzada

Wie bereits erwähnt, haben Sie vor dem Aufruf von saveChanges() keinen Zugriff auf den von der Datenbank generierten Inkrementwert. Wenn Sie jedoch nur an id interessiert sind, um eine Verbindung zu einer anderen Entität herzustellen (z. B. in derselben Transaktion) ) dann können Sie sich auch auf die von EF Core zugewiesenen temporären IDs verlassen :

Je nach verwendetem Datenbankanbieter können die Werte von EF oder in der Datenbank clientseitig generiert werden. Wenn der Wert von der Datenbank generiert wird, weist EF möglicherweise einen temporären Wert zu, wenn Sie die Entität dem Kontext hinzufügen. Dieser temporäre Wert wird dann während SaveChanges () durch den von der Datenbank generierten Wert ersetzt.

Hier ein Beispiel, um zu zeigen, wie das funktioniert. Angenommen, MyEntity wird von MyOtherEntity über die Eigenschaft MyEntityId referenziert, die vor dem Aufruf von saveChanges zugewiesen werden muss.

var x = new MyEntity();        // x.Id = 0
dbContext.Add(x);              // x.Id = -2147482624 <-- EF Core generated id
var y = new MyOtherEntity();   // y.Id = 0
dbContext.Add(y);              // y.Id = -2147482623 <-- EF Core generated id
y.MyEntityId = x.Id;           // y.MyEntityId = -2147482624
dbContext.SaveChangesAsync();
Debug.WriteLine(x.Id);         // 1261 <- EF Core replaced temp id with "real" id
Debug.WriteLine(y.MyEntityId); // 1261 <- reference also adjusted by EF Core

Das Obige funktioniert auch, wenn Referenzen über Navigationseigenschaften zugewiesen werden , d. H. y.MyEntity = x anstelle von y.MyEntityId = x.Id

0
B12Toaster