使用Entity Framework和依赖注入保存C#历史记录表格接口

3

我们正在使用Net Core 2与Entity Framework。我们的Sql数据库由许多表组成,包括Address、Account、Customer、Sales等。

有些表有相应的历史表:AddressHistory、CustomerHistory等。

每当有人更改原始表中的内容时,应更新相应的历史表。(不能使用sql时间表,因为我们有自定义历史逻辑)

我们正在尝试应用接口,但在代码上卡住了,可以有人提供一个快速的代码示例来实现这个接口吗?特别是在SaveHistory部分,如何应用依赖注入?请随意重写代码。

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:类型“Interfaces.IEntityHistory”无法用作通用类型或方法“PropertyContext.AddEntityHistory(IEntityHistory)”中的类型参数“IEntityHistory”。从“Interfaces.IEntityHistory”到“Data.Entities.Address”没有隐式的引用转换。

资源:

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

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


你认为保留一个 AddEntityHistory,并在 SaveEntityHistory 中根据类型调用它是怎么样的? 在 AddEntityHistory 中,你将拥有所有类型(你需要的)的逻辑,或者将它们分开成私有方法。 - sharp
1
嗨@arcticwhite,我们将来会有100种不同类型。 - user12425844
@Artportraitdesign1 你的历史表的目的是什么?它们存储审计数据吗?我们应该将它们视为只追加日志吗?你考虑过第三方解决方案,比如:Audit.Net吗? - Peter Csala
2个回答

0

在这里,通用方法表单根本行不通。反射更适合您的要求:

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 });
        }
    }
}

0
你可以使用通用存储库,然后针对每个实体的存储库,可以保存其相应的历史记录表。以下是示例代码。
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();
        }
    }

如需详细实现,请参考使用Entity Framework Core实现创建、读取、更新和删除功能


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接