留言板

ServiceBuilder -- mapping relationship one-to-many

thumbnail
Ivano Carrara,修改在12 年前。

ServiceBuilder -- mapping relationship one-to-many

Expert 帖子: 345 加入日期: 05-7-3 最近的帖子
Hi all,

There is a long term question in Liferay's forum and other support site (for example in Java Ranch) without some sort of definitive reply , expecially from Liferay team: How to use one-to-may-relationship in ServiceBuilder ?

Jignesh Gohel posted the problem in a very clear manner with this thread in JavaRanch: http://www.coderanch.com/t/518965/Portals-Portlets/java/Liferay-EE-ServiceBuilder-mapping-relationship#2421704

Liferay Portal EE 6.0.5 + MySQL

How to map one-to-many or many-to-one relationship between entities in service.xml ?

I am building a Portlet using the Liferay Plugins SDK.

I am need to map a foreign key relationship between database table LAYOUT(default created by Liferay) and a new table I want to create (P_VERSION)

P_VERSION table would be holding a column "plid" which would refer to "plid" column of LAYOUT table.

Following is my service.xml


   1. <!--?xml version="1.0" encoding="UTF-8"?-->  
   2.   
   3.   
   4. <service-builder package-path="com.sample.page">  
   5.     <namespace>SampleNS</namespace>  
   6.     <entity name="PVersion" uuid="true" local-service="true" remote-service="true">  
   7.           
   8.         <!-- PK fields -->  
   9.   
  10.         <column name="id" type="long" primary="true" />  
  11.           
  12.         <!-- Group instance -->  
  13.   
  14.         <column name="groupId" type="long" />  
  15.           
  16.         <!-- Audit fields -->  
  17.   
  18.         <column name="companyId" type="long" />  
  19.         <column name="userId" type="long" />  
  20.         <column name="createDate" type="Date" />  
  21.         <column name="modifiedDate" type="Date" />  
  22.           
  23.         <!-- Other fields -->  
  24.           
  25.         <column name="sampleId" type="long" />  
  26.         <column name="version" type="double" />  
  27.           
  28.           
  29.         <!-- Relationships -->  
  30.           
  31.         <column name="plid" type="Collection" entity="com.liferay.portal.Layout" mapping-key="plid" />   
  32.           
  33.         <!-- Order -->  
  34.           
  35.         <order>  
  36.             <order-column name="sampleId" order-by="asc" />  
  37.             <order-column name="version" order-by="desc" />  
  38.         </order>  
  39.           
  40.         <!-- Finder methods -->  
  41.           
  42.         .....  
  43.         ....  
  44.           
  45.         <!-- References -->  
  46.         ....  
  47.                ....  
  48.   
  49.     </entity>  
  50.   
  51. </service-builder>  




posted mercoledì 1 dicembre 2010 16.01.13 private message
0
Quote
Liferay Portal EE 6.0.5 + MySQL

How to map one-to-many or many-to-one relationship between entities in service.xml ?

I am building a Portlet using the Liferay Plugins SDK.

I am need to map a foreign key relationship between database table LAYOUT(default created by Liferay) and a new table I want to create (P_VERSION)

P_VERSION table would be holding a column "plid" which would refer to "plid" column of LAYOUT table.



Following is my service.xml

1. <?xml version="1.0" encoding="UTF-8"?>
2. <!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.0.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_0_0.dtd">
3.
4. <service-builder package-path="com.sample.page">
5. <namespace>SampleNS</namespace>
6. <entity name="PVersion" uuid="true" local-service="true" remote-service="true">
7.
8. <!-- PK fields -->
9.
10. <column name="id" type="long" primary="true" />
11.
12. <!-- Group instance -->
13.
14. <column name="groupId" type="long" />
15.
16. <!-- Audit fields -->
17.
18. <column name="companyId" type="long" />
19. <column name="userId" type="long" />
20. <column name="createDate" type="Date" />
21. <column name="modifiedDate" type="Date" />
22.
23. <!-- Other fields -->
24.
25. <column name="sampleId" type="long" />
26. <column name="version" type="double" />
27.
28.
29. <!-- Relationships -->
30.
31. <column name="plid" type="Collection" entity="com.liferay.portal.Layout" mapping-key="plid"/>
32.
33. <!-- Order -->
34.
35. <order>
36. <order-column name="sampleId" order-by="asc" />
37. <order-column name="version" order-by="desc" />
38. </order>
39.
40. <!-- Finder methods -->
41.
42. .....
43. ....
44.
45. <!-- References -->
46. ....
47. ....
48.
49. </entity>
50.
51. </service-builder>

