Сохранение карт и списков свойств в формате JSON в Grails - PullRequest
14 голосов
/ 12 ноября 2011

EDIT: метод 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 выше и изменить его на:

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

Для меня это не очень элегантное решение моей проблемы.Вопросы:

  1. Существует ли более простой подход для сохранения моих сложных динамических картографических данных?
  2. Если мне нужно сделать это так, как я делаю в настоящее время, есть ли способ избежать взлома на шаге 3?

Ответы [ 4 ]

8 голосов
/ 13 ноября 2011

Для варианта 2 вы можете использовать событие beforeValidate вместо событий beforeInsert и beforeUpdate, чтобы обеспечить правильное распространение изменения.

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)
  }
}
1 голос
/ 10 сентября 2014

Есть ли более простой подход для сохранения моих сложных динамических картографических данных?

Grails может сохранять список и карту из коробки, вам не нужно писать сложный код преобразования и злоупотреблять 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()

Я думаю, что это гораздо проще и чище, как с этим справиться.

1 голос
/ 13 ноября 2011

Я, конечно, не очень много знаю о приложении, которое вы создаете, но это не помешает искать альтернативные модели хранения данных, особенно базы данных NOSQL.Grails тоже получил некоторую поддержку.

0 голосов
/ 11 апреля 2014

В ответ на

Есть ли более простой подход для сохранения моих сложных динамических картографических данных?

Grails может сохраняться Наборы, списки и карты в базе данных . Это может быть более простой подход, чем работа с преобразованиями JSON. Чтобы карта сохранялась в базе данных, необходимо включить ее в свойство hasMany.

Map complexMapStructure
static hasMany = [complexMapStructure: dynamicComplexPropertyObject]

Документация предполагает, что использование сумки может быть более эффективным.

...