首页 > 解决方案 > 如何在 DbContext 中将 Created By 设置为 enitites

问题描述

除了 Stack Overflow 问题How to set created date and Modified Date to enitites in DB first approach由用户LP13询问并由用户Ogglas回答。

我正在编写一个测试项目来学习新的开发方法并且碰壁了。我正在尝试实现 Ogglas 提供的答案,但是我不确定如何在 AutoFac 中注册“Wrapper”?

Ogglas 和我的代码示例

public interface IEntity
{
    DateTime CreatedDate { get; set; }

    string CreatedBy { get; set; }

    DateTime UpdatedDate { get; set; }

    string UpdatedBy { get; set; }
}

public interface IAuditableEntity
{
    DateTime CreatedDate { get; set; }
    string CreatedBy { get; set; }
    DateTime UpdatedDate { get; set; }
    string UpdatedBy { get; set; }
}

public interface ICurrentUser
{
    string GetUsername();
}

public interface ICurrentUser
{
    string Name();
    string GetUserId();
    bool IsUserAuthenticated();
    bool IsUserAdmin();
    bool IsUserManager();
}

public class ApplicationDbContextUserWrapper
{
    public ApplicationDbContext Context;

    public ApplicationDbContextUserWrapper(ApplicationDbContext context, ICurrentUser currentUser)
    {
        context.CurrentUser = currentUser;
        this.Context = context;
    }
}

public class MyDbContextWrapper
{
    public IMyDbContext Context;

    public MyDbContextWrapper(IMyDbContext context, ICurrentUser currentUser)
    {
        context.CurrentUser = currentUser;
        Context = context;
    }
}

public class ApplicationDbContext : DbContext
{

    public ICurrentUser CurrentUser;

    public override int SaveChanges()
    {
        var now = DateTime.Now;

        foreach (var changedEntity in ChangeTracker.Entries())
        {
            if (changedEntity.Entity is IEntity entity)
            {
                switch (changedEntity.State)
                {
                    case EntityState.Added:
                        entity.CreatedDate = now;
                        entity.UpdatedDate = now;
                        entity.CreatedBy = CurrentUser.GetUsername();
                        entity.UpdatedBy = CurrentUser.GetUsername();
                        break;
                    case EntityState.Modified:
                        Entry(entity).Property(x => x.CreatedBy).IsModified = false;
                        Entry(entity).Property(x => x.CreatedDate).IsModified = false;
                        entity.UpdatedDate = now;
                        entity.UpdatedBy = CurrentUser.GetUsername();
                        break;
                }
            }
        }

        return base.SaveChanges();
    }
}

public class MyDbContext : DbContext, IMyDbContext
{
    public ICurrentUser CurrentUser { get; set; }

    public DbSet<Staff> Staff { get; set; }
    public DbSet<AddressStaff> StaffAddresses { get; set; }

    public MyDbContext() : base("Name=MyWebPortalConnection")
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, MyWebPortalContextMigrationConfiguration>());
    }

    public override int SaveChanges()
    {
        var modifiedEntries = ChangeTracker.Entries().Where(x => x.Entity is IAuditableEntity
                && (x.State == EntityState.Added
                || x.State == EntityState.Modified));

        foreach (var entry in modifiedEntries)
        {
            if (entry.Entity is IAuditableEntity entity)
            {
                var dateTimeZone = DateTimeZoneProviders.Tzdb["Europe/London"];
                var zonedClock = SystemClock.Instance.InZone(dateTimeZone);
                var localDateTime = zonedClock.GetCurrentLocalDateTime();
                var dateTime = new DateTime(localDateTime.Year,
                                            localDateTime.Month,
                                            localDateTime.Day,
                                            localDateTime.Hour,
                                            localDateTime.Minute,
                                            localDateTime.Second);

                if (entry.State == EntityState.Added)
                {
                    entity.CreatedBy = CurrentUser.Name();
                    entity.CreatedDate = dateTime;
                }
                else if (entry.State == EntityState.Modified)
                {
                    entity.UpdatedBy = CurrentUser.Name();
                    entity.UpdatedDate = dateTime;
                }
                else
                {
                    Entry(entity).Property(x => x.CreatedBy).IsModified = false;
                    Entry(entity).Property(x => x.CreatedDate).IsModified = false;
                }
            }
        }

        return base.SaveChanges();
    }

