Подтвердить что ты не робот

Сохранение карт и списков свойств как JSON в Grails

EDIT: метод onload() изменен на afterLoad(): иначе объекты могут не передаваться должным образом на карту.


В настоящее время я использую некоторые классы доменов с множеством динамических и сложных свойств, которые мне нужно постоянно обновлять и обновлять.

Я сохраняю их в структуре карты для каждого класса, так как это упрощает обращение к моим контроллерам и т.д.

Однако, поскольку 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)

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

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

Ответ 1

Для опции 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)
  }
}

Ответ 2

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

Ответ 3

Существует ли более простой подход к сохранению моих сложных данных динамической карты?

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()

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

Ответ 4

В ответ на

Существует ли более простой подход к сохранению моих сложных данных динамической карты?

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

Map complexMapStructure
static hasMany = [complexMapStructure: dynamicComplexPropertyObject]

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