.Net - 多个 ORM 的工作单元模式解耦

发布于 2024-10-31 10:28:43 字数 1038 浏览 1 评论 0原文

我当前的应用程序结构是:

  • 模型组装
  • 数据组装
    • 定义由 ORM 实现的存储库接口
  • 定义由 ORM ORM 程序集
    • 通过数据组装实现存储库接口
    • 使用 unity(IoC 容器)将 Data.IRepository 注册到 ORM.GenericRepository
  • 业务组件
    • 引用数据和模型程序集
    • 使用 unity 来解析 IRepository 的类型
  • UI 程序集 的类型
    • 引用业务程序集

此结构本质上将业务层与实现 IRepository 的 ORM 解耦。

这种解耦结构的好处之一是我应该能够相对轻松地替换 ORM - 例如,从实体框架迁移到 NHibernate 或只是升级现有的 ORM。我目前首先使用 EF 4.1 代码,并正在为 NHibernate 构建另一个程序集。

我正在考虑实施工作单元模式。

我读到该模式应该在业务层中使用(在我的数据程序集中定义接口,并在 ORM 程序集中实现,就像我对存储库模式所做的那样)。目前,所有实例化存储库都有自己的 DbContext / 会话,并且其生命周期设置为存储库的生命周期 - 这可能很糟糕 - 我的问题是我不确定是否可以实现可以使用的工作单元模式不同的 ORM(呃,更确切地说,它可能是,我只是不跟上速度)。

这是我唯一想到的事情:

在我的 Data 程序集中创建 IUnitOfWork,它具有以下功能: object GetCurrentSession(); ,然后在 ORM 程序集中的存储库的构造函数中添加一个参数并进行强制转换它到适当的会话/DbContext(如果是NHibernate则为ISession,如果为Entity Framework则为DbContext)

如果有人对这种情况有一些见解,我将不胜感激。

My current application structure is:

  • Models assembly
  • Data assembly
    • Defines repository interfaces to be implemented by an ORM
  • ORM assembly
    • Implements repository interfaces from Data assembly
    • Uses unity (IoC container) to regsister Data.IRepository<> to ORM.GenericRepository<>
  • Business assembly
    • References the Data and Models assemblies
    • Uses unity to resolve types of IRepository<>
  • UI assembly
    • References the Business assembly

This structure has essentially decoupled the Business layer from the ORM implementing the IRepository<T>.

One of the benefits of this decoupled structure is that I should be able to replace the ORM relatively easily - for example, move from Entity Framework to NHibernate or just upgrading an existing ORM. I'm currently using EF 4.1 code first and am building another assembly for NHibernate.

I'm considering implementing the Unit of Work pattern.

I've read that this pattern should be used in the business layer (with interfaces defined in my Data assembly, and implemented in the ORM assembly just like I did with the repository pattern). Currently, all instantiated repositories have their own DbContext / session and its lifetime is set to that of the repository - which may be bad- my problem is that I'm not sure if its possible to implement a Unit of Work pattern that would work with different ORM's (er rather, it probably is and I'm just not up to speed).

This is the only thing that comes to mind:

Create IUnitOfWork in my Data assembly that has a function: object GetCurrentSession(); , then have an argument in the constructor of the repositorys in the ORM assembly and cast it to the appropriate session / DbContext (If NHibernate then ISession, if Entity Framework then DbContext)

I would appreciate if anyone has some insight into this situation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

青衫负雪 2024-11-07 10:28:43

最近,我做了一个研究项目,其中使用工作单元和存储库模式实现了一个简单的 ASP.NET Core CRUD API。我这样做是为了让我的 API 控制器仅通过 IUnitOfWork 抽象与持久存储一起工作。我有 Dapper、Entity Framework Core 和 NHibernate 的单独项目,每个项目都为特定的 ORM 实现了 IUnitOfWork。

这是项目链接: https://github.com/pkirilin/UnitOfWorkExample

这是一个简单的示例:

class SomeService
{
    private readonly IAppUnitOfWork _unitOfWork;

