在 Entity Framework 核心中实施工作单元

Implementing unit of work in Entity Framework Core

我已经在 Entity Framework Core 中以下一种方式实现了工作单元。

上下文:

public class DaleContext : DbContext, IDaleContext
{
    private readonly IConnectionStringProvider _connectionStringProvider;

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(_connectionStringProvider.ConnectionString);
        base.OnConfiguring(optionsBuilder);
    }

    public DaleContext(IConnectionStringProvider connectionStringProvider)
    {
        _connectionStringProvider = connectionStringProvider;
    }
    
    public DbSet<ProductProducts { get; set; }

    public override int SaveChanges()
    {
        ChangeTracker.DetectChanges();

        var modifiedEntries = ChangeTracker.Entries()
            .Where(x =x.State == EntityState.Added || x.State == EntityState.Modified).ToList();

        return base.SaveChanges();
    }
}

工作单元:

public class UnitOfWork : IUnitOfWork
{
    public UnitOfWork(DbContext dbContext)
    {
        DbContext = dbContext;
    }

    public DbContext DbContext { get; set; }

    public int Commit()
    {
        return DbContext.SaveChanges();
    }

    public async Task<intCommitAsync()
    {
        return await DbContext.SaveChangesAsync();
    }
}

存储库:

public class Repository<TEntity: IDisposable, IRepository<TEntity>
where TEntity : class
{
    private readonly UnitOfWork _unitOfWork;

    public Repository(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork as UnitOfWork;
    }

    public void Dispose()
    {
        _unitOfWork.DbContext.Dispose();
    } 

    public void Create(TEntity entity)
    {
        _unitOfWork.DbContext.Entry(entity).State = EntityState.Added;
    }
}

我已经全部注入autofac:

public static class Container
{
    public static ContainerBuilder RegisterInfraestructure(this ContainerBuilder containerBuilder)
    {
        containerBuilder.RegisterType<UnitOfWork>().As<IUnitOfWork>();

        return containerBuilder;
    }
}

public static class Container
{
    public static ContainerBuilder RegisterDataResources(this ContainerBuilder containerBuilder)
    {
        var configurationBuilder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json");

        var configuration = configurationBuilder.Build();

        containerBuilder.Register(x =new ConnectionStringProvider(configuration.GetConnectionString("Fgcm.Dale"))
        ).As<IConnectionStringProvider>();

        containerBuilder.RegisterType<DaleContext>().As<DbContext>().As<IDaleContext>();

        return containerBuilder;
    }
} 

public static class Container
{
    public static ContainerBuilder RegisterRepository(this ContainerBuilder containerBuilder)
    {
        containerBuilder.RegisterType<CustomerRepository>().As<ICustomerRepository>();
        containerBuilder.RegisterType<ProductRepository>().As<IProductRepository>();
        containerBuilder.RegisterType<SaleDetailRepository>().As<ISaleDetailRepository>();
        containerBuilder.RegisterType<SaleRepository>().As<ISaleRepository>();
        
        containerBuilder.RegisterDataResources();
        containerBuilder.RegisterInfraestructure();

        return containerBuilder;
    }
}

public static class Container
{
    public static ContainerBuilder RegisterApplicationServiceResources(this ContainerBuilder
    containerBuilder)
    {
        containerBuilder.RegisterRepository();

        containerBuilder.RegisterType<DaleApplicationService>().As<IDaleApplicationService>();

        return containerBuilder;
    }
}

当我尝试保存数据时它不起作用(不插入数据)...我想知道为什么?这是我尝试保存时的情况:

    public Product Create(Product product)
    {
        try
        {
            _productRepository.Create(product);
            _unitOfWork.Commit();
            return product;
        }
        catch (Exception e)
        {
            Debug.WriteLine(e);
            return null;
        }
    }

当然所有都被注入了:

    private readonly ICustomerRepository _customerRepository;
    private readonly IProductRepository _productRepository;
    private readonly ISaleDetailRepository _saleDetailRepository;
    private readonly ISaleRepository _saleRepository;
    private readonly IUnitOfWork _unitOfWork;

    public DaleApplicationService(IProductRepository productRepository, ICustomerRepository customerRepository,
        ISaleRepository saleRepository, ISaleDetailRepository saleDetailRepository, IUnitOfWork unitOfWork)
    {
        _productRepository = productRepository;
        _customerRepository = customerRepository;
        _saleRepository = saleRepository;
        _saleDetailRepository = saleDetailRepository;
        _unitOfWork = unitOfWork;
    }

我错过了什么?

PS:所有这些都适用于 .NET Core Web Api。

正如@zolty13 暗示的那样 Instance scope of your DbContext (DaleContext) is probably incorrect. By default Autofac sets the instance scope to Instance per dependency(也称为“瞬态”生命周期),这意味着 DaleContext 的新实例会为每个 class 创建,这取决于它。因此,您的 UnitOfWork 收到的 DaleContext 实例与 IProductRepository 不同。因此 IProductRepository 中的更改不会反映在 UnitOfWork.

解决这个问题的一种方法是避免像@Igor 建议的那样对 DbContext 进行复杂的包装。你真的需要这个 UnitOfWork 吗?相反,使用具有 oneDaleContext 实例的存储库 class,并在其中进行所有数据库更改并保存它们。

或者(如果您真的认为您需要 UnitOfWork),您可以使用 instance per request 范围注册您的 DaleContext。请注意:Entity Framework 的 DbContext 不是 线程安全的,因此如果您需要进行并发工作,这不是一个安全的方法。

否则,请继续阅读 Instance scope