How to change a Domain Class model object from one

2019-05-20 19:41发布

问题:

Given the following Grails GORM Domain Classes and using table-per-hierarchy inheritance:

class Book {
  static belongsTo = [ parent: Parent ]
  String title
}

abstract class Parent {
  static hasMany = [ books: Book ]
}

class A extends Parent {
  String asset
}

class B extends Parent {
  String asset
}

Say I have retrieved an instance of class A from the database. I want to convert it to an instance of class B. What is the grails idiomatic way to do this?

Without the hasMany relation, I would just delete A and create a new B. But I don't want the overhead of going through a large number of Books and updating their parent_id fields to point to the new B.

Under the hood, I essentially just want to perform an SQL UPDATE to change the database field parent.class from A to B. So what's the recommended way to do this in GORM/Grails?

回答1:

There's no support for this in Grails or Hibernate, since it's the analogue of changing an instance of A to a B in-memory, but an object has a fixed type and cannot change. There's no direct access to the discriminator column that you need to change the value of.

So the way to do this is via a SQL update as you say. There are a few options but the best is probably groovy.sql.Sql, e.g.

import groovy.sql.Sql

class FooService {
   def dataSource

   void convertToB(A a) {
      def sql = new Sql(dataSource)
      sql.executeUpdate('update parent set class=? where id=?', [B.name, a.id])
   }
}


回答2:

Looks like a sign of design flaw.

You could try to replace inheritance with aggregation - "Favor object composition over class inheritance." (Gang of Four 1995:20)" - extract a, say, HasAsset interface from Parent and add a reference to HasAsset.

Groovy delegation could help.