Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Entity Framework non funziona con la tabella temporale

Ci sono due soluzioni a questo problema:

  1. Nella finestra delle proprietà per la colonna nel designer EDMX, cambia il StoreGeneratedPattern nel PERIOD colonne (ValidFrom e ValidTo nel mio caso) devono essere identity . L'identità è migliore di quella calcolata poiché calcolata farà in modo che EF aggiorni i valori su un Inserisci e Aggiorna invece di un semplice inserimento con identity
  2. Crea un IDbCommandTreeInterceptor implementazione per rimuovere le colonne del periodo. Questa è la mia soluzione preferita poiché non richiede lavoro aggiuntivo quando si aggiungono nuove tabelle al modello.

Ecco la mia implementazione:

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;
    }
}

Registra questo interceptor con EF eseguendo quanto segue in qualsiasi punto del codice prima di utilizzare il contesto:

DbInterception.Add(new TemporalTableCommandTreeInterceptor());