Now when I run ant "build-service" target the build is successful and the appropriate classes gets generated without any error.

But having a look at docroot/WEB-INF/sql/tables.sql

following can be seen


   1. create table SampleNS_PVersion (  
   2.     uuid_ VARCHAR(75) null,  
   3.     id_ LONG not null primary key,  
   4.     groupId LONG,  
   5.     companyId LONG,  
   6.     userId LONG,  
   7.     createDate DATE null,  
   8.     modifiedDate DATE null,  
   9.     sampleId LONG,  
  10.     version DOUBLE  
  11. );  




posted mercoledì 1 dicembre 2010 16.01.13 private message
0
Quote
Liferay Portal EE 6.0.5 + MySQL

How to map one-to-many or many-to-one relationship between entities in service.xml ?

I am building a Portlet using the Liferay Plugins SDK.

I am need to map a foreign key relationship between database table LAYOUT(default created by Liferay) and a new table I want to create (P_VERSION)

P_VERSION table would be holding a column "plid" which would refer to "plid" column of LAYOUT table.



Following is my service.xml

view plaincopy to clipboardprint?

1. <?xml version="1.0" encoding="UTF-8"?>
2. <!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.0.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_0_0.dtd">
3.
4. <service-builder package-path="com.sample.page">
5. <namespace>SampleNS</namespace>
6. <entity name="PVersion" uuid="true" local-service="true" remote-service="true">
7.
8. <!-- PK fields -->
9.
10. <column name="id" type="long" primary="true" />
11.
12. <!-- Group instance -->
13.
14. <column name="groupId" type="long" />
15.
16. <!-- Audit fields -->
17.
18. <column name="companyId" type="long" />
19. <column name="userId" type="long" />
20. <column name="createDate" type="Date" />
21. <column name="modifiedDate" type="Date" />
22.
23. <!-- Other fields -->
24.
25. <column name="sampleId" type="long" />
26. <column name="version" type="double" />
27.
28.
29. <!-- Relationships -->
30.
31. <column name="plid" type="Collection" entity="com.liferay.portal.Layout" mapping-key="plid"/>
32.
33. <!-- Order -->
34.
35. <order>
36. <order-column name="sampleId" order-by="asc" />
37. <order-column name="version" order-by="desc" />
38. </order>
39.
40. <!-- Finder methods -->
41.
42. .....
43. ....
44.
45. <!-- References -->
46. ....
47. ....
48.
49. </entity>
50.
51. </service-builder>


Now when I run ant "build-service" target the build is successful and the appropriate classes gets generated without any error.

But having a look at docroot/WEB-INF/sql/tables.sql

following can be seen

view plaincopy to clipboardprint?

1. create table SampleNS_PVersion (
2. uuid_ VARCHAR(75) null,
3. id_ LONG not null primary key,
4. groupId LONG,
5. companyId LONG,
6. userId LONG,
7. createDate DATE null,
8. modifiedDate DATE null,
9. sampleId LONG,
10. version DOUBLE
11. );

create table SampleNS_PVersion ( uuid_ VARCHAR(75) null, id_ LONG not null primary key, groupId LONG, companyId LONG, userId LONG, createDate DATE null, modifiedDate DATE null, sampleId LONG, version DOUBLE );

And in docroot/WEB-INF/service/com/sample/page/service/persistence/PVersionUtil.java I can see the generated method

com.sample.page.service.persistence.PVersionUtil.getLayouts(long)

Questions:

a) I cannot find a setterXXX for associating an existing com.liferay.portal.Layout with my custom entity com.sample.page.PVersion.
I suppose there should be some configuration that should be added to the com.liferay.portal.Layout for making my mapping work.
But com.liferay.portal.Layout is an existing entity configured in <LIFERAY_PORTAL_ROOT>/portal-impl/src/com/liferay/portal/service.xml.
And it is available in my classpath so I cannot modify it.
So how to achieve the above mentioned configuration, in case my assumption is correct? If my assumption is wrong, then please
guide me with the correct approach for achieving my desired requirement as mentioned above.

b) I cannot see any column named "plid" in CREATE STATEMENT in tables.sql shown above.Any specific reason in not including a foreign key constraint in the create clause? If it is not appended in the CREATE clause then how this constraint gets applied?


After a long exploration in Liferay's forums and blogs, DTDs, etc.etc. I asked to Jignesh Gohel if they got a reply, obtaining the below comment:

With all the explorings done till date with Liferay what I think is it is a limitation in Liferay' Service Builder framework to define relationships between
user-defined custom entities and Liferay Portal's entities.

