我应该在哪里存储模型中的虚拟/计算/复杂对象字段?

时间:2010-02-22 21:00:41

标签: orm oop model

我有与数据库表对应的模型。例如,House类具有“color”,“price”,“square_feet”,“real_estate_agent_id”列。

当我显示有关房屋的信息时,我想要显示代理商名称是很常见的。因此,我的House类包含以下字段:

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

  String realEstateAgentName;
}

我一直将realEstateAgentName称为虚拟字段,因为它是从外表中提取的(在real_estate_agent_id上加入)。

这对我来说不合适,因为它将实际数据库列与外部对象的属性混合在一起。但它很快,而且在很多情况下它确实运作良好。

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

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

  RealEstateAgent realEstateAgent;
}

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

我倾向于决定存储整个对象与一些与ID相关的关键信息(例如Name),具体取决于我看到需要访问其代表的对象的其他信息的可能性。

我有几个问题:

在我混合和匹配的两种方法中,哪种方式最好?我倾向于存储id +对象,而不是从我认为可能需要的外来对象中拉出属性。在这两者中,这似乎更“正确”。但它并不完美,因为在许多情况下我没有任何需要保湿整个外来物体,这样做会造成不必要的资源浪费,或者由于数据量或连接数量而无法实现当我对所有信息都没有任何用处时,我会被要求。鉴于这种情况,这似乎是一个糟糕的设计选择,因为我的数据库中有很多空字段并不是真的,但是在记忆中只是因为没有必要填充它们 - 现在我必须跟踪我填充的那些。

但最佳做法是将ID与它所代表的对象一起存储吗?我是应该将对象存储为属性,还是应该将其存放在某个地图中,ID是关键?

在Object世界中,似乎ID甚至不应该存储为属性,它所代表的外部Object是逻辑替代。但是,由于所有内容都与关系数据库紧密结合,因此它似乎不太可行。

我的模型/类的这种令人沮丧的杂质是我必须要忍受的,或者是否存在通过在某个地方进行某种分叉或父/子子类化来解决这个问题的模式纯粹的“对象,而另一个像数据库一样扁平?

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

3 个答案:

答案 0 :(得分:0)

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

然而,实体框架会为您提供完整的控制权,您可以在此处决定数据如何在不考虑物理基础的情况下显示。然而,它还没有完全实现。

这里真的没有杂质。问题是你试图用面向对象的方式表示关系数据的抽象。为了解决像这样的开发难题,更大规模的项目正在转向域驱动设计,其中底层数据被抽象为存储库的逻辑分组。在表中思考类对于大规模解决方案可能会有问题。

只需2美分。

答案 1 :(得分:0)

我可以讲一下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

OTOH如果您确定对于特定类(几乎)总是需要特定属性,则可以在该属性的ORM映射中指定预先加载,在这种情况下,属性在包含对象时立即加载。在映射中,您还可以指定是否需要连接查询或子选择查询。

答案 2 :(得分:0)

Hibernate是Java生态系统中最流行的ORM工具,通常允许您这样做:

class House {
 String color;
 Double price;
 Integer squareFeet;
 RealEstateAgent realEstateAgent;
}

这会转换为如下所示的数据库表:house(id,color,price,squareFeet,real_estate_agent_id)

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

house.getRealEstatAgent().getName()

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

修改后修改 所有解决方案都以类似的方式处理范式不匹配(OO和关系世界之间)。设计已经完成,问题解决了。是的,作为一名应用程序开发人员,处理这个问题仍然很痛苦,但我想只要我们想要将关系数据库和面向对象的持久性结合在一起,它就是它的方式。