实体框架,导航属性,存储库,工作单元,可变ORM

本文关键字:工作 单元 可变 ORM 存储 框架 导航 属性 实体 | 更新日期: 2023-09-27 17:54:33

我正试图为我的应用程序创建一个新的核心框架(主要是web),其中包含存储库和工作单元模式,我可以在以后将我的ORM更改为NHibernate或Dapper。

现在我的工作单元界面是这样的:

 public interface IUnitOfWork : IDisposable
 {
        void Commit();
        void Rollback();
 }

实体框架的实现是这样的(为了可读性而修改)

 public class EfUnitOfWork : IUnitOfWork
 {
    ....
    public EfUnitOfWork(ApplicationDbContext context)
    {
        this._context = context;
        this._transaction = new EfTransaction(_context.Database.BeginTransaction());
    }
    public void Commit()
    {
        this._context.SaveChanges(true);
        this._transaction.Commit();
        ...
    }
    public void Rollback()
    { ...
    }
}
问题是,在包含业务逻辑的服务层中,我可以对导航属性做这样的事情:
public bool CreateCity(CityCreateModel model)
        {
            using (var uow = _unitOfWorkFactory.Create())
            {
                var city = new City();
                city.Name = model.Name;
                city.State = new State() { Country = new Country() { Name = "SomeCountry" }, Name = "SomeCity" };
                _cityRepository.Create(city);
                try
                {
                    uow.Commit();
                    return true;
                }
                catch (Exception)
                {
                    uow.Rollback();
                    throw;
                }
            }
        }

repository Create方法非常简单,因为它使用实体框架:

    public void Create(City entity)
    {
        _set.Add(entity);
    }

问题从这里开始,当团队成员编写类似Service示例的代码,在导航属性上使用new关键字或为集合导航属性添加项时,实体框架会检测到这些更改,当我保存更改时,这些更改也会保存到数据库中。

如果我尝试将现有样本更改为Dapper。净或REST服务以后可能会有很多问题,我必须去寻找每一个导航属性和跟踪,他们已经对其进行了更改,编写大量代码(可能是垃圾)为他们正如我不知道什么是插在桌子上通过实体框架和什么不是(因为导航属性也插入我的仓库一旦只有1插入呼吁城市在我的上面的例子)

是否有一种方法可以防止这种行为,或者是否有一种已知的模式,我可以尽早适应,这样我以后就不会有问题了?

你是怎么克服的?

实体框架,导航属性,存储库,工作单元,可变ORM

在我开始之前,我想给你的代码一些注释:

public EfUnitOfWork(ApplicationDbContext context)
{
    this._context = context;
    this._transaction = new EfTransaction(_context.Database.BeginTransaction());
}

1)从您的示例中,我可以看到您共享相同的DbContext(在整个应用程序的构造函数中作为参数给出)。我不认为这是一个好主意,因为实体将被缓存在第一层缓存中,并且更改跟踪器将跟踪它们。用这种方法会很快得到性能问题,当数据库会增长。

_cityRepository.Create(city);
public void Create(City entity)
{
    _set.Add(entity);
}

2)基本存储库应该是T类型的泛型,其中T是一个实体!所以你可以创建一个城市;

  var city = _cityRepository.Create();
  Fill the city or provide the data as parameters in the create method.

回到你的问题:

是否有一种方法可以防止这种行为,或者是否有一种已知的模式,我可以尽早适应,这样我以后就不会有问题了?

每个ORM都有自己的设计理念,要找到适合他们的通用方法并不容易,所以我会做以下事情:

1)将存储库契约分离为一个程序集(契约dll)

2)为每个ORM框架使用一个单独的程序集来实现存储库契约。

的例子:

public interface ICityRepository<City> :IGenericRepsotiory<City>
{
  City Create();
  Find();
   ....
}

  • 实体框架组装:

    公共类CityRepositoryEF: cityrepository{. .

  • Dapper framework assembly:

    公共类CityRepositoryDapper: cityrepository{. .

如果您遵循下面的URL,您可以找到一个精彩的介绍。它的作者Julie Lerman是一个实体框架的传道者。http://thedatafarm.com/data-access/agile-entity-framework-4-repository-part-1-model-and-poco-classes/