C# EF Core-自动设置字段值

C# EF Core-自动设置字段值,c#,asp.net,entity-framework,refactoring,entity-framework-core,C#,Asp.net,Entity Framework,Refactoring,Entity Framework Core,我正在使用ASP.NET核心开发一个web应用程序+实体框架核心 我想存储更多关于创建、修改和删除的信息 My EF实体实现接口,该接口包含以下字段: DateTime CreationTime{get;set;} 长?CreatorUserId{get;set;} DateTime?修改时间{get;set;} 长?ModifierUserId{get;set;} DateTime?删除时间{get;set;} public long?DeleterUserId{get;set;} bool

我正在使用ASP.NET核心开发一个web应用程序+实体框架核心

我想存储更多关于创建、修改和删除的信息

My EF实体实现接口,该接口包含以下字段:

  • DateTime CreationTime{get;set;}
  • 长?CreatorUserId{get;set;}
  • DateTime?修改时间{get;set;}
  • 长?ModifierUserId{get;set;}
  • DateTime?删除时间{get;set;}
  • public long?DeleterUserId{get;set;}
  • bool被删除{get;set;}
  • int-TenantId{get;set;}
我一直在尝试让我的应用程序自动设置所有字段

现在我只能处理
DateTime
字段:
AppDbContext.cs

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
    ChangeTracker.DetectChanges();
    ChangeTracker.ProcessModifiedTime();
    ChangeTracker.ProcessSoftDelete();
    ChangeTracker.ProcessCreationTime();

    return (await base.SaveChangesAsync(true, cancellationToken));
}
public static class ChangeTrackerExtensions
{
    public static void ProcessCreationTime(this ChangeTracker changeTracker)
    {
        foreach (var item in changeTracker.Entries<ICreationTime>().Where(e => e.State == EntityState.Added))
        {
            item.CurrentValues[AppConsts.CreationTime] = DateTime.Now;
        }
    }

    public static void ProcessModifiedTime(this ChangeTracker changeTracker)
    {
        foreach (var item in changeTracker.Entries<IModificationTime>().Where(e => e.State == EntityState.Modified))
        {
            item.CurrentValues[AppConsts.ModificationTime] = DateTime.Now;
        }
    }

    public static void ProcessSoftDelete(this ChangeTracker changeTracker)
    {
        foreach (var item in changeTracker.Entries<ISoftDelete>().Where(e => e.State == EntityState.Deleted))
        {
            item.State = EntityState.Modified;
            item.CurrentValues[AppConsts.IsDeleted] = true;
            item.CurrentValues[AppConsts.DeletionTime] = DateTime.Now;
        }
    }
}

在服务层或控制器级别,可以每次分配所需的值(
CreatorUserId
mofiderUserId
DeleterUserId
),但这将成为一项例行任务,非常繁琐

我已经看到了,但让我担心的是,开发人员使他们的DbContext依赖于会话和其他东西

public abstract class AbpDbContext : DbContext, ITransientDependency, IShouldInitialize
{ 
    public IAbpSession AbpSession { get; set; }
    public IEntityChangeEventHelper EntityChangeEventHelper { get; set; }
    public ILogger Logger { get; set; }
    public IEventBus EventBus { get; set; }
    public IGuidGenerator GuidGenerator { get; set; }
    public ICurrentUnitOfWorkProvider CurrentUnitOfWorkProvider { get; set; }
    public IMultiTenancyConfig MultiTenancyConfig { get; set; }
    ...
依我看,这是一种典型的违反单一责任原则的行为

我试着研究,但它们似乎只在实体框架的普通(非核心)版本中可用-仍然没有设法弄清楚如何实现我上面提到的内容


实际上,我完全不知道如何使用实体框架核心来处理它。有人能想到任何服务层级别的解决方案吗?或者有更好的方法吗?

这里的UserId和TenantId只是存储库服务(这里是DbContext)需要的数据片段。如果服务需要数据,则应将其注入服务中


如果没有DI,您可能会在DbContext上生成UserID和TenantID构造函数参数。使用DI,您可能会向提供此数据的服务注入依赖项。

只需查看以下答案“两个注意事项”部分,第2条-SRP问题。对于我们是否真的可以将会话或任何其他内容注入
DbContext
,仍然非常确定。让您的DbContext开放访问会话状态或Http上下文显然是错误的。但是让DbContext依赖于少量固定参数是很好的。要使用正确的标识连接到正确的数据库并记录审核数据,可能需要UserId和TenantId。所有这些都在存储库的单一职责范围内。我介绍了会话类,它注册为Scoped/Per Request,它属于服务层,并在MVC筛选器中填充-我们从声明中获取UserID和TenantID,这样当我们在任何服务中进一步注入它时-我们有UserID和TenantID,并且SRP没有违反。但我仍然担心将这个会话实例注入DbContext可能在SRP方面是错误的(即使我们没有注入
HttpContext
)。你怎么认为?只要你不在ISession服务中添加其他成员,发布我的变通方法听起来不错。例如,您需要能够轻松地创建一个实现,您可以在单元测试或其他没有HTTP请求的环境中使用它,比如批处理。很抱歉,我想插一句我自己的问题,但我认为它也与OP相关。那么,您在这里描述的是实现存储库不可知域模型的一种方法吗?您是说这样做的方法是让您的存储库实现依赖于某种“ID提供者”(其实现将在同一体系结构层中)?如果是这样的话,你能写几句话说明在读取(和更新)数据时这是如何工作的吗?我猜您必须以某种方式将ID映射到域对象,并且整个DDD实体与值的概念变得很重要。