【问题标题】:How to avoid loading duplicate objects into main memory?如何避免将重复的对象加载到主内存中?
【发布时间】:2018-02-24 22:08:29
【问题描述】:

假设我正在使用 SQL 并且我有两个表。一个是公司,另一个是员工。当然,员工表有一个外键引用他或她工作的公司。

当我在我的代码中使用这个数据集时,我想知道每个员工所在的公司。我认为最好的解决方案是将一个实例变量添加到我的名为 Company 的 Employee 类(Company 类型)。该变量可能是延迟加载的,也可能是手动填充的。

问题是许多员工为同一家公司工作,因此每个员工最终都会存储一个完全相同的 Company 对象副本,这是不必要的。如果需要更新有关公司的某些内容,这可能是一个大问题。此外,Company 对象自然会存储其员工列表,因此我也可能遇到无限循环引用的问题。

我应该做些什么不同的事情?面向对象的设计似乎不适用于关系数据。

这更像是一个设计/原理之类的问题,我没有任何具体的代码,我只是在寻找朝着正确方向迈出的一步!

如果您有任何问题,请告诉我。

【问题讨论】:

  • 如果您缓存公司并引用同一个实例,则根本没有重复。
  • 只是对@Gusman 评论的补充,您想使用基于哈希的集合来存储这些引用。此外,根据您的应用程序,它可能是并发收集。
  • @Karolis 这是这个问题的正常解决方案吗?我从来没有在任何地方看到过这种情况,所以我假设有一个更典型的解决方案,考虑到地球上几乎所有使用 SQL 的应用程序都可能遇到这个问题。
  • 你应该使用 ORM 框架(我知道 Java 的),例如 Hibernate、Ebean、ActiveJDBC 等。如果你不想或不能使用 ORM 框架,你应该使用您的对象是对象而不是数据值,即如果公司 Acme 的 id=1,则应该只存在一个具有该 id 的公司实例,无论是否有许多 Employee 实例都引用了该公司。有很多技术可以实现这一点,设计持久层很难......
  • OOP 从来都不是用来建模和表示数据的。数据应该被封装或作为消息传递。对象应该围绕系统服务和职责进行设计。你所做的相当于根据路线图造车。不要将域模型实体与系统对象/服务混为一谈。

标签: java c# sql oop design-patterns


【解决方案1】:

不要尝试将您的业务对象设计为镜像数据库架构。
设计对象以满足您的业务需求。

例如,当您需要显示没有公司信息的员工列表时,您可以创建仅从数据库中检索所需信息到对象的函数

public class EmployeeBasicInfo
{
    public int Id;
    public string Name;
}

对于下一个要求,您需要一个包含完整信息的员工列表 - 然后您将拥有从数据库中检索完整数据的功能

public class Employee
{
    public int Id;
    public string Name;
    public int Age;
    public CompanyBasicInfo Company;
}

Company 类没有员工集合,但只有Employee 类所需的信息。

public class CompanyBasicInfo 
{
    public int Id;
    public string Name;
}

当然,在最后一种情况下,您最终会得到一堆不同的 Company 对象,它们将具有相同的数据。但应该没问题。

如果您担心在不同对象中拥有相同的数据副本会导致性能问题,那么直到您加载数百万员工时才会出现问题 - 这应该是您的应用程序设计出现问题的好兆头。

当然,在您实际需要加载数百万员工的情况下 - 然后您可以使用加载员工的类的方法 - 将首先加载 Map<int, Company> 中的所有公司,然后在加载员工时您将引用相同的 @987654328 @员工实例。

【讨论】:

  • 那么如果 Employer/Company 类也这样做并存储一个员工列表,这不会导致一个大问题(无限递归)吗?员工存储公司,存储员工的副本,存储公司的副本,存储员工的第二个副本,存储公司的第二个副本等,直到您的计算机内存不足并崩溃。有什么方法可以在不缓存的情况下避免这种情况?也许我只是在做一些根本错误的事情?
  • @sausageberg 您只存储引用,只是指向某个内存块的链接。这就是图形和许多其他常见集合类型的工作方式。但是您要么为每个条目存储新值,要么缓存它,我现在看不到任何其他选项。
  • @Karolis 如果没有缓存,它会存储比引用更多的东西,它会复制对象本身。我真的是唯一遇到这个问题的人吗?必须有某种方法可以做到这一点,而不依赖于延迟加载每个属性。
  • @sausageberg,您创建的对象仅满足一个特定要求的想法。对于显示带有公司信息的员工列表CompanyBasicInfo 类不需要在其中包含员工集合。
【解决方案2】:

我真的是唯一遇到这个问题的人吗?必须有某种方法可以做到这一点,而不依赖于延迟加载每个属性。

这个问题已经解决了很多次了。避免使用任何广泛可用的 ORM 框架重新发明轮子。

在数据库表中,主键标识一条记录;在运行的应用程序中,引用跟踪对象;而且,在更底层的抽象中,内存地址指向代表该对象的字节。

当您初始化一个对象并将其分配给一个变量时,该变量足以跟踪内存中的对象,以便您随后可以访问它。但是,在数据库层,需要一个主键来定位数据库表中的记录。因此,为了弥合关系模型和对象模型之间的差距,您的对象中需要人工标识符属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-30
    • 2019-12-13
    • 2010-09-10
    • 2013-09-09
    • 1970-01-01
    • 2020-04-21
    • 2015-09-09
    • 1970-01-01
    相关资源
    最近更新 更多