Fornax-Platform
Forum

[Sculptor] how to control surrogate key name

View: New views
10 Messages — Rating Filter:   Alert me  

[Sculptor] how to control surrogate key name

by rsmith :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I have a couple questions regarding Hibernate/DDL generation in Sculptor.

Is there a way I can specify what the name of the surrogate key column should be?
I have to follow a standard where the name would be <table name>_ID.  e.g. ADDRESS_ID instead of ID.  Can I do this with Sculptor?

Also, is there a way to not have a surrogate key for some tables, and use a business key instead?  I know this isn't the recommended approach, but I have a couple exception cases where I'd like to do this.

Thanks for Sculptor
Ron

Re: [Sculptor] how to control surrogate key name

by Patrik Nordwall :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Your first question:
rsmith wrote:
Is there a way I can specify what the name of the surrogate key column should be?
I have to follow a standard where the name would be <table name>_ID.  e.g. ADDRESS_ID instead of ID.  Can I do this with Sculptor?
It is possible to do this using the excellent AOP facilitates of oAW. Do like this:
1. Add an extension advice file in your target project,
location: src/main/resources/extensions/SpecialCases.ext
content:
import sculptormetamodel;

extension extensions::helper;
extension extensions::dbhelper;

around transformation::Transformation::modifyDatabaseNames(DomainObject domainObject) :
    ctx.proceed() ->
    domainObject.getIdAttribute().setDatabaseColumn(domainObject.getDatabaseName() + "_ID");

2. In workflow.oaw in your target project you need to add the following:
        <component adviceTarget="modelTransformation"
                        class="oaw.xtend.XtendAdvice">
                <extensionAdvice
                        value="extensions::SpecialCases" />
        </component>


That's all! However, I found a bug in the DDL generation. It uses a hardcoded ID in the foreign key constraints (CSC-224). I have fixed this, but it is not deployed yet.

I will look at your second question later.

/Patrik

Re: [Sculptor] how to control surrogate key name

by amphoras :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Wow, that is so cool.  I had no idea you can use AOP on the transformations.  I also didn't know that this file is what adds a lot of properties to my model.  Looks like I need to clean up some of my hacks elsewhere.  ;)

--Polly


Patrik Nordwall wrote:
Your first question:
rsmith wrote:
Is there a way I can specify what the name of the surrogate key column should be?
I have to follow a standard where the name would be <table name>_ID.  e.g. ADDRESS_ID instead of ID.  Can I do this with Sculptor?
It is possible to do this using the excellent AOP facilitates of oAW. Do like this:
1. Add an extension advice file in your target project,
location: src/main/resources/extensions/SpecialCases.ext
content:
import sculptormetamodel;

extension extensions::helper;
extension extensions::dbhelper;

around transformation::Transformation::modifyDatabaseNames(DomainObject domainObject) :
    ctx.proceed() ->
    domainObject.getIdAttribute().setDatabaseColumn(domainObject.getDatabaseName() + "_ID");

2. In workflow.oaw in your target project you need to add the following:
        <component adviceTarget="modelTransformation"
                        class="oaw.xtend.XtendAdvice">
                <extensionAdvice
                        value="extensions::SpecialCases" />
        </component>


That's all! However, I found a bug in the DDL generation. It uses a hardcoded ID in the foreign key constraints (CSC-224). I have fixed this, but it is not deployed yet.

I will look at your second question later.

/Patrik

Re: [Sculptor] how to control surrogate key name

by Patrik Nordwall :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Your second question
rsmith wrote:
Also, is there a way to not have a surrogate key for some tables, and use a business key instead?  I know this isn't the recommended approach, but I have a couple exception cases where I'd like to do this.
Sculptor adds id to all persistent DomainObjects and assumes in the generation phase that an id attribute exists. I think it is tricky to support your request in a general manner, foreign keys etc, but if you have a specific exception it might be possible, but that depends on what you need.

Starting point...

1. Skip id attribute in the transformation for some DomainObjects. Use AOP as I described for the first question.

