在 Grails 中将映射和属性列表持久保存为 JSON

发布于 2024-12-15 07:23:53 字数 1775 浏览 1 评论 0原文

编辑:onload() 方法更改为 afterLoad():否则对象可能无法正确传递到地图。


我目前正在使用一些具有大量动态、复杂属性的域类,我需要保留并定期更新它们。

我将它们保存在每个类的 Map 结构中,因为这使得在我的控制器等中引用变得容易。

但是,由于 Grails 似乎无法在数据库中保留复杂的属性类型,如 List 和 Map,我正在使用以下方法通过 JSON String 对象实现此目的:

class ClassWithComplexProperties {

  Map complexMapStructure //not persisted
  String complexMapStructureAsJSON //updated and synched with map via onload,beforeInsert,beforeUpdate


  static transients = ['complexMapStructure']

  def afterLoad() {  //was previously (wrong!): def onLoad() {
    complexMapStructure=JSON.parse(complexMapStructureAsJSON)
  }
  def beforeInsert() {
    complexMapStructureAsJSON= complexMapStructure as JSON
  }
  def beforeUpdate() {
    complexMapStructureAsJSON= complexMapStructure as JSON
  }
  static constraints = {    
    complexMapStructureAsJSON( maxSize:20000)
  }
}

只要我只从数据库加载数据,这种方法就很有效,但是当我想将更改保存回数据库时,我会遇到麻烦。例如,当我执行以下操作时

/* 1. Load the json String, e.g. complexMapStructureAsJSON="""{
   data1:[[1,2],[3,4]],//A complex structure of nested integer lists    
   data1:[[5,6]] //Another one
    }""" :
*/
ClassWithComplexProperties c=ClassWithComplexProperties.get(1)

// 2. Change a value deep in the map: 
c.complexMapStructure.data1[0][0]=7

// 3. Try to save:

c.save(flush:true)

,这通常不起作用,因为我猜(?),GORM 将忽略 save() 请求,因为地图本身是暂时的,并且在持久属性中没有发现任何更改。

我可以使其按预期工作

// 3.Alternative save:
complexMapStructureAsJSON="" //creating a change in persisted property (which will be overwritten anyway by the beforeUpdate closure)
c.save(flush:true)

如果我修改上面的步骤 3 并将其更改为:对我来说,这不是对我的问题的非常优雅的处理, 。 问题:

  1. 是否有更简单的方法来保存复杂的动态地图数据?
  2. 如果我需要按照目前的方式进行操作,有没有办法避免步骤 3 中的 hack ?

EDIT: onload() method changed to afterLoad(): Otherwise objects might not be passed properly to the map.


I am currently using some domain classes with a lot of dynamic, complex properties, that I need to persist and update regularly.

I keep these in a Map structure for each class since this makes it easy for referencing in my controllers etc.

However, since Grails does not seem to be able to persist complex property types like List and Map in the DB I am using the following approach to achieve this via JSON String objects:

class ClassWithComplexProperties {

  Map complexMapStructure //not persisted
  String complexMapStructureAsJSON //updated and synched with map via onload,beforeInsert,beforeUpdate


  static transients = ['complexMapStructure']

  def afterLoad() {  //was previously (wrong!): def onLoad() {
    complexMapStructure=JSON.parse(complexMapStructureAsJSON)
  }
  def beforeInsert() {
    complexMapStructureAsJSON= complexMapStructure as JSON
  }
  def beforeUpdate() {
    complexMapStructureAsJSON= complexMapStructure as JSON
  }
  static constraints = {    
    complexMapStructureAsJSON( maxSize:20000)
  }
}

This works well as long I am only loading data from the DB, but I run into trouble when I want to save back my changes to the DB. E.g. when I do the following

/* 1. Load the json String, e.g. complexMapStructureAsJSON="""{
   data1:[[1,2],[3,4]],//A complex structure of nested integer lists    
   data1:[[5,6]] //Another one
    }""" :
*/
ClassWithComplexProperties c=ClassWithComplexProperties.get(1)

// 2. Change a value deep in the map: 
c.complexMapStructure.data1[0][0]=7

// 3. Try to save:

c.save(flush:true)

This will usually not work, since, I guess(?), GORM will ignore the save() request due to the fact that the map itself is transient, and no changes are found in the persisted properties.

I can make it work as intended if I hack step 3 above and change it to:

