C# 保存更改时设置默认值

C# 保存更改时设置默认值,c#,entity-framework-core,ef-fluent-api,.net-core-2.2,C#,Entity Framework Core,Ef Fluent Api,.net Core 2.2,所有我的实体都扩展了具有以下(相关)属性的BaseEntity: namespace Sppd.TeamTuner.Core.Domain.Entities { public abstract class BaseEntity { /// <summary> /// Unique identifier identifying a single instance of an entity. /// </sum

所有我的实体都扩展了具有以下(相关)属性的
BaseEntity

namespace Sppd.TeamTuner.Core.Domain.Entities
{
    public abstract class BaseEntity
    {
        /// <summary>
        ///     Unique identifier identifying a single instance of an entity.
        /// </summary>
        public Guid Id { get; set; }

        /// <summary>
        ///     Specifies when the entity instance has been created.
        /// </summary>
        public DateTime CreatedOnUtc { get; set; }

        /// <summary>
        ///     Specifies by whom the entity instance has been created.
        /// </summary>
        public Guid CreatedById { get; set; }

        /// <summary>
        ///     Specifies when the entity instance has been last updated.
        /// </summary>
        public DateTime ModifiedOnUtc { get; set; }

        /// <summary>
        ///     Specifies by whom the entity instance has been last modified.
        /// </summary>
        public Guid ModifiedById { get; set; }

        protected BaseEntity()
        {
            Id = Guid.NewGuid();
        }
    }
}
这个
值生成器

internal class CurrentUserIdValueGenerator : ValueGenerator<Guid>
{
    public override bool GeneratesTemporaryValues => false;

    public override Guid Next(EntityEntry entry)
    {
        return GetCurrentUser(entry).Id;
    }

    private static ITeamTunerUser GetCurrentUser(EntityEntry entry)
    {
        var userProvider = entry.Context.GetService<ITeamTunerUserProvider>();
        if (userProvider.CurrentUser != null)
        {
            return userProvider.CurrentUser;
        }

        if (entry.Entity is ITeamTunerUser user)
        {
            // Special case for user creation: The user creates himself and thus doesn't exist yet. Use him as the current user.
            return user;
        }

        throw new BusinessException("CurrentUser not defined");
    }
}
检查
ChangeTracker
的内容时,所有实体都设置了
ModifiedById
: 旁注:
ToList()
是必需的,否则无法正确枚举