    // IAppUnitOfWork is inherited from base IUnitOfWork and added to DI container
    public SomeService(IAppUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public async Task DoSomethingAsync(CancellationToken cancellationToken)
    {
        var entity = await _unitOfWork.WeatherForecasts.GetByIdAsync(..., cancellationToken);
        _unitOfWork.WeatherForecasts.Delete(entity);

        var newEntity = new WeatherForecast(...);
        _unitOfWork.WeatherForecasts.Add(newEntity);

        await _unitOfWork.SaveChangesAsync(cancellationToken);
    }
}

Recently I made my research project where I implemented a simple ASP.NET Core CRUD API using unit of work and repository patterns. I made it so that my API controller works with persistent storage only via IUnitOfWork abstraction. And I have separate projects for Dapper, Entity Framework Core and NHibernate, each of them implements IUnitOfWork for specific ORM.

Here's the project link: https://github.com/pkirilin/UnitOfWorkExample

Here's a simple example:

class SomeService
{
    private readonly IAppUnitOfWork _unitOfWork;

    // IAppUnitOfWork is inherited from base IUnitOfWork and added to DI container
    public SomeService(IAppUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public async Task DoSomethingAsync(CancellationToken cancellationToken)
    {
        var entity = await _unitOfWork.WeatherForecasts.GetByIdAsync(..., cancellationToken);
        _unitOfWork.WeatherForecasts.Delete(entity);

        var newEntity = new WeatherForecast(...);
        _unitOfWork.WeatherForecasts.Add(newEntity);

        await _unitOfWork.SaveChangesAsync(cancellationToken);
    }
}
东北女汉子 2024-11-07 10:28:43

我可能已经找到了解决方案(尚未尝试过):

在数据程序集中:

public interface IUnitOfWork : IDisposable
{
   void Start();
   T Current<T>();
   // IDisposable stuff
}

在 ORM 程序集中:

public class GenericRepository<T> : IRepository<T>
    where T : PersistentEntity
{
    private ISession CurrentSession;

    public GenericRepository(IUnitOfWork uow)
    {
         CurrentSession = uow.Current<ISession>();
    }

    // other repository stuff here
}

public class NHhibernateUnitOfWork : IUnitOfWork
{
   private ISession CurrentSession;

   public void Start()
   {
      // instantiate CurrentSession
   }

   T Current<T>()
   {
      if(typeof(T) is ISession)
         return (T)CurrentSession;
      else
         return new NotImplementedException();
   }
}

// in the prism module
container.Resolve(typeof(IUnitOfWork), typeof(NHhibernateUnitOfWork));

在业务程序集中:

IUnitOfWork uow = container.Resolve<IUnitOfWork>();
using(uow.Start())
{
    IRepository custRepo = container.Resolve<IRepository<Customer>>(uow);
    // do stuff here with cust repo
}

这只是将 IUnitOfWork 与具体实现解耦的概念证明。

I may have found a solution (have not tried it yet):

In the Data assembly:

public interface IUnitOfWork : IDisposable
{
   void Start();
   T Current<T>();
   // IDisposable stuff
}

In the ORM assembly:

public class GenericRepository<T> : IRepository<T>
    where T : PersistentEntity
{
    private ISession CurrentSession;

    public GenericRepository(IUnitOfWork uow)
    {
         CurrentSession = uow.Current<ISession>();
    }

    // other repository stuff here
}

public class NHhibernateUnitOfWork : IUnitOfWork
{
   private ISession CurrentSession;

   public void Start()
   {
      // instantiate CurrentSession
   }

   T Current<T>()
   {
      if(typeof(T) is ISession)
         return (T)CurrentSession;
      else
         return new NotImplementedException();
   }
}

// in the prism module
container.Resolve(typeof(IUnitOfWork), typeof(NHhibernateUnitOfWork));

In the Business assembly:

IUnitOfWork uow = container.Resolve<IUnitOfWork>();
using(uow.Start())
{
    IRepository custRepo = container.Resolve<IRepository<Customer>>(uow);
    // do stuff here with cust repo
}

This is just a proof of concept of decoupling IUnitOfWork from the concrete implementation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文