around transformation::Transformation::modifyIdAttribute(DomainObject domainObject) :
    if domainObject.name != "NoIdEntity" then ctx.proceed();

2. Adjust generation templates. Use AOP, add AROUND advices in src/main/resources/templates/SpecialCases.xpt in your target project.

«AROUND templates::Hibernate::id FOR DomainObject»
    «IF getIdAttribute() == null -»
      <id />
    «ELSE -»
      «targetDef.proceed() »
    «ENDIF -»
«ENDAROUND»

Let me know if you need some adjustments to Sculptor to support your case.

/Patrik

Re: [Sculptor] how to control surrogate key name

by rsmith :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks, I used the latest 1.5.0 snapshot code and it works great.

I'm getting up to speed on oAW/Sculptor, and had a couple more things I was trying to find how to do:

- The foreign key reference columns are named based on the referred-to table (e.g. ADDRESS).  Can I customize this to be the same column name as the primary key of the referred-to table (ADDRESS_ID in my example).
- Is there a way I can customize the names of the CREATEDDATE, CREATEDBY, etc column names?
- For entities that don't have a business key (such as address), Sculptor generates the UUID column/attribute.  Is there a way I can name this <table name>_ID instead of UUID.  For entities with a business key, the below works great.


Thanks again
--Ron


Patrik Nordwall wrote:
Your first question:
rsmith wrote:
Is there a way I can specify what the name of the surrogate key column should be?
I have to follow a standard where the name would be <table name>_ID.  e.g. ADDRESS_ID instead of ID.  Can I do this with Sculptor?
It is possible to do this using the excellent AOP facilitates of oAW. Do like this:
1. Add an extension advice file in your target project,
location: src/main/resources/extensions/SpecialCases.ext
content:
import sculptormetamodel;

extension extensions::helper;
extension extensions::dbhelper;

around transformation::Transformation::modifyDatabaseNames(DomainObject domainObject) :
    ctx.proceed() ->
    domainObject.getIdAttribute().setDatabaseColumn(domainObject.getDatabaseName() + "_ID");

2. In workflow.oaw in your target project you need to add the following:
        <component adviceTarget="modelTransformation"
                        class="oaw.xtend.XtendAdvice">
                <extensionAdvice
                        value="extensions::SpecialCases" />
        </component>


That's all! However, I found a bug in the DDL generation. It uses a hardcoded ID in the foreign key constraints (CSC-224). I have fixed this, but it is not deployed yet.

I will look at your second question later.

/Patrik

Re: [Sculptor] how to control surrogate key name

by Patrik Nordwall :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

rsmith wrote:
- The foreign key reference columns are named based on the referred-to table (e.g. ADDRESS).  Can I customize this to be the same column name as the primary key of the referred-to table (ADDRESS_ID in my example).
I don't think it is named based on the referred-to table, it is named based on the name of the reference. Otherwise it would not be possible to have several references to the same target DomainObject. Try this:

Entity Person {
  - String name
  - @Address primaryAddress
  - @Address secondaryAddress
}

ValueObject Address {
  String street;
}

However, it is possible to specify the name of the database columns, as described here: http://www.fornax-platform.org/cp/display/fornax/3.+Advanced+Tutorial+%28CSC%29#3.AdvancedTutorial%28CSC%29-DatabaseNames

rsmith wrote:
- Is there a way I can customize the names of the CREATEDDATE, CREATEDBY, etc column names?
These attributes are added on the fly by the Transformation. You can replace that transformation by using an around of the transformation extension as described earlier.

It is the the extension named addAuditable that you need to replace. I think I have read somewhere that it is not possible to intercept JAVA extensions and if that is a problem you can intercept the extension named modifyAuditable instead. See Transformation.ext.
You have to invoke your own Java helper class and do something similar to GenerationHelper.addAuditable, but set the databaseColumn of the attributes.
createdBy.setDatabaseColumn("myCreatedDate");

