正如标题所说,我们需要存储更新或创建特定值的用户。以前我们只需要保存CreatedDate
和UpdatedDate
。这很容易,我们让所有实体都继承自一个抽象基类称为CCD_ 3,其实现具有这些值的接口CCD_。DbContext
SaveChanges
随后被覆盖,并且如果特定实体实现IEntity
,则基于EntityState.Added
或EntityState.Modified
来设置值。
interface IEntity
{
DateTime CreatedDate { get; set; }
string CreatedBy { get; set; }
DateTime UpdatedDate { get; set; }
string UpdatedBy { get; set; }
}
public abstract class EntityBase<T1>: IEntity
{
public T1 Id { get; set; }
public virtual DateTime CreatedDate { get; set; }
public virtual string CreatedBy { get; set; }
public virtual DateTime UpdatedDate { get; set; }
public virtual string UpdatedBy { get; set; }
}
然而,一个新的要求是,我们还需要保存哪个用户进行了更改。一个简单的解决方案是通过构造函数添加用户,而不是有一个空的构造函数。然而,在使用迁移等时,这证明了一个问题:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<CatalogServiceContext, Configuration>());
var migrator = new DbMigrator(new Configuration());
目标上下文"CatalogService.Data.context.CatalogServiceContext"是不可构造的。添加默认构造函数或提供IDbContentFactory的实现。
public class CatalogServiceContext : DbContext
{
private readonly string _currentUser;
public CatalogServiceContext(string currentUser) : base("name=CatalogContext")
{
_currentUser = 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.CreatedBy = _currentUser;
entity.UpdatedDate = now;
entity.UpdatedBy = _currentUser;
break;
case EntityState.Modified:
Entry(entity).Property(x => x.CreatedDate).IsModified = false;
Entry(entity).Property(x => x.CreatedBy).IsModified = false;
entity.UpdatedDate = now;
entity.UpdatedBy = _currentUser;
break;
}
}
}
return base.SaveChanges();
}
}
我尝试实现IDbContextFactory
,但它也有类似的问题。
上下文工厂类型"CatalogService.Data.Context.CatalogServiceContextFactory"不有一个公共的无参数构造函数。要么添加公共无参数构造函数,创建IDbContentFactory实现在上下文程序集中,或使用注册上下文工厂DbConfiguration。
public class CatalogServiceContextFactory : IDbContextFactory<CatalogServiceContext>
{
private readonly string _currentUser;
public CatalogServiceContextFactory(string currentUser)
{
_currentUser = currentUser;
}
public CatalogServiceContext Create()
{
return new CatalogServiceContext(_currentUser);
}
}
解决方法是EntityBase
中的两个方法,每次更新或创建值时都需要调用这两个方法。这是可行的,但在我看来,最好的解决方案仍然是构造函数中的强制用户。还有其他有类似需求的人解决了这个问题吗?我想在DbContext
中解决它,而不是对每个DbSet
使用存储库抽象。
public virtual EntityBase<T1> SetCreateFields(string currentUser)
{
CreatedBy = currentUser;
UpdatedBy = currentUser;
return this;
}
public virtual EntityBase<T1> SetUpdateFields(string currentUser)
{
UpdatedBy = currentUser;
return this;
}
决定这样解决:
public class CatalogServiceContext : DbContext
{
public ICurrentUser CurrentUser;
[Obsolete("Use CatalogServiceContextUserWrapper instead")]
public CatalogServiceContext() : base("name=CatalogContext")
{
}
...
public class CatalogServiceContextUserWrapper
{
public CatalogServiceContext Context;
public CatalogServiceContextUserWrapper(CatalogServiceContext context, ICurrentUser currentUser)
{
context.CurrentUser = currentUser;
this.Context = context;
}
}