通用仓储模式的更新方法

4

我正在尝试使用单元工作和仓储模式,并且我有以下的“更新”方法,如果要替换表行中的所有元素(id、颜色、年份),则正常运作。

public virtual void Update(TEntity entityToUpdate)
{
    dbSet.Attach(entityToUpdate);
    (entityToUpdate).State = EntityState.Modified;
}

但我只想更新我所传递的特定列(id和color),而不是覆盖其他元素(year)。

例如,我在我的Cars表中有一个数据库记录:

Id = 1,
color = "red"
year = 2010

如果我这样更新它...

var location = new Car
{
    Id = 1,
    color = "blue"
};


unitOfWork.CarRepository.Update(car);

记录现在是:

Id = 1,
color = "blue"
year = null 

我该如何重写通用仓储方法以只更改输入的内容?(即保留年份值)
2个回答

5
您无法合理地使用通用存储库模式来完成此操作。您真的没有必要使用这种模式。EntityFramework已经是一个通用存储库,为什么需要将其包装在另一个通用存储库中?这种抽象类型会降低价值。
您确实希望将数据库使用从控制器中封装起来(MVC控制器中不应该有DbContext),但是您不需要任何特殊的模式来实现。只需将DbContext注入到执行工作的类中即可。
此外,如果传递UOW,则大部分时间都是反模式。这会在应用程序中创建一些非常疯狂的耦合问题,使得完全无关的代码能够影响非常不同的代码段。
删除通用存储库,并直接在服务/DAL/资源类(您想称之为什么)中使用EF,将允许您使用EF的全部功能。这将允许非常轻松地进行部分更新。
要使用通用存储库进行部分更新,您需要一些重型动态代码来处理映射。老实说,我理论上可以编写这个,但我知道不要写这个。您越是抽象映射,它就变得越脆弱,几乎不可能预测未来如何处理映射。这就是为什么有整个库(例如AutoMapper)用于处理映射的无限组合。AutoMapper也有点名不副实,虽然它可以执行基本自动映射,但AutoMapper的用例仍然是所有静态映射而不是动态映射。您需要创建动态映射,即水晶球映射。

当直接使用实体时,您将如何测试您的服务/DAL/资源?难道您不必模拟每个在服务/DAL/资源方法中使用的实体方法才能进行测试吗? - afarazit
@afarazit 我从不嘲笑数据库,那是没意义的。我嘲笑抽象层,也就是'DAL'。有时,这可能意味着我的模拟 DAL 使用字典来模拟[快速]集成测试的持久性。 - Chris Marisic
@ChrisMarisic - 你能指出一些文章来描述如何模拟DAL而不是数据库的实现吗?因为我也一直在模拟数据库来测试我的服务。 - Nanu
@Nanu 我不这么认为。嘲笑一个数据库是毫无意义的,这时你什么都没有测试。你不知道你的代码是否能够正常工作,如果它只是针对模拟数据库运行良好也没有任何意义。你只是浪费了大量的精力。 - Chris Marisic

0

你编写的更新方法假定你已经有一个已设置属性的现有实体对象。仓库假定你的业务逻辑是这样的:

var car = repo.GetCar(id);

car.prop1 = "new value";
car.prop2 = "another new value";

repo.update(car);

这将保留您先前设置的任何值。


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