If you need to change the names of the Java attributes for these it is the same first step, but you also have to replace AuditInterceptor and specify the gui.systemAttributes generator property.
In your sculptor-generator.properties:

framework.auditInterceptorClass=org.foo.bar.MyAuditInterceptor
gui.systemAttributes=id,uuid,version,myCreatedBy,myCreatedDate,myUpdatedBy,myLastUpdated,myLastUpdatedBy

rsmith wrote:
- For entities that don't have a business key (such as address), Sculptor generates the UUID column/attribute.  Is there a way I can name this <table name>_ID instead of UUID.  For entities with a business key, the below works great.
Aren't you using <table name>_ID for the surrogate id (id attribute)? UUID is not the same as ID.
The uuid attribute is also added by Transformation.ext. It should be possible for you to replace that in the same way as described above. addUuidAttribute or modifyUuid in Transformation.ext.


Re: [Sculptor] how to control surrogate key name

by rsmith :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Patrik Nordwall wrote:
However, it is possible to specify the name of the database columns, as described here: http://www.fornax-platform.org/cp/display/fornax/3.+Advanced+Tutorial+%28CSC%29#3.AdvancedTutorial%28CSC%29-DatabaseNames
For the foreign key reference column name, I didn't realize you could assign those column names.  Worked like a charm.

Patrik Nordwall wrote:
rsmith wrote:
- Is there a way I can customize the names of the CREATEDDATE, CREATEDBY, etc column names?
These attributes are added on the fly by the Transformation. You can replace that transformation by using an around of the transformation extension as described earlier.

It is the the extension named addAuditable that you need to replace. I think I have read somewhere that it is not possible to intercept JAVA extensions and if that is a problem you can intercept the extension named modifyAuditable instead. See Transformation.ext.
You have to invoke your own Java helper class and do something similar to GenerationHelper.addAuditable, but set the databaseColumn of the attributes.
createdBy.setDatabaseColumn("myCreatedDate");
To customize the auditable columns, I added the following to my SpecialCases.ext:
Entity myAddAuditable(Entity entity) :
    addAuditable(entity) ->
    entity.attributes.select(a | a.name == 'createdBy').setDatabaseColumn('CREATED_BY') ->
    entity.attributes.select(a | a.name == 'lastUpdated').setDatabaseColumn('LAST_UPDATED_DATE') ->
    entity.attributes.select(a | a.name == 'lastUpdatedBy').setDatabaseColumn('LAST_UPDATED_BY') ->
    entity.attributes.select(a | a.name == 'createdDate').setDatabaseColumn('CREATED_DATE');

Entity addAuditable(Entity entity) :
    JAVA org.fornax.cartridges.sculptor.generator.util.GenerationHelper.addAuditable(sculptormetamodel.Entity);


Patrik Nordwall wrote:
rsmith wrote:
- For entities that don't have a business key (such as address), Sculptor generates the UUID column/attribute.  Is there a way I can name this <table name>_ID instead of UUID.  For entities with a business key, the below works great.
Aren't you using <table name>_ID for the surrogate id (id attribute)? UUID is not the same as ID.
The uuid attribute is also added by Transformation.ext. It should be possible for you to replace that in the same way as described above. addUuidAttribute or modifyUuid in Transformation.ext.
As far as the UUID attribute, I guess what I really want to do is get rid of the natural key altogether and just use the surrogate key for this particular table.
I tried overriding the modifyUuid extension to not generate the UUID attribute at all via:
modifyUuid(DomainObject domainObject) :
    null;

But the UUID attribute was still generated for some reason.  For now I'm keeping a natural key in this table although I don't really need it.


I ran into something else which I want to check whether is a bug or working as intended...  I have a persistent entity class A which has a collection of non-persistent value objects B.  Class B has a reference to Class C, which IS persistent.
The hibernate mapping and table for B are not generated (good), but the hibernate mapping for class A has a reference to class B, which causes an error because class B isn't a persistent entity.
I didn't see a way to specify the reference from A to B should be non-persistent.  Am I missing something?
Ex:
Entity A {
                        - Set<@B> bs
}

