ManyToOne relationship with a String field - java

I have two classes: TranscriptionService and TranscriptionConfig.
TranscriptionConfig has a serviceName variable, that is a string, with setters and getters.
TranscriptionService has no variables or references in the class to TranscriptionConfig.
There are two database tables: transcriptionConfig and transcriptionServices. transcriptionConfig has a foreign key between its field serviceName, and name inside transcriptionServices.
An admin should be able to set the string value of serviceName inside transcriptionConfig. This then references the equivalent string inside name in transcriptionServices. The transcriptionServices entries in the database are pre defined manually, so they never need to be set using an object.
My current hibernate code inside transcriptionConfig for the serviceName is as follows:
#ManyToOne
#JoinColumn(name = "serviceName", nullable = false)
private String transcriptionService;
However, it will not allow me to do this, as a String is not an entity. I have tried adding target-entity to no avail.
It seems to have a manyToOne relationship, it would need to have an instance of the TranscriptionService class, but I do not want transcriptionConfig to contain this object. It just needs a reference with the names.
How I can use this ManyToOne relationship, but just pass around the string for the name?

If you treat this column as a string value, you don't need to define mapping #ManyToOne and use #JoinColumn. Just mark it by#Column.
You'll need probably to catch SQLException in your DAO to handle foreign key constraint.
Edit:
You get this exception, because you don't have this key in foreign table. First you need to create row in TranscriptionService table.

Related

Hibernate get all foreign keys for mapped entities

i need to get the column names for foreign keys for all mapped hibernate entities. Does anyone know how to do that?
I tried by sessionFactory.getClassMetadata - i can see all the properties names and types for all entities there, but i cannot find information about foreign keys.
Does anyone have any idea? I may not use direct database query - i must extract it from hibernate metadata.
You can use Java Reflection:
// Loop through joined columns that has #JoinColumn annotation
for (Method method : testClass.getMethods())
{
if (method.isAnnotationPresent(JoinColumn.class))
{
// name parameter is foreign key
String foreignKey = method.getAnnotation(JoinColumn.class).name;
// if the referencedColumnName is explicitly defined
String foreignKey = method.getAnnotation(JoinColumn.class).referencedColumnName;
}
}

JPA 2: how to declare primary-key columns in #ElementCollection tables

in JPA2 when we are using Embed-able (Basic Type like String.. etc ) object in Entity using with #ElementCollection and #CollectionTable annotation , the new table is created , but in new table how to declare primary-key contraint in column ? following is my code
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
private String salary;
#Transient
private String phnNum;
#Enumerated(EnumType.STRING)
private EmployeeType type;
#ElementCollection
#CollectionTable(name="vacations" , joinColumns=#JoinColumn(name="Emp_Id"))
private Collection<Vacation> vacationBooking;
#ElementCollection
private Set<String> nickNames;
...................
with this code the "vacation" and "employee_nickname" two tables are created in schema. but i want to declare the one primary-key column in both table . what i do for this?
It looks like a primary key per se is not supported by JPA 2.0:
From Wikibooks:
The JPA 2.0 specification does not provide a way to define the Id in the Embeddable. However, to delete or update an element of the ElementCollection mapping, some unique key is normally required. Otherwise, on every update the JPA provider would need to delete everything from the CollectionTable for the Entity, and then insert the values back. So, the JPA provider will most likely assume that the combination of all of the fields in the Embeddable are unique, in combination with the foreign key (JoinColumn(s)). This however could be inefficient, or just not feasible if the Embeddable is big, or complex.
Some JPA providers may allow the Id to be specified in the Embeddable, to resolve this issue. Note in this case the Id only needs to be unique for the collection, not the table, as the foreign key is included. Some may also allow the unique option on the CollectionTable to be used for this. Otherwise, if your Embeddable is complex, you may consider making it an Entity and use a OneToMany instead.
Do you mean that you want to assign 'id' from Employee table as foreign key to the Vacation table?
In that case, you should use #OneToMany instead of #ElementCollection

Getting Hibernate to cascade on save, but not delete?

