This is a syntax question. I want a one-to-many relationship between Foo -> Bar (simplified here):
class Foo {
String fooPK1, fooPK2
static mapping = {
id composite: ["fooPK1", "fooPK2"]
}
static hasMany = [bars: Bar]
}
class Bar {
String fooPK1, dumbNameForFooPK2, barPK1, barPK2
Foo myFoo
static mapping = {
id composite: ["barPK1", "barPK2"]
columns {
myFoo[:] {
column name: "FOO_PK_1"
column name: "?????????????"
}
}
}
}
In this case, obviously Foo.fooPK1 maps to Bar.fooPK1, but i need Foo.fooPK2 to map to Bar.dumbNameForFooPK2. Hopefully this makes sense.
My problem is I have no idea what the syntax is supposed to be (or if there's a better way to do this!) and from what I could find, the grails documentation wasn't really helpful.
You need to rename the foreign key columns declaration inside Bar, wright?
class Bar {
Foo myFoo
static mapping = {
columns {
myFoo {
//declare them in the order of your id composite.
column name: "foo_pk_1"
column name: "dumb_name_for_foo_pk_2"
}
}
}
}
Related
I have an abstract class in a groovy file:
Implementation 1
public abstract class Item {
public String testStr;
public String getBigTestStr(){
String s = "___" + this.testStr;
return s;
}
}
Which is inherited by
class Material extends Item {
public String testStr;
static marshalling = {
detail {
includes "bigTestStr"
}
summary {
includes "bigTestStr"
}
}
static mapping = {
table 'materialset'
id column: 'NODEID'
testStr column: 'MATERIALTYPE'
version false
}
}
The idea is that hitting the endpoint for a material will return the return value of Item.bigTestStr(). However, when I trace through Item.bigTestStr(), the debug's variables table shows a value for this.testStr, but is null when it is added to s. See here:
I tried taking the testStr property out of Material
Implementation 2
class Material extends Item {
static marshalling = {
detail {
includes "bigTestStr"
}
summary {
includes "bigTestStr"
}
}
static mapping = {
table 'materialset'
id column: 'NODEID'
testStr column: 'MATERIALTYPE'
version false
}
}
but I still get the same problem.
For both implementations the endpoint returns
{
bigTestStr: ____null
}
How can I get the actual value of Material.testStr to be used by the function in its parent class?
UPDATE
As Emmanuel pointed out, Implementation 2 is the right way to use properties from a parent class. However, this implementation does not seem to work with mapping the parent class' properties to a database column. So the real question is: How can I get Material.testStr to map to a database column?
It looks like your problem is in how you initialized your Material instance. Here's an example:
public abstract class Item {
public String testStr
public String getBigTestStr(){
"___$testStr"
}
}
class MaterialA extends Item {
public String testStr
static marshalling = {
detail {
includes 'bigTestStr'
}
summary {
includes 'bigTestStr'
}
}
static mapping = {
table 'materialset'
id column: 'NODEID'
testStr column: 'MATERIALTYPE'
version false
}
}
class MaterialB extends Item {
static marshalling = {
detail {
includes 'bigTestStr'
}
summary {
includes 'bigTestStr'
}
}
static mapping = {
table 'materialset'
id column: 'NODEID'
testStr column: 'MATERIALTYPE'
version false
}
}
Shown above are three classes Item, MaterialA, and MaterialB. The two material classes simulate your two tests: MaterialA has a testStr property, while MaterialB inherits a property with the same name from Item instead. Here's what happens when instances of both classes are initialized and getBigTestStr() is tested:
new MaterialA(testStr: 'Hello').with {
assert bigTestStr == '___null'
}
new MaterialB(testStr: 'Hello').with {
assert bigTestStr == '___Hello'
}
In short, your second approach, inheriting the property, works. A super class does not (and should not) have access to anything in its subclasses. It doesn't even know about its subclasses. The approach works because initializing testStr in an instance of MaterialB actually initializes the inherited property from Item; which of course is accessible within the Item class.
In your case, Grails is initializing the instances for you using the values stored in the database. So I'd check your database.
Update
Here's an example using a trait rather than an abstract class:
public trait Item {
String testStr
public String getBigTestStr(){
"___$testStr"
}
}
class Material implements Item {
static marshalling = {
detail {
includes 'bigTestStr'
}
summary {
includes 'bigTestStr'
}
}
static mapping = {
table 'materialset'
id column: 'NODEID'
testStr column: 'MATERIALTYPE'
version false
}
}
new Material(testStr: 'Hello').with {
assert bigTestStr == '___Hello'
}
This makes it so that there's no need for an Item table.
I want to create a named query that will find all objects of one class, based on a property (or properties) of child class properties.
I want to be able to find all Bars where Foo.me == "some string"
So, I have this, and it doesn't work:
class Foo {
String me
}
class Bar {
Foo foo
static namedQueries = {
findByFooMe { meStr ->
eq(foo.me, meStr)
}
}
}
What does the correct syntax look like please? Also, how does it change if Bar hasMany Foos, and I want to find all Bars where one of its Foo,me properties is "search string"?
i.e.
class Bar {
static hasMany [foos: Foo]
}
While I wouldn't recommend using findBy as the prefix to a named query, you are close to having the right implementation. Here is an updated version with a new name for the query too.
static namedQueries = {
locateByFooMe { meStr ->
foo {
eq('me', meStr)
}
}
}
If you change your relationship to a collection (One to Many) just make sure the property name foo (in this case) changes to whatever you change it to (foos in your question) and the above query will still continue to work.
I have an object Foo that has a bidirectional one-to-one relationship with Bar and another one with Baz. When I try to do a .load with Foo and only give it a Bar, I get referential integrity exceptions complaining that there isn't a Baz.
Should this really be the case? In a real world environment isn't it possible that there wouldn't be any matching Baz object in the database?
I tried manually setting baz:null in the fixtures load closure, but I still get the same thing. On a side note, when I only set properties (such as a simple string), everything works fine. It's only when I start setting relationships.
This is with Grails 2.2.4, Fixtures 1.2, and without the build-test-data plugin installed.
EDIT: I have the constraints specifying Baz to be nullable and unique. Just for giggles I tried adding the blank constraint too, but no luck.
static constraints = {
baz nullable:true, unique: true, blank: true
}
EDIT 2: Here is a simplified version of the code:
class Foo {
String someValue1
String someValue2
String whatever
Bar bar
Baz baz
static mapping = {
id composite: ['someValue1', 'someValue2'], generator: 'assigned'
columns {
bar([:]) { column name: 'some_other_value' }
baz ([insertable:false, updateable: false]) {
column name: 'some_value_1'
column name: 'some_value_2'
}
}
version: false
static constraints = {
//there are no constraints for Bar
baz nullable:true, unique:true
}
}
class Bar {
String someOtherValue
static hasMany = [foos:Foo]
static mapping = {
id generator:'assigned', name:'someOtherValue'
}
}
class Baz {
String someValue1
String someValue2
String asdf
static mapping = {
id composite: ['some_value_1', 'some_value_2']
version false
}
}
class MyTest {
def fixtureLoader
#Before
void setup() {
fixureLoader.load {
myBar(Bar, someOtherValue:"shibby")
myFoo(Foo, someValue1:"test", someValue2:"test2", bar:myBar)
//i also tried this
//myFoo(Foo, someValue1:"test", someValue2:"test2", bar:myBar, baz:null)
}
}
}
Here is part of the exception:
Caused by: org.h2.jdbc.JdbcBatchUpdateException: Referential integrity
constraint violation: "FK190E74B120F4F2BC: MYSCHEMA.FOO FOREIGN
KEY(SOME_VALUE_1, SOME_VALUE_2) REFERENCES MYSCHEMA.BAZ(SOME_VALUE_1,
SOME_VALUE_2)"; SQL statement: insert into MYSCHEMA.foo (whatever,
some_other_value, some_value_2, some_value_1) values (?, ?, ?, ?, ?,
?, ?, ?) [23506-164]
EDIT: Sorry, I misspoke earlier. Bar has a many-to-one relationship with Foo.
Your simplified version of code (except hasMany in Bar) works for me without any FK exception. Although I would prefer a different approach to achieve a true one-one bidirectional relationship if I am correct with the parent and child mapping.
Below is my setup which works fine without the FK constraint exception. Note that I have also mentioned in comments how would I achieve true one-to-one bidirectional assuming Foo has one Bar and has one Baz.
class Foo implements Serializable{
String someValue1
String someValue2
String whatever
//True one to one can be achieved by doing as below
//static hasOne = [bar: Bar, baz: Baz]
Bar bar
Baz baz
static mapping = {
id composite: ['someValue1', 'someValue2'], generator: 'assigned'
columns {
bar([:]) { column name: 'some_other_value' }
baz ([insertable:false, updateable: false]) {
column name: 'some_value_1'
column name: 'some_value_2'
}
}
version: false
}
static constraints = {
//baz nullable:true, unique:true
}
}
class Bar {
String someOtherValue
//True one to one can be achieved by doing as below
//Below entry makes the relation bi-directional
//Foo foo
static mapping = {
id generator:'assigned', name:'someOtherValue'
//Optional, added for clarity
someOtherValue column: 'some_other_value'
}
}
class Baz implements Serializable{
String someValue1
String someValue2
String asdf
//True one to one can be achieved by doing as below
//Below entry makes the relation bi-directional
//Foo foo
static mapping = {
id composite: ['someValue1', 'someValue2']
//Optional, added for clarity
someValue1 column: 'some_value_1'
someValue2 column: 'some_value_2'
asdf column: 'asdf'
version false
}
}
class MyTests extends GroovyTestCase {
def fixtureLoader
void setUp() {
fixtureLoader.load {
myBar(Bar, someOtherValue:"shibby")
myFoo(Foo, someValue1:"test", someValue2:"test2",
whatever: "whatever", bar: myBar)
}
}
void testSomething() {
Foo.all.each{println it.properties}
Bar.all.each{println it.properties}
}
}
//Bootstrap Test in Dev mode
new Bar(someOtherValue: 'shibby').save()
new Foo(someValue1:"test", someValue2:"test2",
whatever: "whatever", bar: myBar).save(failOnError: true, flush: true)
Notes
Above I have used your exact simplified code but the hasMany relation in Bar.
Constraints on Baz is optional.
Fixtures works as expected.
Columns are created in Foo as expected.
logSql showed expected DML.
To witness the table changes, I also BootStraped the same test data in dev mode following a run-app. I was able to see the expected table structure with data in it, using dbconsole.
Following the general way of one-to-one bidirectional (mentioned as commented code), FKs are created in the child tables [Bar and Baz], so the explicit mapping you provided in the sample code would not hold good.
The question will be more clear if the owning side of the relationship and the rationale behind having hasMany in Bar is mentioned.
I have a Grails domain called People, and I want to check that each People has childs or not. Childs are other People objects. Here is my domain structure:
class People implements Serializable {
static constraints = {
name (nullable : false, unique : true)
createdBy (nullable : false)
creationDate (nullable : false)
}
static transients = ['hasChild']
static mapping = {
table 'PEOPLE'
id generator: 'sequence', params : [sequence : 'SEQ_PK_ID']
columns {
id column : 'APEOPLE_ID'
parentPeople column : 'PARENT_PEOPLE_ID'
}
parentPeople lazy : false
}
People parentPeople
String name
String description
Boolean hasChild() {
def childPeoples = People.createCriteria().count {
eq ('parentPeople', People)
}
return (childPeoples > 0)
}
}
But I cannot call people.hasChild() at anywhere. Could you please helpe me on this? Thank you so much!
It's because in eq ('parentPeople', People), Grails can't understand what "People" is (it's a class). You should replace "People" by this. For example:
static transients = ["children"]
def getChildren() {
def childPeoples = People.findAllByParentPeople(this, [sort:'id',order:'asc'])
}
Another way to get the same result is to use Named Queries. It seems more concise and was created specifically for this purpose. I also like it because it fits the pattern of static declarations in a domain model and it's essentially a criteria, which I use throughout my applications. Declaring a transient then writing a closure seems a bit of a work-around when you can declare named queries ... just my opinion.
Try something like this:
static namedQueries = {
getChildren {
projections {
count "parentPeople"
}
}
}
in Grails, Is there a way to limit the size of the column to which the enum is mapped. In the following example, i would like the column type to be char(2)
enum FooStatus {
BAR('br'), TAR('tr')
final static String id
}
class Foo {
FooStatus status
static constraints = {
status(inList:FooStatus.values()*.id,size:2..2)
}
}
both inList and size do not have any effect when exporting the schema, the column type keeps its default value (varch(255))
Maybe i could do that if i define a new UserType. Any idea ?
Thank you
-ken
I don't think it's directly possible given the way enums are mapped internally in GORM. But changing the code to this works:
enum FooStatus {
BAR('br'),
TAR('tr')
private FooStatus(String id) { this.id = id }
final String id
static FooStatus byId(String id) {
values().find { it.id == id }
}
}
and
class Foo {
String status
FooStatus getFooStatus() { status ? FooStatus.byId(status) : null }
void setFooStatus(FooStatus fooStatus) { status = fooStatus.id }
static transients = ['fooStatus']
static constraints = {
status inList: FooStatus.values()*.id
}
static mapping = {
status sqlType: 'char(2)'
}
}
Adding the transient getter and setter allows you to set or get either the String (id) or enum value.
Grails ships with an undocumented (as far as I can tell anyway) custom Hibernate mapping for enums. The class is org.codehaus.groovy.grails.orm.hibernate.cfg.IdentityEnumType. It won't let you set the column size but does make it easy to change what is stored in the DB for each enum value without having to add transient fields to your model.
import org.codehaus.groovy.grails.orm.hibernate.cfg.IdentityEnumType
class MyDomainClass {
Status status
static mapping = {
status(type: IdentityEnumType)
}
enum Status {
FOO("F"), BAR("B")
String id
Status(String id) { this.id = id }
}
}
You can run an 'alter table' in Bootstrap.groovy to shrink the column:
DataSource dataSource
...
Sql sql = new Sql(dataSource)
sql.execute("alter table my_domain_class change column status status varchar(1) not null")
Even easier (works at least in Grails 2.1.0+)
class DomainClass {
Status status
static mapping = {
status(enumType: "string")
}
}
enum Status {
OPEN ("OPEN"),
CLOSED ("CLOSED"),
...
String name
Status (String name) {
this.name = name
}
}
Since GORM 6.1 identity enum mapping can be enabled with such construct
static mapping = {
myEnum enumType:"identity"
}