it-swarm.com.de

Wie erhalte ich den nächsten Wert der SQL Server-Sequenz in Entity Framework?

Ich möchte SQL Server sequence objects in Entity Framework verwenden, um die Nummernfolge vor dem Speichern in der Datenbank anzuzeigen. 

Im aktuellen Szenario mache ich etwas, das in der gespeicherten Prozedur um eins erhöht wird (vorheriger Wert in einer Tabelle gespeichert) und diesen Wert an C # -Code übergeben. 

Um dies zu erreichen, brauchte ich eine Tabelle, aber jetzt möchte ich sie in ein sequence-Objekt konvertieren (gibt es einen Vorteil?). 

Ich weiß, wie man eine Sequenz erstellt und einen nächsten Wert in SQL Server erhält. 

Ich möchte jedoch wissen, wie der nächste Wert des sequence-Objekts von SQL Server in Entity Framework abgerufen wird. 

Ich finde keine nützlichen Antworten in Verwandte Fragen in SO. 

Danke im Voraus.

24
ManirajSS

Sie können eine einfache gespeicherte Prozedur in SQL Server erstellen, die den nächsten Sequenzwert wie folgt auswählt:

CREATE PROCEDURE dbo.GetNextSequenceValue 
AS 
BEGIN
    SELECT NEXT VALUE FOR dbo.TestSequence;
END

anschließend können Sie diese gespeicherte Prozedur in Ihr EDMX-Modell in Entity Framework importieren und diese gespeicherte Prozedur aufrufen und den Sequenzwert wie folgt abrufen:

// get your EF context
using (YourEfContext ctx = new YourEfContext())
{
    // call the stored procedure function import   
    var results = ctx.GetNextSequenceValue();

    // from the results, get the first/single value
    int? nextSequenceValue = results.Single();

    // display the value, or use it whichever way you need it
    Console.WriteLine("Next sequence value is: {0}", nextSequenceValue.Value);
}

Update: tatsächlich können Sie die gespeicherte Prozedur überspringen und diese unformatierte SQL-Abfrage einfach aus Ihrem EF-Kontext ausführen:

public partial class YourEfContext : DbContext 
{
    .... (other EF stuff) ......

    // get your EF context
    public int GetNextSequenceValue()
    {
        var rawQuery = Database.SqlQuery<int>("SELECT NEXT VALUE FOR dbo.TestSequence;");
        var task = rawQuery.SingleAsync();
        int nextVal = task.Result;

        return nextVal;
    }
}
37
marc_s

Da ich Code First verwende und keine zusätzliche DDL haben möchte, ist dies mein Weg: (EF Core 2.1, SQL Server)

Definieren Sie die Reihenfolge:

protected override void OnModelCreating( ModelBuilder modelBuilder )
{
    modelBuilder.HasSequence("MySequence");
}

Und um es abzurufen, füge ich dem Kontext die folgende Funktion hinzu:

public int GetMySequence()
{
   SqlParameter result = new SqlParameter("@result", System.Data.SqlDbType.Int)
   {
      Direction = System.Data.ParameterDirection.Output
   };

   Database.ExecuteSqlCommand(
              "SELECT @result = (NEXT VALUE FOR MySequence)", result);

   return (int)result.Value;
}
10
SeSpoon

Da diese Funktionalität nicht sofort verfügbar ist, habe ich eine Erweiterungsklasse für den DbContext geschrieben, der den Job ausführt. Schauen Sie sich diesen Code an:

public enum Sequence
{
    [Description("sequence__name__goes__here")]
    ClientNr,
    [Description("another__sequence__name")]
    OrderNr,
}
public static class MyDbContextExtensions
{
    public static int NextValueForSequence(this MyDbContext pCtx, Sequence pSequence)
    {
        SqlParameter result = new SqlParameter("@result", System.Data.SqlDbType.Int)
        {
            Direction = System.Data.ParameterDirection.Output
        };
        var sequenceIdentifier = pSequence.GetType()
                    .GetMember(pSequence.ToString())
                    .First()
                    .GetCustomAttribute<DescriptionAttribute>()
                    .Description;
        pCtx.Database.ExecuteSqlCommand($"SELECT @result = (NEXT VALUE FOR [{sequenceIdentifier}]);", result);
        return (int)result.Value;
    }
}

Obwohl ich zugeben muss, dass all das Zeug mit Überlegungen und Anmerkungen für manche wie ein Overkill wirken mag, mag ich es trotzdem irgendwie.

Es ermöglicht mir, den Wert auf eine ziemlich elegante Weise abzurufen

ctx.NextValueForSequence(Sequence.OrderNr);

Es wird auch eine "typensichere" Art verspottet, die mich dazu zwingt, die verschiedenen Sequenznamen explizit an einem zentralen Ort zu definieren, anstatt nur magische Zeichenfolgen von einem beliebigen Ort aus zu übergeben.

Wenn Sie dies nicht möchten, ändern Sie einfach die Methode, um den Sequenznamen als Zeichenfolge zu übergeben. Es würde genauso gut funktionieren.

1
Alan

Wenn Sie es außerhalb einer gespeicherten Prozedur ausführen möchten, können Sie eine Entitätsklasse erstellen, die nur eine Zeichenfolge oder ein int enthält (was auch immer Ihre Sequenz zurückgibt) und dann etwas Roh-SQL ausführen. Dann verwenden Sie einfach Ihr Objekt oder Ihren String, wie Sie möchten.

 SEQ_TXN_ID txn_id= _context.SEQ_TXN_IDs.SqlQuery("SELECT txn_id_seq.NEXTVAL txn_ID FROM DUAL").FirstOrDefault();
0
user2460920