Pytanie Trwałe mapy i listy właściwości jako JSON w Grails


EDYCJA: Metoda onload () zmieniona na afterLoad (): w przeciwnym razie obiekty mogą nie zostać poprawnie przekazane do mapy.


Obecnie używam niektórych klas domen z wieloma dynamicznymi, złożonymi właściwościami, które muszę utrzymywać i aktualizować regularnie.

Zachowuję je w strukturze mapy dla każdej klasy, ponieważ ułatwia to odwoływanie się do kontrolerów itp.

Jednakże, ponieważ Grails nie wydaje się być zdolny do utrzymywania złożonych typów właściwości, takich jak Lista i Mapa w DB, używam następującego podejścia, aby osiągnąć to poprzez obiekty String JSON:

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

Działa to tak długo, jak długo ładuję tylko dane z DB, ale napotkam kłopoty, gdy chcę zapisać moje zmiany w DB. Na przykład. kiedy wykonuję następujące czynności

/* 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)

Zwykle to nie działa, ponieważ, jak sądzę (?), GORM zignoruje żądanie save () ze względu na fakt, że sama mapa jest przejściowa i nie znaleziono żadnych zmian w utrwalonych właściwościach.

Mogę sprawić, by działał zgodnie z zamierzeniami, jeśli zhakuję krok 3 powyżej i zmienię go na:

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

Dla mnie nie jest to bardzo elegancka obsługa mojego problemu. Pytania:

  1. Czy istnieje prostsze podejście do utrzymywania złożonych, dynamicznych danych map?
  2. Jeśli muszę to zrobić tak jak obecnie, czy jest jakiś sposób na uniknięcie włamania w kroku 3?

14
2017-11-12 17:54


pochodzenie


W przypadku opcji 2 próbowałeś użyć beforeValidate wydarzenie zamiast beforeInsert i beforeUpdate? - OverZealous
To wystarczyło, i odpowiedział Q2. Plus jeden ode mnie! - John Doppelmann
OK, napiszę to jako prawdziwą odpowiedź! - OverZealous
Zobacz także moje pytanie uzupełniające: stackoverflow.com/questions/25749101 Okazuje się, że przejściowa mapa musi zostać zadeklarowana bindable: true w ograniczeniach, aby móc odbierać dane z formularza POST i z konstruktora mapy, podczas gdy pole JSON jest najlepiej zadeklarowane bindable: false. - Tobia


Odpowiedzi:


W przypadku opcji 2 można użyć skrótu beforeValidate wydarzenie zamiast beforeInsert i beforeUpdate zdarzenia, aby zapewnić poprawną propagację zmiany.

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

8
2017-11-13 09:49



Dzięki OverZealous. Pozostawi pytanie otwarte, ponieważ nadal chciałbym sprawdzić, czy ktoś może zaproponować rozwiązanie w pierwszym kwartale. - John Doppelmann
Myślę, że powinno być afterLoad zamiast onLoad. - Tomasz Kalkosiński


Oczywiście nie wiem zbyt wiele o aplikacji, którą budujesz, ale nie zaszkodzi szukać alternatywnych modeli przechowywania danych, szczególnie baz danych NOSQL. Grails również ma dla nich wsparcie.


1
2017-11-13 08:27



Zgadzam się, że ten rodzaj danych może być doskonałym kandydatem do przechowywania NOSQL. Jednakże, ponieważ chcielibyśmy, aby wszystkie nasze dane były przechowywane w tej samej bazie danych, obawiam się, że w tym przypadku nie będzie to możliwe. - John Doppelmann


Czy istnieje prostsze podejście do utrzymywania złożonych, dynamicznych danych map?

Grails może wytrwać List i Mapę po wyjęciu z pudełka, nie musisz pisać skomplikowanego kodu konwersji i nadużywać Json.

Przykład mapy:

class ClassWithComplexProperties {
    Map<String, String> properties    
}

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

Przykład listy:

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

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

Myślę, że jest to znacznie łatwiejsze i czystsze sposób radzenia sobie z tym.


1
2017-09-10 08:11



Tak, w dzisiejszych czasach może poprawnie przechowywać listę i mapy, ale tworzy wszystkie rodzaje pośrednich tabel w bazie danych, które czasami nie są tym, co jest potrzebne. W każdym razie dzięki. - Tobia
Tak, tabele pośrednie są efektem ubocznym tego rozwiązania. Jeśli chcesz ich uniknąć i masz dane w jednej kolumnie, spójrz na moją odpowiedź tutaj: stackoverflow.com/a/25760600/4018614 . Ale pamiętaj również, że jeśli będziesz musiał zmienić dane z wielu wątków, musisz rozwiązać synchronizację, w przeciwnym razie prawdopodobnie napotkasz OptimisticLockException. - Tomas Bartalos


W odpowiedzi na

Czy istnieje prostsze podejście do utrzymywania złożonych, dynamicznych danych map?

Graal może przetrwać Zestawy, listy i mapy do bazy danych. To może być prostsze podejście niż rozwiązywanie konwersji JSON. Aby mapa była przechowywana w bazie danych, musisz ją uwzględnić w usłudze hasMany.

Map complexMapStructure
static hasMany = [complexMapStructure: dynamicComplexPropertyObject]

Dokumentacja sugeruje, że używanie torby może być bardziej efektywne.


0
2018-04-10 21:43