ValueObject B {
        not persistent
       
        - @C c
}

Entity C {
}

Re: [Sculptor] how to control surrogate key name

by Patrik Nordwall :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

rsmith wrote:
As far as the UUID attribute, I guess what I really want to do is get rid of the natural key altogether and just use the surrogate key for this particular table.
I tried overriding the modifyUuid extension to not generate the UUID attribute at all via:
modifyUuid(DomainObject domainObject) :
    null;

But the UUID attribute was still generated for some reason.  For now I'm keeping a natural key in this table although I don't really need it.
Strange. As far as I can see it should not be generated if you skipped it in the transformation. I have changed things in this area recently to support multi levels of subclasses. Are you using latest trunk?

rsmith wrote:
I ran into something else which I want to check whether is a bug or working as intended...  I have a persistent entity class A which has a collection of non-persistent value objects B.  Class B has a reference to Class C, which IS persistent.
The hibernate mapping and table for B are not generated (good), but the hibernate mapping for class A has a reference to class B, which causes an error because class B isn't a persistent entity.
I didn't see a way to specify the reference from A to B should be non-persistent.  Am I missing something?
Ex:
Entity A {
                        - Set<@B> bs
}

ValueObject B {
        not persistent
       
        - @C c
}

Entity C {
}
Good observation. It is a bug. I have fixed it in trunk. I will add a jira for the record also, but right now the server is down.

/Patrik

Re: [Sculptor] how to control surrogate key name

by rsmith :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Patrik Nordwall wrote:
rsmith wrote:
As far as the UUID attribute, I guess what I really want to do is get rid of the natural key altogether and just use the surrogate key for this particular table.
I tried overriding the modifyUuid extension to not generate the UUID attribute at all via:
modifyUuid(DomainObject domainObject) :
    null;

But the UUID attribute was still generated for some reason.  For now I'm keeping a natural key in this table although I don't really need it.
Strange. As far as I can see it should not be generated if you skipped it in the transformation. I have changed things in this area recently to support multi levels of subclasses. Are you using latest trunk?
Works now..  I updated to the latest code, but think I may have been setting up my aspect wrong anyways.  For anyone else needing to do the same, following is the code:

around transformation::Transformation::modifyUuid(DomainObject domainObject) :
        myModifyUuid(domainObject);

// Don't automatically add UUID natural key attribute    
myModifyUuid(DomainObject domainObject) :
        null;

Is there somewhere we can document these types of recipes?  The Wiki?


Re: [Sculptor] how to control surrogate key name

by Patrik Nordwall :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Good. Developer's Guide is the place to document these kind of things. I have added a section about this now: http://fornax-platform.org/cp/display/fornax/7.+Developer%27s+Guide+%28CSC%29#7.Developer%27sGuide%28CSC%29-CustomizetheTransformations

I don't think you need myModifyUuid. I think you can return null instead. Correct?

/Patrik

rsmith wrote:
Patrik Nordwall wrote:
rsmith wrote:
As far as the UUID attribute, I guess what I really want to do is get rid of the natural key altogether and just use the surrogate key for this particular table.
I tried overriding the modifyUuid extension to not generate the UUID attribute at all via:
modifyUuid(DomainObject domainObject) :
    null;

But the UUID attribute was still generated for some reason.  For now I'm keeping a natural key in this table although I don't really need it.
Strange. As far as I can see it should not be generated if you skipped it in the transformation. I have changed things in this area recently to support multi levels of subclasses. Are you using latest trunk?
Works now..  I updated to the latest code, but think I may have been setting up my aspect wrong anyways.  For anyone else needing to do the same, following is the code:

around transformation::Transformation::modifyUuid(DomainObject domainObject) :
        myModifyUuid(domainObject);

// Don't automatically add UUID natural key attribute    
myModifyUuid(DomainObject domainObject) :
        null;

Is there somewhere we can document these types of recipes?  The Wiki?
LightInTheBox - Buy quality products at wholesale price