So I'm having a problem with my hibernate implementation. When I try to delete a parent class, I receive a foreign key constraint exception on a class deep within the cascade hierarchy. Before I go into specifics, I'll first describe the relationships of the classes, as it has a bearing on how they need to be saved and deleted.
At the top level, I have a Customer class, which contains a list of DefaultMask objects. This is the master list, in that these default masks are used by other classes in my object hierarchy, but always from this list. Masks are only created into this list and deleted from this list.
Further down the hierarchy, I have a Column class, which can (optionally) have a DefaultMask set on it. To describe the relationship more succinctly;
A Customer OWNS zero to many DefaultMasks.
A Customer OWNS zero to many Columns.
A Column may have one DefaultMask.
In my application, when I attempt to delete a Customer, the exception comes from the foreign-key constraint on the Column class to the DefaultMask class, and I believe the problem is incorrect settings with CascadeType. I have researched the problem and found information on an attribute called mappedBy and on using Hibernate's own CascadeType.SAVE_UPDATE (in order to prevent Hibernate trying to delete a DefaultMask held by a Column), but I will admit I am a bit lost here and could use some direct guidance. Relevant code for the classes and the actual exception message are below.
Customer:
#Entity
public class Customer {
#Id
private String id;
#OneToMany(cascade = CascadeType.ALL)
private List<DefaultMask> masks;
//(Columns are held further down in hierarchy)
Column:
#Entity
#Table(name = "WarehouseColumn")
public class Column implements Comparable<Column> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int hibernateID;
#OneToOne
private DefaultMask mask;
DefaultMask:
#Entity
public class DefaultMask implements Mask {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int hibernateID;
private String type;
private String mask;
Exception message:
org.hibernate.exception.ConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (hibernate.WarehouseColumn, CONSTRAINT FK8BB153D994AD57D3 FOREIGN KEY (mask_hibernateID) REFERENCES DefaultMask (hibernateID))
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (hibernate.WarehouseColumn, CONSTRAINT FK8BB153D994AD57D3 FOREIGN KEY (mask_hibernateID) REFERENCES DefaultMask (hibernateID))
You're rying to delete a customer, which automatically deletes its list of default masks. But one of these masks is referenced by a column. So the database (and thus Hibernate) refuses to execute the deletion, because it would leave the column in an inconsistent state: it would reference a default mask that doesn't exist anymore.
So you have several functional choices:
leave it as it is: the customer can't be deleted because one of its masks is still referenced by a column
remove the cascade: deleting the customer will delete the customer but not its masks.
find all the columns which reference any of the default masks of the user to be deleted, and remove these columns. Then, remove the user and its default masks
find all the columns which reference any of the default masks of the user to be deleted, and set their mask fild to null. Then, remove the user and its default masks
Cascading is closely related to the concept of logical ownership.
Basically, you need to choose one of the following options:
Customer logically owns its DefaultMasks. In this case you want DefaultMasks to be deleted when you delete a Customer, therefore you need to use CascadeType.ALL. Since Column references DefaultMask, it's probably owned by Customer as well, and should be deleted to
It can be achieved by using bidirectional relationship between DefaultMask and Column with appropriate cascading, as follows:
#Entity
public class DefaultMask implements Mask {
#OneToOne(mappedBy = "mask", cascade = CascadeType.ALL)
Column column;
...
}
DefaultMasks are entities on its own, and Customer just references existing DefaultMasks. In this case you probably don't need to use cascading for this relationship at all.

Hibernate Mapping One To Many Relationship:Parent's PK to Child's FK

I have a classic one to many relationship and while saving it with Hibernate, I am not able to pass parent's PK column value to Child's FK column.
Parent Class
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int holdingPK;
#OneToMany(mappedBy="holding",targetEntity=PolicyType.class,fetch=FetchType.LAZY, cascade = CascadeType.ALL)
#XmlElement(name = "Policy")
private Set<PolicyType> policy;
Child Class
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int policyPK;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="HoldingFK",nullable = false)
private HoldingType holding;
Here HoldingPKis a auto generated sequence column which represents primary key. Value gets generated when I insert a Holding row. So I want to pass HoldingPK value to child's HoldingFK column on the fly.
Test Code
HoldingType obj = new HoldingType();
obj.setCurrencyTypeCode("6");
obj.setHoldingKey("123");
Set<PolicyType> set = new TreeSet<PolicyType>();
PolicyType policy = new PolicyType();
policy.setJurisdiction("Haha");
set.add(policy);
obj.setPolicy(set);
session.save(obj);
transaction.commit();
So I am able to pass Child's other values to Child Table column, just Parent PK is not reaching to Child's FK column.
Here I am persisting XML document values to database. For this I am marshalling XML to Java Objects using JAXB then persisting objects using Hibernate. In this way I am reusing JAXB generated classes with Hibernate and these PK and FK elements do not exist on XML. These are specific to Database.
You simply forgot to initialise the owning side of the bidirectional association. You only initialized the inverse side (the one which has the mappedBy attribute). Hibernate only considers the owning side to know if an association exists or not (the side without the mappedBy attribute).
Add this to your code (before the holding is saved):
policy.setHolding(obj);
Side note: your code would be much more readable if you named the policy field (and accessors) policies. There are many of them, so it should have a plural form.

JPA composite key #OneToMany

I have the following existing DB schema, which I'd like to recreate with Java and plain JPA annotations (using hibernate as provider, so hibernate specific annotations would work as a last resort):
CREATE TABLE users (
user_id NUMBER NOT NULL -- pk
);
CREATE TABLE userdata_keys (
userdata_key_id NUMBER NOT NULL, -- pk
key VARCHAR2(128) NOT NULL
);
CREATE TABLE users_userdata (
user_id NUMBER NOT NULL, -- fk users.user_id
userdata_key_id NUMBER NOT NULL, -- fk userdata_keys.userdata_key_id
value VARCHAR2(256)
);
I've thus created the following classes and annotations:
class User {
#Id
Long id;
#OneToMany
Set<Userdata> userdata;
}
class UserdataKey {
#Id
Long id;
String key;
}
class Userdata {
String value;
#EmbeddedId
UserdataId userdataId;
}
#Embeddable
class UserdataId {
User user;
UserdataKey userdataKey;
}
I left out columnName attributes and other attributes of the entities here.
It does however not quite work as intended. If I do not specify a mappedBy attribute for User.userdata, hibernate will automatically create a table USERS_USERS_USERDATA, but as far as I've seen does not use it. It does however use the table which I specified for the Userdata class.
Since I'm rather new to Java and hibernate as well, all I do to test this currently is looking at the DB schema hibernate creates when persisting a few sample entries.
As a result, I'm entirely puzzled as to whether I'm doing this the right way at all. I read the hibernate documentation and quite a bunch of Google results, but none of them seemed to deal with what I want to do (composite key with "subclasses" with their own primary key).
The mappedBy attribute is mandatory at one of the sides of every bidirectional association. When the association is a one-to-many, the mappedBy attribute is placed ot the one- side (i.e. on the User's userdata field in your case).
That's because when an association is bidirectional, one side of the association is always the inverse of the other, so there's no need to tell twice to Hibernate how the association is mapped (i.e. which join column or join table to use).
If you're ready to recreate the schema, I would do it right (and easier), and use a surrogate auto-generated key in users_userdata rather than a composite one. This will be much easier to handle, in all the layers of your application.

Categories

Resources