问题
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.
来源:https://stackoverflow.com/questions/5725362/how-to-change-a-domain-class-model-object-from-one-derived-class-to-another-in-g