Orm 模型中的虚拟/计算/复杂对象字段应存储在何处?

Orm 模型中的虚拟/计算/复杂对象字段应存储在何处?,orm,oop,model,Orm,Oop,Model,我有对应于数据库表的模型。例如,House类有“颜色”、“价格”、“平方英尺”、“房地产代理id”列 在显示房屋信息时,我通常希望显示代理名称。因此,my House类具有以下字段: class House { String color; Double price; Integer squareFeet; Integer realEstateAgentId; String realEstateAgentName; } 我一直将realEstateAgentName称为一个

我有对应于数据库表的模型。例如,House类有“颜色”、“价格”、“平方英尺”、“房地产代理id”列

在显示房屋信息时,我通常希望显示代理名称。因此,my House类具有以下字段:

class House {
  String color;
  Double price;
  Integer squareFeet;
  Integer realEstateAgentId;

  String realEstateAgentName;
}
我一直将realEstateAgentName称为一个虚拟字段,因为它是从外部表中提取的(在real\u estate\u agent\u id上进行连接)

我觉得这不对,因为它混合了实际的数据库列和外部对象的属性。但是它很快,而且在很多情况下,它真的很有效

其他时候,我发现自己在做这样的事情:

class House {
  String color;
  Double price;
  Integer squareFeet;
  Integer realEstateAgentId;

  RealEstateAgent realEstateAgent;
}
如您所见,我正在存储与存储在House表中的ID相对应的实际对象

我倾向于决定存储整个对象,而不是与ID(例如名称)相关的一些关键信息,这取决于我看到需要访问其所代表对象的其他信息的可能性

我有几个问题:

在我混合和匹配的两种方法中,哪一种最好?我倾向于将id+存储到对象中,而不是仅仅从我认为可能需要的外来对象中提取属性。在这两种情况中,这似乎更“正确”。但这并不完美,因为在许多情况下,我不需要为整个异物水合,这样做会造成资源的过度浪费,或者是不可行的,因为当我无法使用所有引入的信息时,需要大量的数据或连接数。考虑到这种情况,这似乎是一个糟糕的设计选择,因为我的数据库中有很多空字段,它们不是真正的空字段,但它们在内存中是如此的简单,因为不需要填充它们——现在我必须跟踪填充了哪些字段

但是,最好的做法是将ID存储在它所表示的对象旁边吗?我甚至应该将该对象存储为属性,还是应该将其外部存在于某个映射中,以ID作为键

在对象世界中,ID似乎甚至不应该存储为属性,它表示的外部对象是逻辑替换。但由于所有东西都与关系数据库紧密耦合,这似乎不太可行

我的模型/类中的这种令人沮丧的杂质是我不得不忍受的吗,还是有一些模式通过某种分叉或父/子类化来解决这一问题,其中一个是“纯”对象,而另一个像数据库一样扁平?


编辑:我在这里寻找设计建议,而不是特定的ORM框架,如Hibernate/nHibernate/等。我使用的特定语言没有我满意的语言版本的ORM解决方案,示例是Java风格的,但我的源代码不是用Java编写的。

LINQ to SQL使用ID+对象,效果很好。我更喜欢那种型号,因为它最灵活。Hibernate也可以这样做。您将面临的一个问题是深度加载:何时实际加载对象而不仅仅是ID?LINQtoSQL和Hibernate都有延迟加载,让您可以控制这个问题

然而,实体框架似乎为您提供了完全的控制,您可以在其中决定数据的显示方式,而不考虑物理基础。然而,这一点尚未完全实现

这里真的没有杂质。问题是,您试图以面向对象的方式表示数据的抽象关系。为了摆脱这样开发的痛苦,更大规模的项目正在转向领域驱动的设计,其中底层数据被抽象为存储库的逻辑分组。对于大规模解决方案来说,将表看作类可能会有问题


只有我的2美分。

我可以告诉你Hibernate,因为这是我最熟悉的ORM工具。我相信其他ORM工具在某种程度上也支持类似的行为

Hibernate通过延迟加载解决了您的问题。将代理作为属性添加到房屋中,默认情况下,当房屋对象加载时,代理由Hibernate生成的代理对象表示,该代理对象仅包含ID。如果查询代理的其他属性,Hibernate将在后台加载完整对象:

class House {
    String color;
    Double price;
    Integer squareFeet;
    RealEstateAgent realEstateAgent;
    // getters, setters,...
}

House house = (House) session.load(House.class, new Long(123));
// at this point, house refers to a proxy object created by Hibernate
// in the background - no house or agent data has been loaded from DB
house.getId();
// house still refers to the proxy object
RealEstateAgent agent = house.getRealEstateAgent();
// house is now loaded, but agent not - it refers to a proxy object
String name = agent.getName(); // Now the agent data is loaded from DB

o如果您确定对于特定的类,您(几乎)总是需要一个特定的属性,那么您可以在该属性的ORM映射中指定立即加载,在这种情况下,只要包含该属性的对象被加载,就会立即加载该属性。在映射中,您还可以指定是要联接查询还是要子选择查询。

Hibernate,Java生态系统中最流行的ORM工具,通常允许您执行以下操作:

class House {
 String color;
 Double price;
 Integer squareFeet;
 RealEstateAgent realEstateAgent;
}
这转化为一个DB表,看起来像这样:房子(id、颜色、价格、平方英尺、房地产经纪人id)

如果需要打印代理的名称,只需遍历对象图:

house.getRealEstatAgent().getName()
通过延迟加载,这是非常有效的。我不会担心在压力测试证明这是一个问题之前,可能需要对数据库进行额外的查询

编辑后再编辑:
所有的解决方案都以类似的方式处理了范式不匹配(OO和关系世界之间)。设计完成了,问题解决了。是的,作为一名应用程序开发人员,这仍然是一个棘手的问题,但我想,只要我们想同时使用关系数据库和面向对象的持久性,这就是解决问题的方法。

我以前使用过Hibernate,但在许多情况下,这似乎有些过分。我只是想知道是否有一些简单的设计,虽然没有f那么复杂