Grails: legacy database: foreign key that has not the same type in each mapped table - grails

So I have a grails model looking like this:
class Tree {
Long id;
String name;
static hasMany = [branches: Branch
}
class Branch {
Long id;
String name;
static belongsTo = [tree: Tree]
}
The issue is that in DB, the Tree id is a number, while the tree_id in the Branch table is a varchar.
The db model is a de facto foreign key that is not enforced at all as a constraint.
Gorm generate a query that is not handled by my database: it tries to bing a numerical value where text is expected:
ERROR util.JDBCExceptionReporter - ORA-01722: invalid number
How can I tell GORM to convert the value before binding the parameter ?
I looked in the join table config but I did not find anything relevant.

Have you tried using sqlType in column definition in mappings?
class Branch {
Long id
String name
static belongsTo = [tree: Tree]
static mapping = {
tree column: 'TREE_ID', sqlType: "char"
}
}
Unable to test right now, but do let me know.

Related

SpringData Cassandra Java Adapter - Using UDTs in Map Columns

I am using the 1.5.1 version of the Cassandra adapter for Java, and I am attempting to insert a record to a table having a Map column that uses a UDT as the column value (key is just a varchar). I created the table using cqlsh and am able to insert to it in CQL just fine. When i try to use a CassandraTemplate...insert(), though, all I get is:
UserTypeResolver must not be null
My UDT class is defined as:
#UserDefinedType("iss_type")
public class IssueType {
#CassandraType(type = DataType.Name.VARCHAR)
private String issue_code;
#CassandraType(type = DataType.Name.VARCHAR)
private String issue_name;
#CassandraType(type = DataType.Name.TIMESTAMP)
private Date issue_start;
#CassandraType(type = DataType.Name.TIMESTAMP)
private Date issue_end;
And my table is defined as
#Table
public class IssueMap {
#PrimaryKeyColumn(
type = PrimaryKeyType.PARTITIONED)
private UUID map_id;
#Column
private Map<String, IssueType> issue_map;
In my config, i have:
#Bean
public CassandraMappingContext cassandraMapping()
throws ClassNotFoundException {
BasicCassandraMappingContext mappingContext = new BasicCassandraMappingContext();
mappingContext.setUserTypeResolver(new SimpleUserTypeResolver(cluster().getObject(),"campaign_management"));
return mappingContext;
}
Is there something I am missing here? Or is it just not possible to define columns this way? I realize I could just use a query builder to create the CQL and do the insert, but I was hoping to be able to make full use of the Cassandra template features.

Employee not found with id null grails

Can someone help me with my situation. I have the following code.
class Employee {
Integer empId
String firstName
String lastName
static constraints = {
empId()
firstName()
lastName()
}
static mapping = {
id generator:'assigned', name:'empId'
version false
}
}
The code allows me to save employee through 'create' but gives the following error message
"Employee not found with id null" and also in the list, all the employees are listed but clicking on any Emp Id gives the same error. Please help. This is driving me nuts.
Rocky
Thanks for your reply. Like I mentioned I am able to save the empId in the database but get that message nonetheless and see the list with assigned ids (empId). The link points to employee/show with no number at end. However employee/show/22(empId) works fine. employee/edit/22 works too but update does not work.
I am not using any assigned sequence. Just some random integer. Maybe a better example would be to use SSN instead of empId.
Thank you once again.
You are a great help buddy. Appreciate your time and patience. I am not writing any special update or save (I am too new to dig too deep). Just using grails to generate-all. However, I did find a workaround. I changed the domain class to add variable id (Long) and added empId setter method to allocate the empId value to id. That did it. Here is my code.
class Employee {
Long id
Long empId
String firstName
String lastName
static constraints = {
empId()
firstName()
lastName()
}
static mapping = {
id generator:'assigned', name:'empId', column: 'emp_id'
version false
}
public void setEmpId(Long empId){
this.empId = empId
this.id = empId
}
}
Please feel free to suggest if you have a better way of doing that.
Regards
Rocky
If you are using the "assigned" sequence, then you have to assign the objects ids yourself before saving them. Otherwise your objects will be saved with a null or 'default 0' id. If you want GORM to assign an id for you, you need to use another type of generator, like "sequence" generator. It would be like:
id name: 'customId', generator: 'sequence', params: [sequence:'some_sequence']
More info on id generators here.

Mapping exception when using discriminator in Grails 2.0.0

At general I have problem with mapping: org.hibernate.MappingException: Repeated column in mapping for entity: os.comida.StoreDocumentRw column: Type (should be mapped with insert="false" update="false")
To introduce the problem: I have many document types where each document type differs just a little bit from any other. All of them have common properties: date, number, issuer etc. So I decided store all document types in one physical table (one - it's very important for me). To implement this I wanted use hibernate discriminator.
Below I'm pasting my source code. I have there a base class StoreDocument and two document types StoreDocumentRw and StoreDocumentWz.
class StoreDocument {
String type
Date documentDate
static mapping = {
table '"StoreDocument"'
version false
id column:'"StoreDocumentID"', generator:'sequence', params:[sequence:'STORE_DOCUMENT_SEQ']
discriminator column: '"Type"'
documentDate column:'"DocumentDate"'
type column:'"Type"'
}
}
class StoreDocumentRw extends StoreDocument {
String rwSpecificData
static mapping = {
discriminator value: 'rw'
rwSpecificData column:'"RwSpecificData"'
}
}
class StoreDocumentWz extends StoreDocument {
String wzSpecificData
static mapping = {
discriminator value: 'wz'
wzSpecificData column:'"WzSpecificData"'
}
}
And when I'm trying run an app I get mentioned earlier org.hibernate.MappingException: Repeated column in mapping for entity: os.comida.StoreDocumentRw column: Type (should be mapped with insert="false" update="false")
When I add type insertable: false, updateable: false to StoreDocumentRw mapping, it's still the same.
When I add type insertable: false, updateable: false to StoreDocument mapping, it's even worse:
ERROR hbm2ddl.SchemaExport - Unsuccessful: create table COMIDA2."StoreDocument" ("StoreDocumentID" number(19,0) not null, "DocumentDate" timestamp not null, "Type" varchar2(255 char), "Type" varchar2(-1 char) not null, "WzSpecificData" varchar2(255 char), "RwSpecificData" varchar2(255 char), primary key ("StoreDocumentID"))
ERROR hbm2ddl.SchemaExport - ORA-00957: duplicate column name
So I don't know where I should put this insertable/updateable thing to make it working. I'm using Grails 2.0.0 and Oracle 10g. Can anybody tell me what's wrong with my code?
Solution:
My mapping in StoreDocument was wrong. It's enough to cut String type and type column:'"Type"' and edit discriminator mapping like this discriminator column:[name:'"Type"',length:50], which in result gives:
class StoreDocument {
Date documentDate
static mapping = {
table '"StoreDocument"'
version false
id column:'"StoreDocumentID"', generator:'sequence', params:[sequence:'STORE_DOCUMENT_SEQ']
discriminator column:[name:'"Type"',length:50]
documentDate column:'"DocumentDate"'
}
}
In StoreDocument you have String type and discriminator column: '"Type"', so from your exceptions it looks like Grails is trying to create two columns of name type. Try changing the name of your String or discriminator-column and see if that corrects the issue.
To get around the issue with generating a varchar(-1) field try this: discriminator column:[name:'Type',length:10] from this JIRA GRAILS-5168. Of course, change the length to whatever you need.

my own id in GORM

I tried to change the standard 'id' in grails:
calls Book {
String id
String title
static mapping {
id generator:'assigned'
}
}
unfortunately, I soon noticed that this breaks my bootstrap. Instead of
new Book (id:'some ISBN', title:'great book').save(flush:true, failOnError:true)
I had to use
def b = new Book(title:'great book')
b.id = 'some ISBN'
b.save(flush:true, failOnError:true)
otherwise I get an 'ids for this class must be manually assigned before calling save()' error.
but that's ok so far.
I then encountered the same problem in the save action of my bookController. But this time, the workaround didn't do the trick.
Any suggestions?
I known, I can rename the id, but then I will have to change all scaffolded views...
That's a feature of databinding. You don't want submitted data to be able to change managed fields like id and version, so the Map constructor that you're using binds all available properties except those two (it also ignores any value for class, metaClass, and a few others).
So there's a bit of a mismatch here since the value isn't managed by Hibernate/GORM but by you. As you saw the workaround is that you need to create the object in two steps instead of just one.
I can't replicate this problem (used Grails 2.0.RC1). I think it might be as simple as a missing equal sign on your static mapping = { (you just have static mapping {)
Here's the code for a domain object:
class Book {
String id
String name
static mapping = {
id generator:'assigned'
}
}
And inside BootStrap.groovy:
def init = { servletContext ->
new Book(name:"test",id:"123abc").save(failOnError:true)
}
And it works fine for me. I see the id as 123abc.
You need to set the bindable constraint to true for your id prop, e.g.
class Employee {
Long id
String name
static constraints = {
id bindable: true
}
}

Grails GORM MissingMethodException with 1:N relationship

I have such domain classes:
class ServicesGroup {
Long id
String name
String description
String toString(){
return name
}
static mapping = {
version false
table 'root.services_groups'
id column:'group_id'
name column:'group_name'
description column:'group_desc'
}
}
and
class Step {
Long id
ServicesGroup service
String stepType
Integer stepFrom
Integer stepTo
static constraints = {
stepType(inList:['operator', 'client'])
}
static mapping = {
version false
table 'bill.steps'
service column:'service_group_id'
}
}
The relationship is - one ServicesGroup entry can have multiple Step instances.
However, when in my controller I try to
Step.findByService(3)
I get:
"org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingMethodException: No signature of method: Step.findByService() is applicable for argument types: (java.lang.Integer) values: {3}"
However, when I change Step domain class field
ServicesGroup service
to simply
Long service
it works.
What's going on here?
Try it that way:
Step.findByService(ServicesGroup.get(3))
Try
grails clean
grails run-app
Then try again.
Something like Step.findByService([id: 3]) may work. It only cares about the ID anyway for the purposes of the SQL generation. In a lot of cases like this you can toss a fake map into there rather than the real thing, and save yourself some performance.
On the other hand, the abstraction breaks down a bit when you do this.

Resources