Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Entity Framework funktioniert nicht mit temporaler Tabelle

Es gibt zwei Lösungen für dieses Problem:

  1. Ändern Sie im Eigenschaftsfenster für die Spalte im EDMX-Designer das StoreGeneratedPattern am PERIOD Spalten (ValidFrom und ValidTo in meinem Fall) als identity . Identität ist besser als berechnet, da berechnet EF dazu veranlasst, die Werte bei einer Einfügung und Aktualisierung zu aktualisieren, im Gegensatz zu nur einer Einfügung mit identity
  2. Erstellen Sie einen IDbCommandTreeInterceptor Implementierung zum Entfernen der Periodenspalten. Dies ist meine bevorzugte Lösung, da beim Hinzufügen neuer Tabellen zum Modell keine zusätzliche Arbeit erforderlich ist.

Hier ist meine Implementierung:

using System.Data.Entity.Infrastructure.Interception; 
using System.Data.Entity.Core.Common.CommandTrees; 
using System.Data.Entity.Core.Metadata.Edm; 
using System.Collections.ObjectModel;

internal class TemporalTableCommandTreeInterceptor : IDbCommandTreeInterceptor
{
    private static readonly List<string> _namesToIgnore = new List<string> { "ValidFrom", "ValidTo" };

    public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
    {
        if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
        {
            var insertCommand = interceptionContext.Result as DbInsertCommandTree;
            if (insertCommand != null)
            {
                var newSetClauses = GenerateSetClauses(insertCommand.SetClauses);

                var newCommand = new DbInsertCommandTree(
                    insertCommand.MetadataWorkspace,
                    insertCommand.DataSpace,
                    insertCommand.Target,
                    newSetClauses,
                    insertCommand.Returning);

                interceptionContext.Result = newCommand;
            }

            var updateCommand = interceptionContext.Result as DbUpdateCommandTree;
            if (updateCommand != null)
            {
                var newSetClauses = GenerateSetClauses(updateCommand.SetClauses);

                var newCommand = new DbUpdateCommandTree(
                    updateCommand.MetadataWorkspace,
                    updateCommand.DataSpace,
                    updateCommand.Target,
                    updateCommand.Predicate,
                    newSetClauses,
                    updateCommand.Returning);

                interceptionContext.Result = newCommand;
            }
        }
    }

    private static ReadOnlyCollection<DbModificationClause> GenerateSetClauses(IList<DbModificationClause> modificationClauses)
    {
        var props = new List<DbModificationClause>(modificationClauses);
        props = props.Where(_ => !_namesToIgnore.Contains((((_ as DbSetClause)?.Property as DbPropertyExpression)?.Property as EdmProperty)?.Name)).ToList();

        var newSetClauses = new ReadOnlyCollection<DbModificationClause>(props);
        return newSetClauses;
    }
}

Registrieren Sie diesen Interceptor bei EF, indem Sie Folgendes an einer beliebigen Stelle in Ihrem Code ausführen, bevor Sie Ihren Kontext verwenden:

DbInterception.Add(new TemporalTableCommandTreeInterceptor());