0

我在 grails 中有一个域类,应该只用相同的名称创建一次。为了确保我有一个静态方法 getColor 和私有构造函数,如下所示:

class Color {
  String name

  static hasMany = [moods: Mood] 

  // not accessible
  private Color() {}

  // not accessible because getColor should be used
  private Color(String name) {
    this.name = name
  }

  static getColor(String name) {
    def color = Color.findByName(name.toLowerCase())
    color ? color : new Color(name).save(flush:true) 
  }

  def beforeValidate() {
    name = name.toLowerCase();
  }
}

为了确保仅使用静态 getColor 方法创建 Color 对象,我想将构造函数设为私有。到目前为止,它可以工作,我可以创建颜色对象。但是当我使用这个实例来创建 Object Mood 的对象时

class Mood {

  static belongsTo = [color:Color]

}

def color = Color.getColor('verylightgreen')
def mood = new Mood(color: color)

我得到一个例外:

error initializing the application: Could not instantiate bean class [de.tobi.app.Color]: Is the constructor accessible?

此异常由

def mood = new Mood(color: color)

那么为什么创建 Mood 需要访问 Color 的构造函数。我已经通过了对象。一般来说,在 groovy/grails 中隐藏域类的构造器以控制对象的创建方式的最佳方法是什么。特别是地图控制器的使用也应该被禁用。

4

2 回答 2

5

用作您name的主键Color可以实现唯一性。另外,findOrSaveBy*可以用来替换自定义的静态方法getColor

如果制作name主键不是一个可行的选择,那么您可以继续添加约束,正如几乎所有个人在对该问题的评论中提到的那样。:)

class Color {
  String name

  static mapping = {
      //column is optional
      id name: 'name', generator: 'assigned', type: 'string', column: 'NAME' 
  }

  static hasMany = [moods : Mood] //for example

  //DO NOT NEED THIS
  //This can be achieved by findOrSaveBy*
  /*static getColor(String name) {
    def color = Color.findByName(name.toLowerCase())
    color ? color : new Color(name).save(flush:true) 
  }*/

  def beforeValidate() {
    name = name.toLowerCase();
  }
}

那么你可以很好地做到

def color = Color.findOrSaveByName('verylightgreen')
def mood = new Mood()

color.addToMoods(mood)
color.save()
于 2013-08-16T17:11:30.760 回答
1

关于异常:

由于地图构造函数而发生异常。对于普通的 groovy 类,这不是问题,但 grails 将域类注册为原型 bean。然后它会覆盖元类中的构造函数以使用 bean 创建和自动装配机制来获取实例。地图构造函数和自动装配中的某些内容导致在地图设置之前创建一个空的颜色 bean。

如果您将代码更改为:

Color c = Color.getColor('red')
Mood m = new Mood()
m.color = c
m.save()

异常应该消失。

您可以考虑为这个特定用例提交JIRA 问题,但我不知道 grails 团队是否会认为这是一个错误或设计决定。它肯定没有记录在任何地方。

关于设计:

在不了解您的模型的更多信息的情况下,我同意 dmahapatro 将数据完整性的责任转移到您的数据库和 GORM 约束上。这就是他们的目的。

规避这一点会导致代码中出现异常的使用模式,例如知道使用Color.getColor而不是正常的域类实例化。

像 Grails 这样的约定优于配置框架背后的理念是尽可能地遵守约定,这样任何熟悉约定的人都可以介入并立即知道发生了什么。

于 2013-08-16T20:51:19.067 回答