除了id包含我期望的值之外,
ModifiedById
属性不可为null,因此不应为null(它可能包含
default(Guid)

知道发生了什么吗

[编辑]要添加的代码:

播种机:

internal class CardTypeDbSeeder : IDbSeeder
{
    private readonly IRepository<CardType> _cardTypeRepository;

    public CardTypeDbSeeder(IRepository<CardType> cardTypeRepository)
    {
        _cardTypeRepository = cardTypeRepository;
    }

    public int Priority => SeederConstants.Priority.BASE_DATA;

    public void Seed()
    {
        _cardTypeRepository.Add(new CardType
                                {
                                    Id = Guid.Parse(TestingConstants.CardType.ASSASSIN_ID),
                                    Name = "Assassin"
                                });
    }
        [...]
}
内部类CardTypeDbSeeder:IDbSeeder
{
私有只读IRepository\u cardTypeRepository;
公共CardTypedBeeder(IRepository cardTypeRepository)
{
_cardTypeRepository=cardTypeRepository;
}
public int Priority=>SeederConstants.Priority.BASE_数据;
公开无效种子()
{
_cardTypeRepository.Add(新的CardType
{
Id=Guid.Parse(TestingConstants.CardType.刺客Id),
Name=“刺客”
});
}
[...]
}
存储库:

namespace Sppd.TeamTuner.Infrastructure.DataAccess.EF.Repositories
{
    internal class Repository<TEntity> : IRepository<TEntity>
        where TEntity : BaseEntity
    {
        protected DbSet<TEntity> Set => Context.Set<TEntity>();

        protected TeamTunerContext Context { get; }

        protected virtual Func<IQueryable<TEntity>, IQueryable<TEntity>> Includes { get; } = null;

        public Repository(TeamTunerContext context)
        {
            Context = context;
        }

        public async Task<TEntity> GetAsync(Guid entityId)
        {
            TEntity entity;
            try
            {
                entity = await GetQueryWithIncludes().SingleAsync(e => e.Id == entityId);
            }
            catch (InvalidOperationException)
            {
                throw new EntityNotFoundException(typeof(TEntity), entityId.ToString());
            }

            return entity;
        }

        public async Task<IEnumerable<TEntity>> GetAllAsync()
        {
            return await GetQueryWithIncludes().ToListAsync();
        }

        public void Delete(Guid entityId)
        {
            var entityToDelete = GetAsync(entityId);
            entityToDelete.Wait();
            Set.Remove(entityToDelete.Result);
        }

        public void Add(TEntity entity)
        {
            Set.Add(entity);
        }

        public void Update(TEntity entity)
        {
            Set.Update(entity);
        }

        protected IQueryable<TEntity> GetQueryWithIncludes()
        {
            return Includes == null
                ? Set
                : Includes(Set);
        }
    }
}
名称空间Sppd.TeamTuner.Infrastructure.DataAccess.EF.Repositories
{
内部类存储库:IRepository
其中tenty:BaseEntity
{
受保护的DbSet Set=>Context.Set();
受保护的TeamTunerContext上下文{get;}
受保护的虚拟函数包括{get;}=null;
公共存储库(TeamTunerContext上下文)
{
上下文=上下文;
}
公共异步任务GetAsync(Guid entityId)
{
触角实体;
尝试
{
entity=await GetQueryWithIncludes().SingleAsync(e=>e.Id==entityId);
}
捕获(无效操作异常)
{
抛出新的EntityNotFoundException(typeof(tenty),entityId.ToString());
}
返回实体;
}
公共异步任务GetAllAsync()
{
return wait wait getquerywhincludes().toListSync();
}
公共无效删除(Guid entityId)
{
var entityToDelete=GetAsync(entityId);
entityToDelete.Wait();
Set.Remove(entityToDelete.Result);
}
公共无效添加(TEntity实体)
{
设置、添加(实体);
}
公共无效更新(TEntity实体)
{
设置、更新(实体);
}
受保护的IQueryable GetQueryWithIncludes()
{
返回Includes==null
设置
:包括(套);
}
}
}
提交更改:

            if (isNewDatabase)
            {
                s_logger.LogDebug($"New database created. Seed data for SeedMode={databaseConfig.SeedMode}");

                foreach (var seeder in scope.ServiceProvider.GetServices<IDbSeeder>().OrderBy(seeder => seeder.Priority))
                {
                    seeder.Seed();
                    s_logger.LogDebug($"Seeded {seeder.GetType().Name}");
                }

                // The changes are usually being saved by a unit of work. Here, while starting the application, we will do it on the context itself.
                context.SaveChanges();
            }
if(isNewDatabase)
{
s_logger.LogDebug($“为SeedMode创建了新数据库。种子数据={databaseConfig.SeedMode}”);
foreach(scope.ServiceProvider.GetServices().OrderBy中的var seeder(seeder=>seeder.Priority))
{
播种机;
LogDebug($“seedd{seeder.GetType().Name}”);
}
//更改通常由一个工作单元保存。在这里,当启动应用程序时,我们将在上下文本身上进行保存。
SaveChanges();
}

正如评论中所讨论的,在GitHub问题中进行了大量的浏览,结果是不可能使用值生成器来实现这一点。我通过在
Datacontext.SaveChanges
的重写中实现一个
PrepareSaveChanges()
来解决这个问题,它调用以下代码:

    private void SetModifierMetadataProperties(EntityEntry<BaseEntity> entry, DateTime saveDate)
    {
        var entity = entry.Entity;
        var currentUserId = GetCurrentUser(entry).Id;

        if (entity.IsDeleted)
        {
            entity.DeletedById = currentUserId;
            entity.DeletedOnUtc = saveDate;
            return;
        }

        if (entry.State == EntityState.Added)
        {
            entity.CreatedById = currentUserId;
            entity.CreatedOnUtc = saveDate;
        }

        entity.ModifiedById = currentUserId;
        entity.ModifiedOnUtc = saveDate;
    }
private void SetModifierMetadataProperties(EntityEntry,DateTime saveDate)
{
var实体=条目。实体;
var currentUserId=GetCurrentUser(条目).Id;
if(实体已删除)
{
entity.DeletedById=currentUserId;
entity.DeletedOnUtc=保存日期;
返回;
}
if(entry.State==EntityState.Added)
{
entity.CreatedById=currentUserId;
entity.CreatedOnUtc=保存日期;
}
entity.ModifiedById=currentUserId;
entity.ModifiedOnUtc=保存日期;
}

对于完整的实现,请按照注释中讨论的

覆盖的执行路径以及GitHub问题中的大量浏览,结果表明,不可能使用值生成器来实现此功能。我通过在
Datacontext.SaveChanges
的重写中实现一个
PrepareSaveChanges()
来解决这个问题,它调用以下代码:

    private void SetModifierMetadataProperties(EntityEntry<BaseEntity> entry, DateTime saveDate)
    {
        var entity = entry.Entity;
        var currentUserId = GetCurrentUser(entry).Id;

        if (entity.IsDeleted)
        {
            entity.DeletedById = currentUserId;
            entity.DeletedOnUtc = saveDate;
            return;
        }

        if (entry.State == EntityState.Added)
        {
            entity.CreatedById = currentUserId;
            entity.CreatedOnUtc = saveDate;
        }

        entity.ModifiedById = currentUserId;
        entity.ModifiedOnUtc = saveDate;
    }
private void SetModifierMetadataProperties(EntityEntry,DateTime saveDate)
{
var实体=条目。实体;
var currentUserId=GetCurrentUser(条目).Id;
if(实体已删除)
{
entity.DeletedById=currentUserId;
entity.DeletedOnUtc=保存日期;
返回;
}
if(entry.State==EntityState.Added)
{
entity.CreatedById=currentUserId;
entity.CreatedOnUtc=保存日期;
}
entity.ModifiedById=currentUserId;
entity.ModifiedOnUtc=保存日期;
}

对于完整的实现,请按照覆盖的执行路径执行

您是否在Insert或Update?Insert中收到错误。当我在创建DBTry之后对数据进行种子设定时,会发生这种情况,手动设置ModifiedById的值,然后查看错误是否移动到下一个属性。如果不这样做,则可以正常工作。我使用了另一种方法,使用EntityMetadataProviders在PrepareSaveChanges中设置这些值,这不会导致任何问题。但这样做看起来更性感。由于这个错误对我来说没有意义,我想了解到底发生了什么,并希望它能以这种方式工作
    private void SetModifierMetadataProperties(EntityEntry<BaseEntity> entry, DateTime saveDate)
    {
        var entity = entry.Entity;
        var currentUserId = GetCurrentUser(entry).Id;

        if (entity.IsDeleted)
        {
            entity.DeletedById = currentUserId;
            entity.DeletedOnUtc = saveDate;
            return;
        }

        if (entry.State == EntityState.Added)
        {
            entity.CreatedById = currentUserId;
            entity.CreatedOnUtc = saveDate;
        }

        entity.ModifiedById = currentUserId;
        entity.ModifiedOnUtc = saveDate;
    }