我不理解持久化独立的意义。

6

可能是重复问题:
持久性无知的好处是什么?

经过一段时间和一些问题,试图弄清楚实体框架,我得出的结论是,我不明白持久性无知对象的意义。

据我所知,使用持久性感知对象和持久性无知对象之间的实际区别在于,一个类似于以下内容:

Person p = Person.Load(id);
p.Active = false;
p.Save();

另一个是沿着这条线使用的

using (var context = new MyContext())
{
   Person p = context.Persons.Single(x => x.ID == id);
   p.Active = false;
   context.SaveChanges();
}

在第一种情况下,我可以返回p,并在稍后的某个时刻调用Save()。在后一种情况下,我可以返回p,但需要将其放入新的MyContext()中以保存它。在第一种情况下,假设Person从某个基对象继承Load()和Save(),该基对象实际上处理数据库逻辑,如果我想改变持久性,那么只需要更改该基对象(甚至只需有一个IPersistent接口,多个基类可以实现以访问多个存储)。在后一种情况下,如果持久层发生变化,我需要更改每个MyContext实例,并且分步骤进行将非常复杂。

我的印象是持久性无关是一件好事。我只是不明白为什么。它似乎要设置、使用、整体更改和分步更改更加复杂,而这种复杂性没有任何优势。我是错过了重要的东西,还是我的整个理解持久性感知/无感知的含义是错误的?


除了持久性无知实体之外,您还应该将ORM抽象出来。常见的方法是使用存储库模式 - jrummell
@DavidHall,我不认为这是重复的。至少,在阅读其他问题的答案之后,我仍然不明白为什么一个适当抽象化的持久性感知对象比一个持久性无知对象更好。 - Bobson
2个回答

5

持久化无关性是关注点分离的一部分。你应该问自己,为什么Person需要知道如何加载或保存?Person应该处理自己的小领域。

PI意味着Person不关心它是从内存、SQL、平面二进制还是任何其他持久化方式中获取的,并允许您在以后将持久化层替换为其他内容。您可能最初开发应用程序使用基本序列化器和平面二进制文件来存储数据。稍后,出于性能原因,您可能会升级到SQL--这种更改只需要在负责处理持久化的一个位置进行即可,而不必在整个代码库中更改处理持久化的各个部分。


看,我的经验恰好相反。从知道持久性的基本类型继承的Person对象很容易更改为新的持久层,但PI Person对象有点难以改变。我当然不会声称如果每个对象都必须拥有自己独立访问数据的知识,那么Aware对象就更好了,但只要你可以将其抽象成一个单一的地方,我就看不出PI更好在哪里了。 - Bobson

1
仅就您的示例而言,通过编写Person.Load(id),您正在表达“按照标识符加载此对象”- 您正在创建一个严格的工厂模式,只有在您知道它们的ID时才能获取对象,后来您会发现需要根据某些搜索条件提取记录,然后您将添加更多的工厂方法,而第二种解决方案已经给您提供了所需的所有自由度。
第二个解决方案非常适合在运行时切换持久性逻辑,因为它与对象模型解耦,您可以理论上决定在客户端代码中使用哪个持久性引擎,而不需要硬编码和触及您的OM,并且说您需要更改每个实例的MyContext是错误的,您应该编写客户端代码以让它从某种工厂类或依赖注入接收上下文。
例如,您可以使用以下伪代码:
var person = onlineDbContext.Persons.Single(x=>x.Guid == myguid);

offlineDbContext.Persons.Add(person)
offlineDbContest.SaveOrUpdate();

那个伪代码是否必须在两个单独的 using() 语句中,每个上下文一个?此外,我如何拥有支持相同对象的多个上下文? - Bobson
我没有写using语句,因为这并不重要,我甚至没有谈论特定的ORM,我只是展示了如果你按照处理方式将数据分离,就像邮递员的信件一样,你会得到更多的机会。如何创建一个不同的邮递员是另一个话题。 - Spartaco
好的。然而,我仍然不知道如何在不同的上下文中使用person。如果新的邮递员在不同的路线上并且从未来过我的地方,那么换一个新的邮递员也没有帮助。这个答案似乎正是我正在寻找的,我只是试图理解它。 - Bobson

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