many-to-many (self referencing problem) vs double one-to-many - java

I'm facing some of the problem some of you already talked about and sorry to bring this out again.
It's just like I still don't get certain aspect of hibernate. I'm using maven2, hibernate 3.2.5 ga, spring 2.6.5 SEC01, hsqldb 1.8.0.10, netbeans 6.7.1.
I'm bulding a user and contat management and I've managed to get a working "many-to-many" relationship between "contact" and "group pojo" in my environment with either hsql or mysql 5.0.51 but not on a local test server .Because of that i'ld like t try the double one-to-many association so there are few things I would like to ask about that mapping with the introduction of an intermediary model.
Now here are my mappings (I've posted just the necessary to avoid long post )
//UserAccount POJO
#OneToMany(targetEntity=PhoneImpl.class, cascade= {CascadeType.ALL})
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Phone> phones = new HashSet<Phone>();
#OneToMany(targetEntity=ContactImpl.class, cascade={CascadeType.ALL}, mappedBy="userAccount")
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Contact> contacts = new HashSet<Contact>();
#OneToMany(targetEntity=GroupImpl.class, cascade={CascadeType.ALL}, mappedBy="userAccount")
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Group> groups = new HashSet<Group>();
//Contact POJO
#ManyToOne(targetEntity=UserAccountImpl.class)
#JoinColumn(name="USER_ACCOUNT_ID",nullable=false)
private UserAccount userAccount;
#OneToMany(targetEntity=PhoneImpl.class, cascade={CascadeType.ALL})
private Set<Phone> phones = new HashSet<Phone>();
#ManyToMany(targetEntity=GroupImpl.class, mappedBy="contacts")
private Set<Group> groups=new HashSet<Group>();
//Group POJO
#ManyToOne(targetEntity=UserAccountImpl.class)
#JoinColumn(name="USER_ACCOUNT_ID",nullable=false)
private UserAccount userAccount;
#ManyToMany(targetEntity=ContactImpl.class,cascade={CascadeType.PERSIST, CascadeType.MERGE})
#JoinTable(name="GROUP_CONTACT_MAP", joinColumns={#JoinColumn(name="GROUP_ID")},
inverseJoinColumns={#JoinColumn(name="CONTACT_ID")})
private Set<Contact> contacts = new HashSet<Contact>();
SO this works fine on my machine with hsqldb and my local mysql however it's not the same for the local testing server using the same mysql 5.0.SO here are my questions:
1. on the local testing server there is a self referencing foreign key to Contact as well as for group.I've read about circular referencing but can't really tell if it's the case here.Is there in the mapping anything that could generate this kind of self referencing foreign key.Or i failed to avoid the circular referencing stuffs?
2. I'm using Manning java persistence with hibernate which is a great book from where I started practicing the usage of hibernate.in that book the is a double one-to-many association let's say in my case between contact and group with an intermediary model. I just don't know how to use it in practice because I'll like to switch to that approach.
2.1 So my main worries are how to get all the contacts that are in a group and all the groups in which a contact is? I just can't see it clearly.
2.2 if going by that approach how will the contact and group referencing to each other will be? will the ignore each other?
maybe those are basic stuffs for experience java coders like you so forgive my ignorance, i'll be very pleased if you could shed some light on that.
Thanks for reading!

a few ideas:
0: are you sure you've changed the hibernate dialect between using hsqldb and mysql?
1: i think you could expect an exception if you had an unresolvable / circular reference
2.**: you would create a new class called ContactToGroup, it would have a contact field and a group field, each of which is the one end of a many-to-one. Both Contact and Group classes would have a Set of contactToGroup. You could query it like:
from Contact c
left join fetch c.contactToGroupSet joinTable
left join fetch joinTable.Group
This would give you all the Contacts with their Sets of Group attached via ContactToGroup objects.
creating a Contact, ContactToGroup and Group object together would allow you to write to these tables too.
Good luck!

Related

Weblogic to Liberty w JPA upgrade - related entities intermittently not being queried

just a quick question please in case something stands out immediately.
We're migrating an EAR/EJB application from Weblogic 11g to latest WS Liberty (22.x) also upgrading several of the frameworks including JPA to 2.2. This also changes JPA implementation to eclipseLink. We came from com.oracle.weblogic.11g.modules:javax.persistence:1.0.0.0_1-0-2. Underlying DB is MS-SQL Server.
And I'm running into some weirdness with regards to related objects not being resolved/queried intermittently.
Just as an example we have entities where the columns hold reference data codes or similar lookups. Say I have an entity called PayemntRecordT and it has a status code which refers to a ref table that also holds a textual description. Something like this:
SQL:
CREATE TABLE [PAYMENT_RECORD_T](
[PAYMENT_ID] [int] NOT NULL,
...
[PAYMENT_STATUS_CD] [CHAR](8) NOT NULL,
...
)
ALTER TABLE [PAYMENT_RECORD_T] WITH CHECK ADD CONSTRAINT [FK_PAYM4] FOREIGN KEY([PAYMENT_STATUS_CD])
REFERENCES [RECORD_STATUS_T] ([REC_STAT_CD])
GO
CREATE TABLE [RECORD_STATUS_T] (
[RECORD_STAT_CD] [CHAR](8) NOT NULL,
[RECORD_STAT_DSC] [VARCHAR](60) NOT NULL
CONSTRAINT [PK_RECORD_STATUS_T] PRIMARY KEY CLUSTERED (
[RECORD_STAT_CD] ASC
)WITH (PAD_INDEX = OFF...) ON [PRIMARY]
) ON [PRIMARY]
GO
Java:
#Table(name = "PAYMENT_RECORD_T")
#Entity
public class PaymentRecordT {
...
#ManyToOne
#PrimaryKeyJoinColumn(name = "payment_status_cd", referencedColumnName = "REC_STAT_CD")
private RecordStatusT recordStatusT;
}
#Table(name = "RECORD_STATUS_T")
#Entity
public class RecordStatusT {
#Column(name = "REC_STAT_CD")
#Id
private String recStatCd;
#Column(name = "REC_STAT_DSC")
#Basic
private String recStatDsc;
}
Others relations in our app might not be primary key relations but loose relations in which case its just #JoinColumn but the pattern would be the same.
My 'weirdness' is the following:
So in this example I have a list of 10 'Payment Records' each of them have such a record status, which is actually NON NULL in the database. When I do the initial retrieval via EJB method it grabs the 10 records and I also get the correctly resolved/queried record statuses.
Then I add a new record via EJB method (TRANSACTION_REQUIERD). After the add method returns I can query the new payment record in the database via SSMS. Its committed and it looks 100% correct and it contains a correct record status code.
Now I run the retrieval method again and I get the 11 records as I would expect. Only the 11th (newly inserted) record will have recordStatusT as null.
When I restart the app all goes well again for the retrieval of all 11 records. But for subsequent additions the outcome seems again 'undefined'.
In JDBC logging I an see that during the original retrieval of the records the record_status_t table was queried but the 2nd time around it was not and I have no explanation why.
I played with FETCHTYPE.EAGER and read up on caching etc but I'm not going anywhere.
Any ideas?
Thanks for your time
Carsten
I solved the problem by ensuring that after inserts/updates the objects arent being queried from the cache.
In the end - rather than doing it with query hint - I disabled caching for the entity involved using the #Chacheable annotation, like so
#Table(name = "PAYMENT_RECORD_T")
#Entity
#Cacheable(false)
public class PaymentRecordT {
...
#ManyToOne
#PrimaryKeyJoinColumn(name = "payment_status_cd", referencedColumnName = "REC_STAT_CD")
private RecordStatusT recordStatusT;
}
I still feel like there should be a better solution. Eclipselink tracks the inserts/updates so it should be able track what needs rereading from the DB and what not. I still feel like I don't fully understand the entire picture, but this works for me and its reasonably clean.
I can leave the considerable amount of read-only data/objects chacheable and the few that are changeable as non-cacheable.
Thanks for reading
Carsten

Multiple levels of cascading persists in Ebean

I have a model class which defines a list of children that are models of the same class. Persisting a new object with some initial children works fine, but when I have two or more levels of children Ebean does not seem to be able to handle it well. This seemed unexpected so I'm worried I made a mistake. At the same time I couldn't find any examples or mentions about multiple level persist cascades so my questions are:
Is there an error in my code, Is this even a supported feature or did I find a bug?
My model class:
#Entity
public class TestEntity extends Model {
#Id
private int id;
private String text;
#ManyToOne
private TestEntity parentEntity;
#OneToMany(cascade = CascadeType.ALL)
private List<TestEntity> childEntities;
...
}
My program:
TestEntity grandparent = new TestEntity();
grandparent.setText("grandparent");
TestEntity parent = new TestEntity();
parent.setText("parent");
TestEntity child = new TestEntity();
child.setText("child");
grandparent.setChildEntities(Collections.singletonList(parent));
parent.setChildEntities(Collections.singletonList(child));
grandparent.save();
I added logging for the sql statements and it is evident that the third insert didn't get the correct value for parent_entity_id. That row fails due to 0 not being a valid foreign key and the batch is reverted.
insert into test_entity (text, parent_entity_id) values ('grandparent',null);
insert into test_entity (text, parent_entity_id) values ('parent',1);
insert into test_entity (text, parent_entity_id) values ('child',0);
I'm using Play framework 2.7.3 with the ebean plugin version 5.0.2 and Ebean version 11.39
This is indeed a supported feature and the code snippet above is expected to persist all three entities.
There was a unit test added to verify that this is working correctly in the latest version of ebean.
In ebean 11.39 which is currently the latest supported by play framework the test fails. An easy workaround when using that version is to use Long instead of primitive int as ID for the models.
While not an answer to this specific question, it is good to be aware that these same symptoms also appear if the collections are set without using setters enhanced by ebean. I had some trouble using public fields and play enhancer .

Is it ok to save the parent if I am just adding a new child, java hibernate spring?

using hibernate with Java Spring, I have two database tables, Projects and ProjectNotes. Project can have many Notes.
#Entity
#Table(name="projects")
public class Project {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy="project", cascade=CascadeType.ALL)
private List<ProjectNote> projectNotes;
}
and I want to add a new note to the project. Clearly i can do this.
Project project = projectRepository.findOne(id);
ProjectNote pn = new ProjectNote();
pn.setText("Hello");
pn.setProject(project);
project.getProjectNotes().add(pn);
projectRepository.save(project);
and it works. Is that any different than using the notes repository instead
Project project = projectRepository.findOne(id);
ProjectNote pn = new ProjectNote();
pn.setText("Hello");
pn.setProject(project);
projectNotesRepository.save(pn);
Is either more efficient or more correct than the other?
EDIT: another thought. I'm also using #LastModifiedBy/Date on the project. I guess the first method will alter the project lastModified information, whilst the second method will not. But I have not tried it!
In a bidirectional mapping the application is expected to keep the values in sync, meaning that if you call bar.setProject(foo) that method is expected to call foo.getNotes().add(this), making the operations symmetric.
If you enable query logging on Hibernate, you'll see that the end result is the same. The last modified date will also be updated in both cases of course.
Here are some good additional considerations about the complexities of bidirectional associations (and why you might want to avoid them): What is the difference between Unidirectional and Bidirectional associations?

Hibernate List is empty when using lazy loading but it has results when eagerly loaded

I two entities a User and a Place witch are bound with many to many association.
When I try to get all the places for a given user thought the getter method, an emtpy list is returned but the user is bound to the place in the database and if I change the default fetching strategy to eager I can see all the places just fine.
I am using MySQL for the persistance.
The annotations used are:
for the User entity:
#ManyToMany
#JoinTable(name= "USER_PLACE",
joinColumns = {#JoinColumn(name="USER_ID")},
inverseJoinColumns = {#JoinColumn(name="PLACE_ID")})
private List<Place> places = new ArrayList<Place>();
and for the Place entity:
#ManyToMany(mappedBy = "places")
private List<User> users = new ArrayList<User>(0);
What can it be the cause of this?
To me, it looks like a Mapping issue in Your domain-model. Do the provided entities also map somewhere else? You might run into crazy joins with other tables. Could you provide all relevant entities? Also, the SQL statements generated by Hibernate for User.getPlaces() would be helpful.

Database design to track changes - w/ Hibernate

Hey All I'm having a difficult time with a database design. As you can see from my current design a Registration can have multiple EmployerRegistrations which can have multiple ClientRegistrations. It's pretty simple from here. A new registration needs to be created by the user each year.
Unfortunately I need to be able to track changes / amendments. Changes can be made to the Registration information (name, address, etc.) or Client Registration information (remove / add client or remove / add employer).
I've tried a bunch different designs, but so far nothing feels "right". Tracking amendments in the Registration table is easy as this affects all tables above it. All id's are updated. It's the changes to the ClientRegistration table that's throwing me for a loop. As you can see I have a version column I was trying, but it's not helping me much. With Hibernate it feels like each amended client registration needs it's own unique registration object, but creating a whole new registration for any client registration amendments doesn't seem right / efficient.
I've been battling this for about a week so any help would be greatly appreciated. Thanks!
Have you checked out Hibernate Envers? Its an automatic versioning plugin for Hibernate. Makes tracking history of object changes very easy. It is configured in an AOP way, so you can simply annotate the object you want audited and let Envers handle the details:
#Entity
#Audited
public class Person {
#Id
#GeneratedValue
private int id;
private String name;
private String surname;
#ManyToOne
private Address address;
...
}
You can use Envers, which is now bundled in hibernate-core. Check the docs
Have you come across the concept of Temporal data modeling? You might want to Google for it. One very popular technique for temporal modeling is "Effective Dated" logic, used extensively in Peoplesoft. Briefly, it goes like this:
Every table in the system would have this design pattern:
Table{
Primary_key,
effdt,
effseq,
other data,
modified_ts
};
Multiple versions of the record are "stacked up" using the primary key, effdt and effseq. Effdt stores date only, not datetime. effseq (int) is used store multiple changes on the same day. modified_ts stores the date stamp of data change.
the data in a table would look like this:
PrimaryKey1 2012-01-01 1 MyData1 MyData2
PrimaryKey1 2012-02-01 1 MyData1 Change1
PrimaryKey1 2012-02-01 2 Change2 Change1
To get the latest data from any table, you would use the query like this:
select * from MyTable A
where effdt = (select max(effdt) from MyTable where PrimaryKey = A.PrimaryKey)
and effseq = (select max(effseq) from MyTable where PrimaryKey = A.PrimaryKey
and Effdt=A.EFfdt)
Will that help?

Categories

Resources