Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Entity Framework ne fonctionne pas avec la table temporelle

Il existe deux solutions à ce problème :

  1. Dans la fenêtre de propriétés de la colonne dans le concepteur EDMX, modifiez le StoreGeneratedPattern sur la PERIOD colonnes (ValidFrom et ValidTo dans mon cas) pour être identity . L'identité est meilleure que calculée car calculée entraînera l'actualisation par EF des valeurs d'une insertion et d'une mise à jour, par opposition à une simple insertion avec identity
  2. Créer un IDbCommandTreeInterceptor mise en œuvre pour supprimer les colonnes de période. C'est ma solution préférée car elle ne nécessite aucun travail supplémentaire lors de l'ajout de nouvelles tables au modèle.

Voici mon implémentation :

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

Enregistrez cet intercepteur avec EF en exécutant ce qui suit n'importe où dans votre code avant d'utiliser votre contexte :

DbInterception.Add(new TemporalTableCommandTreeInterceptor());