Of course, the relationships can be defined between user-defined custom entities in a given service.xml and it would generate the proper code.

http://www.liferay.com/community/forums/-/message_boards/message/1061266

However, what I have found is that though Liferay uses ORM framework (Hibernate) underneath its Persistent mechanism, the relationships and constraints
are not managed in the way it gets managed when using Hibernate itself at the Persistent layer.For instance on deleting a related entity
Liferay doesn't complain that there is an associated record in the related table, please delete that first.Above all looking at the Liferay's
Portal's implemented source code though they define a relationship between tables but sets the foreign key manually in the entity i.e. for instance,

a) EntityA and EntityB are related.
b) EntityB holds the primary key of EntityA as its foriegn key
c) What Liferay implementation does is it sets the foreign key manually which is contrary to the way relationships are managed when using Hibernate directly.


I may be wrong on my above findings but above is what I have observed while implementing portlets using Liferay and thought it would be good to share and
get comments from experts and others who are working on application involving Liferay.If I am wrong that somebody shall correct me and if I am correct then it might help somebody.


The above is a clear discussion on the problem. I think this is an important question for all developers, so I hope someone from Liferay can comments on the thread...

Thank you in advance !

Ivano C.
Rana Datra,修改在12 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

New Member 帖子: 5 加入日期: 11-9-29 最近的帖子
*push*

I have the same problem:

This is my service.xml:

<service-builder package-path="my.path">
<author>me</author>
<namespace>AssociateService</namespace>

<entity name="Associate" local-service="true" remote-service="false">

<column name="associateId" type="long" primary="true" />

<column name="type" type="String" />
<column name="company" type="String" />
<column name="phone" type="String" />
<column name="fax" type="String" />

<column name="addInfos" type="Collection" entity="AddInfos" mapping-key="associateId" />

<finder name="company" return-type="Collection">
<finder-column name="company" />
</finder>
</entity>

<entity name="AddInfos" local-service="true" remote-service="false">
<column name="addInfosId" type="long" primary="true" />

<column name="associateId" type="long" />

<column name="street" type="String" />
<column name="plc" type="String" />

</entity>

</service-builder>

But I cannot find any results by defining this line: "<column name="addInfos" type="Collection" entity="AddInfos" mapping-key="associateId" />"

There are no setters or getters or attributes in the Associate-Classes or at least errors or warnings. The line is completely ignored.

What are we doing wrong?

And by the way: the german translation of this forum is confusing. Sentences like: "Wenn dieses überprüft wird, dann werden Sie zu diesem Gewinde unterzeichnet" don't make sense.
Andreas Tasoulas,修改在12 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

New Member 帖子: 4 加入日期: 09-8-5 最近的帖子
+1 from me having the same problem. No getters or setters are generated and the line is completely ignored
Andreas Tasoulas,修改在12 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