我的 AutoFac EF 模块已更新

public class EFModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        //builder.RegisterType<MyDbContextWrapper>().As<IMtDbContext>();
        //builder.RegisterDecorator<MyDbContextWrapper, IMyDbContext>();
        //builder.RegisterDecorator<MyDbContextWrapper, IMyDbContext>();
        builder.RegisterType<MyDbContextWrapper>().AsSelf().InstancePerLifetimeScope();
        builder.RegisterType(typeof(MyDbContext)).As(typeof(IMyDbContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
        builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork)).InstancePerRequest();
        builder.Register(_ => new HttpClient()).As<HttpClient>().InstancePerLifetimeScope();
    }
}

我已使用以下教程作为设置我的项目 教程指南项目的指南, 我将非常感谢提供的任何帮助。谢谢你。

通用存储库已更新

public abstract class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity
{
    protected MyDbContextWrapper DbContextWrapper;
    protected DbContext GenericDbContext;
    protected readonly IDbSet<T> GenericDbset;

    protected GenericRepository(MyDbContextWrapper dbContextWrapper)
    {
        DbContextWrapper = dbContextWrapper;
        GenericDbContext = (DbContext)DbContextWrapper.Context;
        GenericDbset = GenericDbContext.Set<T>();
    }

IMyDbContext 已更新

public interface IMyDbContext
{
    ICurrentUser CurrentUser { get; set; }
    DbSet<Staff> Staff { get; set; }
    DbSet<AddressStaff> StaffAddresses { get; set; }

    int SaveChanges();
}

我的 CurrentUser AutoFac 模块

 public class CurrentUserModule : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterAssemblyTypes(Assembly.Load("MyWebPortal.Model"))
               .Where(t => t.Name.EndsWith("User"))
               .AsImplementedInterfaces()
               .InstancePerLifetimeScope();
    }
}

标签: c#dependency-injectionautofacwrapper

解决方案


这是一个最小的工作解决方案。

接口:

public interface IMyDbContext
{
    DbSet<Staff> Staff { get; }
    DbChangeTracker ChangeTracker { get; }
    int SaveChanges();
}

public interface IAuditableEntity
{
    string CreatedBy { get; set; }
}

public interface ICurrentUser
{
    string Name();
}

实体:

public class Staff : IAuditableEntity
{
    [Key]
    public int Id { get; set; }
    public string CreatedBy { get; set; }
}

模拟:

public class MockCurrentUser : ICurrentUser
{
    public string Name() => "Mock";
}

public class MockDbContext : DbContext, IMyDbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<MockDbContext>(null);
        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Staff> Staff { get; set; }

    public override int SaveChanges() => 1;
}

装饰师:

public class ApplicationDbContextAuditDecorator : IMyDbContext
{
    private readonly IMyDbContext context;
    private readonly ICurrentUser currentUser;

    public ApplicationDbContextAuditDecorator(IMyDbContext context, ICurrentUser currentUser)
    {
        this.context = context;
        this.currentUser = currentUser;
    }
    public DbSet<Staff> Staff { get => this.context.Staff; }

    public DbChangeTracker ChangeTracker => this.context.ChangeTracker;

    public int SaveChanges()
    {
        foreach (var changedEntity in ChangeTracker.Entries())
        {
            if (changedEntity.Entity is IAuditableEntity entity)
            {
                switch (changedEntity.State)
                {
                    case EntityState.Added:
                        entity.CreatedBy = this.currentUser.Name();
                        break;
                }
            }
        }

        return this.context.SaveChanges();
    }
}

并测试:

[TestMethod]
public void TestMethod1()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<MockDbContext>().As<IMyDbContext>().InstancePerLifetimeScope();
    builder.RegisterDecorator<ApplicationDbContextAuditDecorator, IMyDbContext>();
    builder.RegisterType<MockCurrentUser>().As<ICurrentUser>();

    var container = builder.Build();
    var context = container.Resolve<IMyDbContext>();
    context.Staff.Add(new Staff());
    context.SaveChanges();

    Assert.AreEqual("Mock", context.Staff.Local.Single().CreatedBy);
}

推荐阅读