2010-12-05 38 views
0

我正在调查个人Grails项目,并希望将域模型放在一起以表示产品目录。我真的不能决定最好的方式去做。虽然许多类别只有一组基本属性(所有类别之间共享)(例如,产品名称,产品说明,价格等),但我将拥有许多不同的产品类别。但是,一些产品将具有特定于其类别的其他属性。在Grails中建模产品目录模型

我已经研究了实体属性值(EAV)模型技术,它提供了一个非常可扩展的解决方案。而且,我已经考虑了使用显式OO继承模型的路线,其中我有一个基类Product类的子类来表示具有附加属性的任何产品。

显然,第二种方法的扩展性较差 - 添加新的产品类别需要一个新的实体,并且可能需要前端的自定义视图/编辑器。不过,作为一名开发人员,我认为编程模型更加清晰,并且更符合代码编写的逻辑。

EAV方法将允许动态扩展性,但会导致更隐蔽的编程模型,并会在DB(复杂表连接)中产生性能开销。前端的视图/编辑器可以动态生成,以包含产品类别的任意数量的自定义属性 - 尽管我确信会出现这种动态生成不足以满足可用性角度的情况。

当我考虑像Grails这样的框架时,似乎有必要沿着创建显式继承模型的路线走下去。我不相信像Grails这样的框架能够很好地适应EAV方法 - Grails的很多好处都会在复杂性中丧失。但是,我不确定这种方法会随着产品类别数量的增加而实际扩展。

我真的很想听听其他人对这种建模挑战的体验!

回答

0

我有类似的情况,并继承解决方案。进入这个阶段我知道我永远不会超过10个班,所以我并不担心复杂性的指数级增长。尽管您需要每个类的视图和控制器,但您可以采取一些措施来减少代码重复。首先要做的是将所有常见的视图代码放在模板中。例如,如果所有类都有价格,名称和描述,那么允许显示和编辑它的视图代码应该放入模板中。而不是在每一个码重复行的视图,你可以简单地做一个

<g:render template=”/baseView</g>render> 

欲了解更多信息的模板见http://www.grails.org/Tag+-+render 我发现这样做是有用的第二件事是将所有共享控制器的代码放到一个类,并定义关闭我可以从我的实际控制器拨打电话。这很难看,因为我的save方法不仅保证了基类的字段被正确处理,而且还有代码来处理继承类的转角情况。回顾一下,更好的选择可能是将自定义行为定义为需要它或使用服务的域类的功能。有人说,将代码放入可以从控制器调用的闭包中仍然有帮助,因为它可以让我有一行长的控制器体,而不是30或40个。如果我必须修改处理基类的代码,我可以编辑它在那里定义了闭包,并且这种变化会反映在我的所有控制器中,而不会更改代码到控制器的实际源文件。这非常有用,并允许我在一个地方编辑代码,而不是在10个控制器上编辑重复的代码。

+0

谢谢,这里有一些非常有用的想法。我感觉继承路线感觉更舒适。就像你的情况一样,我不认为实体的数量会达到成为问题的程度。 – DrewEaster 2010-12-06 15:15:40

0

Inheritance在Hibernate和GORM下正常工作。考虑using映射table-per-subclass,因为您不能用(默认)table-per-hierarchy继承映射来定义NOT NULL约束。

您也可以使用composition来表示“不那么”常见但共享的属性。

“EAV”的标准是,您是否需要在不更改数据模型的情况下引入新属性?

实际上,像您这样的应用程序使用继承和EAV的组合。

在查询JOIN ed表时,您担心性能问题。这通常是而不是问题如果您index SQL WHERE语句中包含的列。 (GORM/Hibernate会自动创建外键,这也是非常重要的。)(给定的,必要的索引已经到位,并且DBMS提供了一个体面的查询优化器(即PostgreSQL或SQL Server - 可能不是MySQL)),您可以使用50个毫秒或更少的10次连接从数百万条记录中进行选择。)

最后,关于您的问题,最近出现了一个出色的近期discussion