// 3.Alternative save:
complexMapStructureAsJSON="" //creating a change in persisted property (which will be overwritten anyway by the beforeUpdate closure)
c.save(flush:true)

To me this is not a very elegant handling of my problem.
The questions:

  1. Is there a simpler approach to persist my complex, dynamic map data?
  2. If I need to do it the way I currently do, is there a way to avoid the hack in step 3 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

娇妻 2024-12-22 07:23:53

对于选项 2,您可以使用 beforeValidate 事件而不是beforeInsertbeforeUpdate 事件,以确保更改正确传播。

class ClassWithComplexProperties {

  Map complexMapStructure //not persisted
  String complexMapStructureAsJSON //updated and synched with map via onload,beforeInsert,beforeUpdate


  static transients = ['complexMapStructure']

  def onLoad() {
    complexMapStructure=JSON.parse(complexMapStructureAsJSON)
  }

// >>>>>>>>>>>>>>
  def beforeValidate() {
    complexMapStructureAsJSON= complexMapStructure as JSON
  }
// >>>>>>>>>>>>>>

  static constraints = {    
    complexMapStructureAsJSON( maxSize:20000)
  }
}

For option 2, you can use the beforeValidate event instead of beforeInsert and beforeUpdate events to ensure that the change propagates correctly.

class ClassWithComplexProperties {

  Map complexMapStructure //not persisted
  String complexMapStructureAsJSON //updated and synched with map via onload,beforeInsert,beforeUpdate


  static transients = ['complexMapStructure']

  def onLoad() {
    complexMapStructure=JSON.parse(complexMapStructureAsJSON)
  }

// >>>>>>>>>>>>>>
  def beforeValidate() {
    complexMapStructureAsJSON= complexMapStructure as JSON
  }
// >>>>>>>>>>>>>>

  static constraints = {    
    complexMapStructureAsJSON( maxSize:20000)
  }
}
亚希 2024-12-22 07:23:53

当然,我对您正在构建的应用程序了解不多,但查找替代数据存储模型(尤其是 NOSQL 数据库)不会有什么坏处。 Grails 也得到了一些支持。

I of course do not know much about the application you are building, but it won't hurt to look up alternate data storage models particularly NOSQL databases. Grails has got some support for them too.

信愁 2024-12-22 07:23:53

是否有更简单的方法来保存复杂的动态地图数据?

Grails 可以开箱即用地持久化 List 和 Map,您不需要编写复杂的转换代码和滥用 Json。

地图示例:

class ClassWithComplexProperties {
    Map<String, String> properties    
}

def props = new ClassWithComplexProperties()
props.properties = ["foo" : "bar"]
props.save()

列表示例:

class ClassWithComplexProperties {
    List<String> properties
    static hasMany = [properties: String]
}

def props = new ClassWithComplexProperties()
props.properties = ["foo", "bar"]
props.save()

我认为这是处理它的更简单、更清晰的方式。

Is there a simpler approach to persist my complex, dynamic map data?

Grails can persist List and Map out of the box, you don't need to write complex conversion code and abuse Json.

Example for Map:

class ClassWithComplexProperties {
    Map<String, String> properties    
}

def props = new ClassWithComplexProperties()
props.properties = ["foo" : "bar"]
props.save()

Example for List:

class ClassWithComplexProperties {
    List<String> properties
    static hasMany = [properties: String]
}

def props = new ClassWithComplexProperties()
props.properties = ["foo", "bar"]
props.save()

I think this is much easier and cleaner way how to deal with it.

始终不够 2024-12-22 07:23:53

回应

是否有更简单的方法来保存复杂的动态地图数据?

Grails 可以将集合、列表和映射持久保存到数据库 。这可能是比处理 JSON 转换更简单的方法。要将地图持久保存到数据库中,您需要将其包含在 hasMany 属性中。

Map complexMapStructure
static hasMany = [complexMapStructure: dynamicComplexPropertyObject]

文档表明使用 Bag 可能会更有效。

In response to

Is there a simpler approach to persist my complex, dynamic map data?

Grails can persist Sets, Lists and Maps to the database. That may be a simpler approach than dealing with JSON conversions. To have the map persisted to the database you need to include it in the hasMany property.

Map complexMapStructure
static hasMany = [complexMapStructure: dynamicComplexPropertyObject]

The documentation suggests that using a Bag may be more efficient.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文