I have a User entity. Each User can have one or more personal Addresses. According to the Hibernate documentation for mapping embeddable collections this is how it should be done:
#Entity
public class User {
[...]
public String getLastname() { ...}
#ElementCollection
#CollectionTable(name="Addresses", joinColumns=#JoinColumn(name="user_id"))
#AttributeOverrides({
#AttributeOverride(name="street1", column=#Column(name="fld_street"))
})
public Set<Address> getAddresses() { ... }
}
#Embeddable
public class Address {
public String getStreet1() {...}
[...]
}
Now if I want the User to have a collection for work addresses too, what should I do?
Here is what I thought:
Create 2 different collections for work addresses and personal addresses then map them into 2 different tables. ( Sounds like over complicating things as both addresses are exactly the same)
Store both addresses into the same table. (However, I don't know how will I differentiate between them)
Introduce a look up entity/value object and use it somehow to differentiate between personal and work addresses. (from the database point of view we will have a look up table for address types linked via a foreign key to the address table, but I don't know how that should be modeled in the domain itself using Hibernate)
Alternative approaches are very welcomed.
Try using hibernate single table inheritance mapping:
#Entity
#Inheritance(strategy= InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="addresstype",
discriminatorType= DiscriminatorType.STRING)
public abstract class Address {
... common attributes here
}
#Entity
#DiscriminatorValue("home")
public class HomeAddress extends Address {
...
}
#Entity
#DiscriminatorValue("work")
public class WorkAddress extends Address {
...
}
And then create two collections, one for home addresses and the other for work addresses.
If there is code that is valid only for home addresses then we use the HomeAddress type, the same if there is code that is only valid for work addresses we use WorkAddress.
If there is code that is valid for both address types then we use the Address super type.
Related
can JPA ElementCollection Embeddable have ElementCollection List Embeddable property?
#Entity
class Person {
#ElementCollection
private List<Address> addressList;
}
#Embeddable
public class Address {
private String city;
private String state;
private String countary;
#ElementCollection
private List<Phone> phones;
...
}
#Embeddable
public class Phone {
private String type;
private String areaCode;
private String number;
...
}
Yes you can have that, if you try your configuration you will have something like this.
http://postimg.org/image/pc0f3cxbp/
Also Embeddable types can have Collection Relationship to another entities this allowed by JPA.
Taking from specs JSR317
An embeddable class may be used to represent the state of another
embeddable class.
An embeddable class (including an embeddable class within another
embeddable class) may contain a collection of a basic type or other
embeddable class.
An embeddable class may contain a relationship to an entity or
collection of entities. Since instances of embeddable classes
themselves have no persistent identity, the relationship from the
referenced entity is to the entity that contains the embeddable
instance(s) and not to the embeddable itself.
An embeddable class that is used as an embedded id or as a map key
must not contain such a relationship
UPDATE
According to your question if embeddables can contain a list of embeddables this is possible and can be done as picture in this answer suggest, BUT regarding if and ElementCollection can contain an embeddables with another element collection the answer is NO
Trying to do that will cause.
Mapping contains an embeddable "examples.model.Address" with a
prohibited mapping "phones", element collections may not contain
embeddables with element collection mappings
How to annotate my code to have a Person with 2 Addresses :
#Entity
public Person {
// ... other attributes for a person
#OneToOne
public Address homeAddress;
#OneToOne
public Address workAddress;
}
#Entity
public Address {
// ... other attributes for an address
#OneToOne
public Person person;
}
Can I use OneToOne ?
Should I have to use options on this annotations ?
Unfortunately this is not possible to achieve with #OneToOne. The reason:
the persistence provider will have one Person id for two entries the Address table. This is not sufficient to decide which relation a given Address belongs to.
The simplest solution would be to add a type field (an enum) to the Address entity and map the addresses with #OneToMany/#ManyToOne.
In order to get the home address, you would need to iterate over the addresses and check for type.
Alternatively, you could create extra types like HomeAddress and WorkAddress which would derive from the Address. You could then keep the #OneToOne relations, but would end up with two additional types.
IMO a cleaner entity relation mapping is not a sufficient reason for doing this, as you are inviting some issues. For example a HomeAddress can never be a WorkAddress.
EDIT: If both Address ids are stored in the Person table, you should be able to use the#OneToOne relation. To ensure deletion of attached Address entities and deletion of orphaned Address entities, you can use cascading and orphan removal:
#OneToOne(cascade=CascadeType.ALL, orphanRemoval=true)
Although it might look like this makes sure that there could be no orphaned Address records in the DB, it is not entirely true. Orphan removal works only when you remove the referenced entity inside a transaction while the entities are attached. Furthermore it does not work for bulk updates. A DELETE FROM Person WHERE ... query will happily delete the Persons and will not touch the connected Addresses.
OneToOne implies a table has a foreign key to another, but you haven't specified which, and are implying that it isn't a real 1:1 situation from address->person. Will employee have a workAddress_ID and homeAddress_id field? In which case, there are two different 1:1s. What isn't valid is your address->Employee 1:1 as there is no way for it to use both the workAddress_ID and homeAddress_id relationships. You could work around this by having address have 2 OneToOnes that are private, and then a public getPerson method used by the application that returns the one that isn't null. Setting the person would require looking at the passed in person object ot know which of the Address 1:1's to populate, but it wouldn't matter as much since they wouldn't control the relationship:
public Address {
// ... other attributes for an address
#OneToOne(mappedby="workAddress")
private Person workPerson;
#OneToOne(mappedby="homeAddress")
private Person homePerson;
public Person getPerson() {
return workPerson==null? homePerson:workPerson;
}
public void setPerson(Person p) {
workPerson=null;
homePerson=null;
if (p !=null) {
if (p.getHomeAddress()==this) {
homePerson=p;
} else {
workPerson=p;
}
}
}
}
Here is parent class Enterprise. It has employers and one of them is president of enterprise.
#Entity
class Enterprise
{
// fields
#OneToMany
public List<Employee> getEmployers()
// implementation
#OneToOne
public Employee getPresident()
// implementation
}
Here is child Employee class. It has only info about Enterprise where he works. But question is what association should I use?
#Entity
class Employee
{
// fields
// what association should I use?
public Enterprise getEnterprise()
// implementation
}
Given that you've defined the Enterprise->Employers association with #OneToMany, which means that an Employer belongs to only one Enterprise, you should be using #ManyToOne, meaning that every Employer belongs to max. 1 Enterprise, but an Enterprise can reference many Employers.
You can define the association specifics (join columns, etc) in one of the sides only, using the mapped-by attribute in the annotation:
#Entity
class Enterprise
{
#OneToMany(mapped-by="enterprise")
public List<Employee> getEmployers()
// implementation
#OneToOne
public Employee getPresident()
// implementation
}
#Entity
class Employee
{
#ManyToOne
#JoinTable ( name="Enterprise", joinColumns={ #JoinColumn(name="ENT_ID", referencedColumnName="ENT_ID") }
public Enterprise getEnterprise()
// implementation
}
In case an Employer could be president of a different Enterprise in which he is employed (seems unlikely, unless one can be president of an enterprise without being employed by it), and in case you needed to access the Enterprise of which the Employer is president from the Employer entity, you would need to add another association, ideally with #OneToOne (you would encounter problems, because #OneToOne relations require both entities to have the same #Id class). In this case I would annotate the getPresidedEnterprise() method on Employer with #ManyToOne for practical reasons.
Use #ManyToOne annotation. It is the opposite side of a one-to-many relation. It says an employee can have one enterprise, but an enterprise can have many employees.
You should have two properties on the Employee class. Employee table should have a reference to an enterprise, ad enterprise should have a reference to an employee-president.
(you could also probably subclass an Employee based on the isPresident flag column, but I don't have experience with that)
#Entity
class Enterprise
{
// fields
#OneToMany(mappedBy="enterprise")
public List<Employee> getEmployees(){}
#OneToOne
#JoinColumn(name="PRESIDENT_ID")
public Employee getPresident(){}
}
#Entity
class Employee
{
// fields
#ManyToOne
#JoinColumn(name="ENTERPRISE_ID")
public Enterprise getEnterprise(){}
#OneToOne(mappedBy="President")
public Enterprise getMyEnterprise(){}
}
I need to model a Customer and an Address for applications in django as well as in Play!.I believe that two Customers can have the same address.
So a Many to One relation between Customer and Address
class Customer extends play.db.jpa.Model{
#ManyToOne
public Address address;
..
}
In django ,does this python code below give similar mapping?
class Address(models.Model):
customer= models.ForeignKey(Customer)
What will be the tables created like?I am slightly confused here..
You almost got that right. The many-to-one relationship in Django is indeed represented by the models.ForeignKey.
To express relationship that two customers can have the same address you would define that relation in the Customer model (not in the Address model as you assumed).
class Customer(models.Model):
address = models.ForeignKey(Address)
I want to know annotation based one-to-many mapping for basic type for example Person has many nick names. Person is class type and nick name is basic type String. One Person many nick names.
Check out section 2.2.5.3.3 of the Hibernate Annotations manual, which has an example suspiciously similar to yours:
In some simple situation, do don't
need to associate two entities but
simply create a collection of basic
types or embeddable objects. Use the
#ElementCollection in this case.
#Entity
public class User {
[...]
public String getLastname() { ...}
#ElementCollection
#CollectionTable(name="Nicknames", joinColumns=#JoinColumn(name="user_id"))
#Column(name="nickname")
public Set<String> getNicknames() { ... }
}
Note: In older versions of Hibernate Annotations, #ElementCollection was called #CollectionOfElements.