An identifying relationship (or "compound identity relationship") is a relationship between two objects of two classes in which the child object must coexist with the parent object and where the primary key of the child includes the Entity object of the parent. So effectively the key aspect of this type of relationship is that the primary key of one of the classes includes a Entity field (hence why is is referred to as Compound Identity). This type of relation is available in the following forms
Lets take the same classes as we have in the 1-1 Relationships. In the 1-1 relationships guide we note that in the datastore representation of the User and Account the ACCOUNT table has a primary key as well as a foreign-key to USER. In our example here we want to just have a primary key that is also a foreign-key to USER. To do this we need to modify the classes slightly and add primary-key fields and use "application-identity".
In addition we need to define primary key classes for our User and Account classes
public class User { long id; ... (remainder of User class) /** * Inner class representing Primary Key */ public static class PK implements Serializable { public long id; public PK() { } public PK(String s) { this.id = Long.valueOf(s).longValue(); } public String toString() { return "" + id; } public int hashCode() { return (int)id; } public boolean equals(Object other) { if (other != null && (other instanceof PK)) { PK otherPK = (PK)other; return otherPK.id == this.id; } return false; } } } public class Account { User user; ... (remainder of Account class) /** * Inner class representing Primary Key */ public static class PK implements Serializable { public User.PK user; // Use same name as the real field above public PK() { } public PK(String s) { StringTokenizer token = new StringTokenizer(s,"::"); this.user = new User.PK(token.nextToken()); } public String toString() { return "" + this.user.toString(); } public int hashCode() { return user.hashCode(); } public boolean equals(Object other) { if (other != null && (other instanceof PK)) { PK otherPK = (PK)other; return this.user.equals(otherPK.user); } return false; } } }
To achieve what we want with the datastore schema we define the MetaData like this
<entity-mappings> <entity class="mydomain.User"> <table name="USER"/> <id-class class="mydomain.User.PK"/> <attributes> <id name="id"> <column name="USER_ID"/> </id> <basic name="login"> <column name="LOGIN" length="20"/> </basic> </entity> <entity class="mydomain.Account"> <table name="ACCOUNT"/> <id-class class="mydomain.Account.PK"/> <attributes> <id name="user"> <column name="USER_ID"/> </id> <basic name="firstName"> <column name="FIRSTNAME" length="50"/> </basic> <basic name="secondName"> <column name="LASTNAME" length="50"/> </basic> <one-to-one name="user"/> </attributes> </entity> </entity-mappings>
So now we have the following datastore schema
Things to note :-
Lets take the same classes as we have in the 1-N Relationships (FK). In the 1-N relationships guide we note that in the datastore representation of the Account and Address classes the ADDRESS table has a primary key as well as a foreign-key to ACCOUNT. In our example here we want to have the primary-key to ACCOUNT to include the foreign-key. To do this we need to modify the classes slightly, adding primary-key fields to both classes, and use "application-identity" for both.
In addition we need to define primary key classes for our Account and Address classes
public class Account { long id; // PK field Set addresses = new HashSet(); ... (remainder of Account class) /** * Inner class representing Primary Key */ public static class PK implements Serializable { public long id; public PK() { } public PK(String s) { this.id = Long.valueOf(s).longValue(); } public String toString() { return "" + id; } public int hashCode() { return (int)id; } public boolean equals(Object other) { if (other != null && (other instanceof PK)) { PK otherPK = (PK)other; return otherPK.id == this.id; } return false; } } } public class Address { long id; Account account; .. (remainder of Address class) /** * Inner class representing Primary Key */ public static class PK implements Serializable { public long id; // Same name as real field above public Account.PK account; // Same name as the real field above public PK() { } public PK(String s) { StringTokenizer token = new StringTokenizer(s,"::"); this.id = Long.valueOf(token.nextToken()).longValue(); this.account = new Account.PK(token.nextToken()); } public String toString() { return "" + id + "::" + this.account.toString(); } public int hashCode() { return (int)id ^ account.hashCode(); } public boolean equals(Object other) { if (other != null && (other instanceof PK)) { PK otherPK = (PK)other; return otherPK.id == this.id && this.account.equals(otherPK.account); } return false; } } }
To achieve what we want with the datastore schema we define the MetaData like this
<entity-mappings> <entity class="mydomain.Account"> <table name="ACCOUNT"/> <id-class class="mydomain.Account.PK"/> <attributes> <id name="id"> <column name="ACCOUNT_ID"/> </id> <basic name="firstName"> <column name="FIRSTNAME" length="50"/> </basic> <basic name="secondName"> <column name="LASTNAME" length="50"/> </basic> <one-to-many name="addresses" mapped-by="account"/> </entity> <entity class="mydomain.Address"> <table name="ADDRESS"/> <id-class class="mydomain.Address.PK"/> <attributes> <id name="id"> <column name="ID"/> </id> <id name="account"> <column name="ACCOUNT_ID"/> </id> <basic name="city"> <column name="CITY"/> </basic> <basic name="street"> <column name="STREET"/> </basic> <many-to-one name="account"/> </attributes> </entity> </entity-mappings>
So now we have the following datastore schema
Things to note :-
Lets take the same classes as we have in the 1-N Relationships (FK). In this guide we note that in the datastore representation of the Account and Address classes the ADDRESS table has a primary key as well as a foreign-key to ACCOUNT. In our example here we want to have the primary-key to ACCOUNT to include the foreign-key. To do this we need to modify the classes slightly, adding primary-key fields to both classes, and use "application-identity" for both.
In addition we need to define primary key classes for our Account and Address classes
public class Account { long id; // PK field Set addresses = new HashSet(); ... (remainder of Account class) /** * Inner class representing Primary Key */ public static class PK implements Serializable { public long id; public PK() { } public PK(String s) { this.id = Long.valueOf(s).longValue(); } public String toString() { return "" + id; } public int hashCode() { return (int)id; } public boolean equals(Object other) { if (other != null && (other instanceof PK)) { PK otherPK = (PK)other; return otherPK.id == this.id; } return false; } } } public class Address { String alias; Account account; .. (remainder of Address class) /** * Inner class representing Primary Key */ public static class PK implements Serializable { public String alias; // Same name as real field above public Account.PK account; // Same name as the real field above public PK() { } public PK(String s) { StringTokenizer token = new StringTokenizer(s,"::"); this.alias = Long.valueOf(token.nextToken()).longValue(); this.account = new Account.PK(token.nextToken()); } public String toString() { return alias + "::" + this.account.toString(); } public int hashCode() { return alias.hashCode() ^ account.hashCode(); } public boolean equals(Object other) { if (other != null && (other instanceof PK)) { PK otherPK = (PK)other; return otherPK.alias.equals(this.alias) && this.account.equals(otherPK.account); } return false; } } }
To achieve what we want with the datastore schema we define the MetaData like this
<entity-mappings> <entity class="mydomain.Account"> <table name="ACCOUNT"/> <id-class class="mydomain.Account.PK"/> <attributes> <id name="id"> <column name="ACCOUNT_ID"/> </id> <basic name="firstName"> <column name="FIRSTNAME" length="50"/> </basic> <basic name="secondName"> <column name="LASTNAME" length="50"/> </basic> <one-to-many name="addresses" mapped-by="account"> <map-key name="alias"/> </one-to-many> </entity> <entity class="mydomain.Address"> <table name="ADDRESS"/> <id-class class="mydomain.Address.PK"/> <attributes> <id name="account"> <column name="ACCOUNT_ID"/> </id> <id name="alias"> <column name="KEY"/> </id> <basic name="city"> <column name="CITY"/> </basic> <basic name="street"> <column name="STREET"/> </basic> <many-to-one name="account"/> </attributes> </entity> </entity-mappings>
So now we have the following datastore schema
Things to note :-