C# 保存历史记录表与具有依赖项注入的实体框架的接口



我们正在将Net Core 2与Entity Framework一起使用。我们的SQL数据库由许多表格,地址,帐户,客户,销售等组成。

某些表具有相应的历史记录表:地址历史记录、客户历史记录、

每当有人更改原始表中的某些内容时,都应更新相应的历史记录表。(不能使用 SQL 时态表,因为我们有自定义历史逻辑(

我们正在尝试应用接口,我有点卡在代码上,有人可以提供如何使用接口实现这一点的快速代码示例吗?特别是在保存历史部分,如何应用依赖注入?根据需要随意重写代码

public partial class TestDbContext
{
public void AddEntityHistory<IEntityHistory>(IEntityHistory entity) where IEntityHistory: Address
{  
// do something 1 etc
}
public void AddEntityHistory<IEntityHistory>(IEntityHistory entity) where IEntityHistory: Customer
{  
// do something 2 etc
}
public override int SaveChanges()
{
SaveEntityHistory();
return base.SaveChanges();
}
protected void SaveEntityHistory()
{
var modifiedEntities = ChangeTracker.Entries<IEntityHistory>().Where(e => e.State == EntityState.Added || e.State == EntityState.Modified);
foreach(var entity in modifiedEntities)
{ 
AddEntityHistory(entity);  // what is the code base here? giving error below, it should call appropriate AddEntityHistory Method for corresponding Entity
}
}
}

上面的错误:

错误 CS0311 类型"接口.IEntityHistory"不能用作泛型类型或方法"属性上下文.添加实体历史记录(IEntityHistory("中的类型参数"IEntityHistory"。没有从"Interfaces.IEntityHistory"到"Data.Entities.Address"的隐式引用转换。

资源:

尝试使用类似的代码库:用于CreateDate,UserId等

https://dotnetcore.gaprogman.com/2017/01/26/entity-framework-core-shadow-properties/

方法的通用形式在这里根本不起作用。反射更适合您的要求:

public partial class TestDbContext
{
public void AddEntityHistory(Address entity)
{
// do something 1 etc
}
public void AddEntityHistory(Customer entity)
{
// do something 2 etc
}
public override int SaveChanges()
{
SaveEntityHistory();
return base.SaveChanges();
}
protected void SaveEntityHistory()
{
var modifiedEntities = ChangeTracker.Entries<IEntityHistory>()
.Where(e => e.State == EntityState.Added || e.State == EntityState.Modified);
foreach (var entity in modifiedEntities)
{
var methodInfo = this.GetType().GetMethod(nameof(AddEntityHistory), new[] { entity.Entity.GetType() });
methodInfo.Invoke(this, new[] { entity.Entity });
}
}
}

您可以使用通用存储库,然后对于每个实体的存储库,您可以保存其各自的历史记录表。下面是示例代码。

IGenericRepository

public interface IGenericRepository
{
Task GetByIdAsync(object id, CancellationToken cancellationToken = default);
Task InsertAsync(TEntity entity, CancellationToken cancellationToken = default);
void Delete(object id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
void UpdateStateAlone(TEntity entityToUpdate);
}

泛型存储库

public class GenericRepository : IGenericRepository
where TEntity : class, new()
{
private readonly YourDbContext context;
internal DbSet dbSet;
public GenericRepository(YourDbContext context)
{
this.context = context;
dbSet = context.Set();
}
public virtual Task GetByIdAsync(object id, CancellationToken cancellationToken = default)
{
return dbSet.FindAsync(id);
}
public virtual Task InsertAsync(TEntity entity, CancellationToken cancellationToken = default)
{
return dbSet.AddAsync(entity, cancellationToken);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
public virtual void UpdateStateAlone(TEntity entityToUpdate)
{            
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}

现在,若要将上述通用存储库用于实体,请使用以下示例代码。

using System.Threading.Tasks;
public interface IAddressRepository: IGenericRepository
{
Task CommitAsync();
public virtual Task InsertAsync(TEntity entity, CancellationToken cancellationToken = default)
}
using System.Threading.Tasks;
public class AddressRepository: GenericRepository, IAddressRepository
{
private readonly YourDbContext _context;
public AddressRepository(YourDbContext context) : base(context)
{
_context = context;
}
public override Task InsertAsync(Address entity, CancellationToken cancellationToken = default)
{
base.InsertAsync(entity,cancellationToken );
//call your history insert here and then the below save. This will save both the record in the main Address table and then your Address's history table.
return _context.SaveChangesAsync();
}
public Task CommitAsync()
{
return _context.SaveChangesAsync();
}
}

有关详细实现,请参阅此使用实体框架核心实现创建、读取、更新和删除功能

最新更新