我正在调查个人Grails项目,并希望整合一个域模型来表示产品目录。我真的无法决定最好的方法。我将拥有许多不同的产品类别,尽管许多类别只有一组基本的属性,这些属性在所有类别中共享(例如产品名称,产品描述,价格等)。但是,某些产品将具有特定于其类别的其他属性。
我研究了实体属性值(EAV)模型技术,该技术提供了一种非常可扩展的解决方案。而且,我已经考虑了使用显式OO继承模型的路线,其中我有基础Product类的子类来表示任何具有其他属性的产品。
显然,第二种方法的可扩展性较低 - 添加新的产品类别需要新的实体,并且可能需要前端的自定义视图/编辑器。但是,作为一名开发人员,我认为编程模型更加清晰,而且编码更合乎逻辑。
EAV方法将允许动态可扩展性,但会导致更加神秘的编程模型,并且会在DB(复杂表连接)中产生性能开销。可以动态生成前端的视图/编辑器,以包含产品类别的任意数量的自定义属性 - 尽管我确信在可用性方面这样的动态生成是不够的。
当我考虑像Grails这样的框架时,沿着创建显式继承模型的路线似乎是有意义的。我不相信像Grails这样的框架会很好地适应EAV方法 - Grails的很多好处都会在复杂性中丢失。但是,我不确定这种方法会随着产品类别数量的增加而实际扩展。
我真的很想知道其他人对这种建模挑战的经验!
答案 0 :(得分:0)
我遇到了与此类似的情况,并采用了继承解决方案。进入这个我知道我从来没有超过10个班级所以我并不担心复杂性的指数增长。虽然每个类都需要视图和控制器,但您可以采取一些措施来减少代码重复。首先要做的是将所有常见的视图代码放在模板中。例如,如果您的所有类都有价格,名称和描述,那么允许显示和编辑它的视图代码应放入模板中。您可以简单地执行
,而不是在每个视图中都有重复的代码行<g:render template=”/baseView</g>render>
有关模板的详细信息,请参阅http://www.grails.org/Tag+-+render 我觉得有用的第二件事是将所有共享控制器代码移动到一个类中,并定义我可以从实际控制器调用的闭包。这非常难看,因为我的save方法不仅可以确保基类的字段得到正确处理,而且还可以为继承类的极端情况提供代码。回顾一下,更好的选择可能是将自定义行为定义为需要它或使用服务的域类的函数。有了这个说,把代码放入可以从控制器调用的闭包中仍然有用,因为它允许我有一个行长控制器主体而不是30或40.如果我必须修改处理基类的代码我可以编辑它闭包定义的位置,并且更改将反映在我的所有控制器上,而不会将代码更改为控制器的实际源文件。这非常有用,允许我在一个地方编辑代码,而不是在10个控制器上编辑重复的代码。
答案 1 :(得分:0)
Inheritance适用于Hibernate和GORM。请考虑using table-per-subclass
映射,因为您无法使用(默认)NOT NULL
继承映射定义table-per-hierarchy
约束。
您还可以将composition用于“不那么常见”但共享的属性。
“EAV”的标准是,您是否需要在不更改数据模型的情况下引入新属性?
在实践中,像你这样的应用程序使用继承和EAV的组合。
在查询JOIN
ed表时,您会关注性能。如果index包含在SQL WHERE
语句中的列,那通常不就会出现问题。
(GORM / Hibernate会自动创建外键,这也很重要。)(鉴于,必要的索引到位,DBMS提供了不错的查询优化器(即PostgreSQL或者SQL Server - 可能不是MySQL),你可以在50毫秒或更短的时间内使用10个连接从数百万条记录中进行选择。)
最后,你的问题上有一个很好的,最近的discussion。