New Member 帖子: 4 加入日期: 09-8-5 最近的帖子
Problem kind of solved for me (or there wasn't a problem at all, in the first place!). I was expecting the getters and setters in model class, while the ones being updated were the persistence and util classes. I hadn't noticed that in the first place, and with the subsequent experiments, naturally no files were updated. Only after removing and bringing back the one-to-many relationship and building the services in between, there was an update in the files and that time I was more attentive with the logs.
Ryan Griffith,修改在12 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

New Member 帖子: 4 加入日期: 12-2-22 最近的帖子
Hope someone is still out there.

I seem to be running into the same issue with the latest IDE/SDK, where my persistence and util classes are updating upon building the service, but not the model. Can someone explain in a little more detail how to "force refresh" the files (i.e. model) so the setters and getters are available. I'm assuming this will also update the tables, correct? I noticed the column doesn't exist either when the service is built.

Thanks in advance!
thumbnail
David H Nebinger,修改在12 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

Liferay Legend 帖子: 14914 加入日期: 06-9-2 最近的帖子
Well, to force refresh delete the code in the service folder, the jar file in the lib folder, and the generated source in the src folder and re-run service builder.

You are incorrect about the tables being updated, service builder will not do that nor will the deployed artifact update the tables either. This is a process you must manually implement. You might model your implementation after the various classes in com.liferay.portal.upgrade package. Liferay keeps a version number in the database to identify which version of Liferay the database is from, and when a newer version of Liferay starts it sees the difference in the version and invokes the upgrade process.
gavin lau,修改在3 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

New Member 帖子: 5 加入日期: 11-8-3 最近的帖子
emoticonI think you're missing the main point of service builder. I think it's because Brian Chan hasn't explained it too well yet.

Developers are mistaking service builder as a tool to generating database entities. Service builder as the name implies is used to generate "service". "Service" here implies interfaces. "Entities" in service.xml are entities in interface definition.

Service builder, however, also generates "standard" set of database entities by default. However, it's really up to the developer to use these "default" set of database entities or to use some external entities. It's also possible to customize how these database entities are created.

As service builder is about interfaces and interfaces doesn't have relationships, there's no concept of relationship supported by service builder. If you want to add relationship to the "default" database entities, you'll have to do it on your own.

Furthermore, liferay is designed to be a high performance platform. Database entities by "default" doesn't have relationships because they're designed to be transactional database entities instead of applicational or data mining database entities. Remember that liferay can be clustered and entities are cached in each server in a cluster before they are written to a database.

EntitieUtil.getRequireEntries(pk);//just for the persist
Hiran Chaudhuri,修改在10 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

Regular Member 帖子: 188 加入日期: 10-9-1 最近的帖子
gavin lau:
emoticonI think you're missing the main point of service builder. I think it's because Brian Chan hasn't explained it too well yet.

Developers are mistaking service builder as a tool to generating database entities. Service builder as the name implies is used to generate "service". "Service" here implies interfaces. "Entities" in service.xml are entities in interface definition.

...

Furthermore, liferay is designed to be...


So if Liferay or the ServiceBuilder is designed to be different than what most people expect, It is worth pointing it out as you just did - but probably in more prominent places. This would encourage developers to think of their own CRUD methods for more complex models, which may be a real relief to the ServiceBuilder mystery.
Maybe a Wiki entry could also help that would recommend when to use ServiceBuilder and when to use something different.

If I understood you right, ServiceBuilder should be used for simple, unrelated instances that can be created independently without transactional background
(I have noet yet seen a possibility to rollback the creation of several ServiceBuilder instances if the last one goes wrong...).
Otherwise, if someone needs relationships and clean transactions, a developer should go his own path?
thumbnail
David H Nebinger,修改在10 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

Liferay Legend 帖子: 14914 加入日期: 06-9-2 最近的帖子
The problem is most new developers see SB as a broken ORM, but it is not an ORM in the classical sense.

The point of SB is to share the service with all deployed web apps on the platform (normally you cannot cross the web app boundary).

To that end SB provides basic CRUD support but mostly on singletons (it will not manage the parent/child relationships in a one-to-many setup).

Transaction support is fine, as long as you know how to plug into it. Txns are applied at the method called in XxxLocalServiceUtil as long as it is named to indicate a txn is required (i.e. addSomething() or createSomething() or saveSomething(), etc., you have to check the spring txn definitions for the exact list).

Anything that must be bound into the txn must be invoked within the body of that implementation method. So if you create an addSomething() method in EntityLocalServiceImpl and this in turn calls other add, update, create, save methods, etc, it's all contained within a single txn so any thrown exception should result in a rollback.
thumbnail
David Lee,修改在10 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

New Member 帖子: 16 加入日期: 13-7-16 最近的帖子
I posted this issue a day ago. But after tinkering and mucking around with my code (including erasing all of my service folder and all the other files/folder generated by service builder), I started over with a similar service.xml file. And today it works!! Wow...

Anyway, if you defined your relationship correctly, then you'll see a getLocation() function in your event class (assuming a 1 event to many location entity relationship model) in your eventPersistence.java and also your eventUtil.java (in the persistence folder in the service folder). From there the only problem is to properly implement it so that you can access your "joined" data from EventLocalServiceImpl.java file:
public java.util.List<Location> getLocation(int location_id) throws SystemException {

java.util.List<Location> location = eventPersistence.getLocations(location_id);
return location;

}

You can see my conversation with Jesse here:
https://www.liferay.com/documentation/liferay-portal/6.2/development/-/ai/write-local-service-classes-liferay-portal-6-2-dev-guide-04-en

SB is actually not that bad... it's probably a lot better than what's out there. IT's slightly hard to understand at first but then so is Java and everything else. Don't give up!!
Antonio Ricciardiello,修改在7 年前。

RE: ServiceBuilder -- mapping relationship one-to-many

New Member 发布: 1 加入日期: 16-3-10 最近的帖子
Hi! I'm new in Liferay so following tutorial I read about Service Builder too

As in the service.xml it's avalable the relationship management over Hibernate, my question is if I have to declare it or as Liferay pratices relationship are to manage in different way.

So if I have some tables, e.g. Employees and Departments, how can I declare and manage building my portlet?

Thanks in advance!