I am currently building a persistence layer for a number of data classes that I can NOT change. These classes have no Id property/field which makes them ill suited for being used in ORM.
A best case scenario for me would have been some sort of auto-generated Ids that would only be present inside the database to set the objects in relation to each other. Sadly this does not seem to be possible using the JPA apis.
Since the above approach did not work out, I decided on trying to use simple wrapper #Entity objects like so:
#Entity
public class ThirdPartyObjectWrapper {
#Id private long id;
#Embedded private ThirdPartyObject myThirdPartyObject;
}
This approach works out nicely in the database, but I am having problems getting the object out of the wrapper and into its place inside another third party object.
public class AnotherThirdPartyObject {
private ThirdPartyObject object; //Actually in a Many-To-One-Relationship
}
Because they are third party objects I'm mapping them through the orm.xml file defining the relationships there. At this point in time the relationship mapping looks like so:
<many-to-one name="object"
target-entity="ThirdPartyObjectWrapper"/>
But with this setup Hibernate tries to insert the ThirdPartyObjectWrapper.id into the AnotherThirdPartyObject.object field, which obviously fails.
My question now is:
Is what I am trying even possible?
Related
I'm designing a solution for dealing with complex structure (user related stuff with lots of relations) in a simplier and possibly more efficient way than getting all the related data from DB. The only part of data I really need in my use case is basically contained withing the non-relational 'main' entity fields.
As for now I extracted the basic fields from 'main' class (let it be class OldMain) to another class (let's call it abstract class Extracted), used #MappedSuperclass and created 2 classes that extends it- Basic (which is empty class as Extracted gives it all the data I need and mapped to table 'X') and Extended (which is also mapped to table 'X' but with all the extra relations). It basically works but the code structure looks odd and makes me thinking if that's a proper way of dealing with such a problem.
I also tried with lazy initiation on relational fields (which i guessed on the beginning would serve here well), but I wasn't able to get it to work as I wanted with Jackson (only non-lazy fields in JSON, without fetching lazy related data- it couldn't be serialized or fired another several dozen of relation queries).
Another thing i stumbled upon in some tutorial was making DTO from 'OldMain' entity to not touch the lazy fields but haven't tried it yet as I started with the #MappedSuperClass way.
#Table(name = "X")
#MappedSuperclass
public abstract class Extracted{
//all the non-relational fields from OldMain
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String surname;
private String userName;
private String email;
}
#Table(name = "X")
#Entity
public class Basic extends Extracted{
//empty
}
#Table(name = "X")
#Entity
public class Extended extends Extracted{
//all relational fields from OldMain, no data fields
}
Also the general question is- is there any good practices when dealing with need of using only a subset of a bigger entity?
There is no obligation for a JPA Entity to map all existing columns in the corresponding table in the database. That is, given a table my_entity with columns col1, col2, col3, the Entity mapped to this table could map only col1 and col2 and ignore col3. That being said, plus the fact that you only need the non-relational attributes, you could directly use your Extracted class with the attributes you need and ignore the fact that other relational field exists. Furthermore, if all the relational fields are nullable then you could even be able to persist new instances of Extracted class. And Jackson would only (un)marshal the declared attributes in Extracted class.
In other case, I suggest to follow the approach you already are in and define new Entity classes that extend your Extracted class with the required attributes. I don't see how "code structure looks odd", other than having a Basic class with no new attributes than Extracted - you could easily make Extracted non-abstract and use it directly, and get rid of Basic.
Preliminary Info
I'm currently trying to integrate Hibernate with my team at work. We primarily do Java web development, creating webapps that provide data to clients. Our old approach involves calling stored procedures with JDBC (on top of Oracle boxes) and storing their results in beans. However, I've heard a lot about the benefits of integrating Hibernate into a development environment like ours so I'm attempting to move away from our old habits. Note: I'm using the Hibernate JPA annotation approach due to simplicity for team adoption's sake.
Specific Problem
The specific issue I'm having currently is using Hibernate with normalized tables. We have a lot of schemas structured like so:
StateCodes (integer state_code, varchar state_name)
Businesses (integer business_id, varchar business_name, integer state_code)
I want to be able to have a single #Entity that has all of the "Businesses" fields, except instead of "state_code" it has "state_name". To my understanding, Hibernate treats #Entity classes as tables. The #OneToMany, #OneToOne, #ManyToOne annotations create relationships between entities, but this is a very simplistic, dictionary-like lookup and I feel like it doesn't apply here (or might be overkill).
One approach I've seen is
#Formula("(select state_name from StateCodes where Businesses.state_code = state_code)")
private String stateCode;
But, given Hibernate's perk of "avoiding writing raw SQL", this seems like bad practice. Not to mention, I'm extremely confused about how Hibernate will then treat this field. Does it get saved on a save operation? It's just defined as a query, not a column, after all.
So what is the best way to accomplish this?
I do not see any reason not use the standard JPA mappings in this case. Short of creating a database view and mapping an entity to that (or using the non-JPA compliant #Formula) then you will have to map as below.
Unless you are providing a means for the State to be changed then you do not need to expose the State entity to the outside world: JPA providers do not need getters/setters to be present.. Neither do you need to Map a State to Businesses:
#Entity
#Table(name = "Businesses")
public class Business{
//define id and other fields
#ManyToOne
#JoinColumn(name = "state_code")
private State state;
public String getStateName(){
return state.getName();
}
}
#Entity
#Table(name="StateCodes")
public class State{
//define id and other fields.
#Column(name = "state_name")
private String stateName;
public String getStateName(){
return stateName;
}
}
I have following entitys:
#Entity
#Inheritance
#DiscriminatorColumn(name = "TYPE")
#DiscriminatorValue("Company")
public class Company {
... (lot of attributes)
}
#Entity
#DiscriminatorValue("Company")
public class LargeCompany extends Company {
... (a few not required attributes)
}
The Company entity lies in a separate project and should be extendable (usually just by one subclass).
When I use #Inheritance by default JPA creates only one table with all attributes from Company and all sub classes. To separate all these different types of instances JPA
uses the #DiscriminatorValue which is usually different for each class.
I realized that it doesn't cause problems if I use same #DiscriminatorValue for both classes (entities). That would make it much easier to use:
The separat project can be responsible for creating Companies and storing them (UI, Validation, etc.). In the next step my project could load these Companies and without
an additional step I get LargeCompany objects.
I verified with several integration tests that this works (when entityManager is cleared) but I'm not sure if I can really rely on that "feature"? Is there probably a better way?
Btw. I'm using hibernate 4.2.0
one of the working tests:
#Test
public void test() {
Company company = new Company("TEST");
em.persist(company);
em.flush();
em.clear(); // required!!
company = em.createQuery("from Company").getFirstResult();
assertEquals(LargeCompany.class, company.getClass());
}
Are you trying to convert one Object in one application to another object in another machine? In this case, it will work. If we talk about its background, in backend (in DB) it create one column for discrimination of row and that row be form to particular java object based on that discrimination value. As you are using same discrimination value in two application accessing same DB, its actually transporting the object from one application to another application. But, If you try to use same discrimination value in single application then you will be in trouble. Firstly, it should give error and if its not giving error then its converted one of your object to another object without your knowledge. So, be careful when using it in same application.
Put another way: How do you model/map a heavily reused child class/table to many different parent entities?
I have several entity types each being persisted into its own table:
class A --> table A
class B --> table B
....
Now I need to make each of these classes the parent of a 1:M unidirectional child collection. The collection is a history of approvals the entity has gained over time. The Child domain class is called "ApprovalItem". The Approval class is exactly the same for all types of parents.
What is the best way to map this? If I create a single table to hold all ApprovalItems, then I can't enforce a FK relation to the PK of the entity and/or I am left with a bad database design.
On the other hand, I could create an ApprovalIems table for each entity type (e.g. A_ApprovalItems, B_ApprovalItems, etc.). This seems like a good schema on the database side, but then it seems I need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.). This seems like a lot of hassle and complexity to create so many new classes in Java that do nothing other than allow me to put in different JPA mapping annotations.
Is there a mapping technique in Hibernate that will allow me to have one class in Java map to several different tables depending on who the parent owner of the collection is?
I could create an ApprovalItem table for each entity type (e.g. A_ApprovalItem, B_ApprovalItem, etc.). This seems like a good schema on the database side
But
It seems i need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.).
You do not need it. you can create a single ApprovalItem class and create a #OneToMany relationship between your parent classes and your ApprovalItem. Hibernate takes care to create a linked table for each relationship.
#Entity
public class ClassA {
#Id
#GeneratedValue
private Integer id;
// Hibernate will create CLASSA_APPROVALITEM to link both class
#OneToMany
private List<ApprovalItem> approvalItemList;
}
#Entity
public class ClassB {
#Id
#GeneratedValue
private Integer id;
// Hibernate will create CLASSB_APPROVALITEM to link both class
#OneToMany
private List<ApprovalItem> approvalItemList;
}
And your ApprovalItem class
#Entity
public class ApprovalItem {
#Id
#GeneratedValue
private Integer id;
// Nothing else
}
But Let's see what Java Persistence with Hibernate book talks about it
You may have shared references to the Bid objects. As suggested earlier, a User may have a collection of references to the Bid instances they made. You can’t delete an item and all its bids without removing these references first. You may get an exception if you try to commit this transaction, because a foreign key constraint may be violated.
So keep it in mind when dealing with shared references.
In order to see how the target schema looks like, you can use the following
AnnotationConfiguration configuration = new AnnotationConfiguration();
configuration
.addAnnotatedClass(ClassA.class)
.addAnnotatedClass(ClassB.class)
.addAnnotatedClass(ApprovalItem.class)
.setProperty(Environment.USER, <TYPE_YOUR_USER>)
.setProperty(Environment.PASS, <TYPE_YOUR_PASSWORD>)
.setProperty(Environment.URL, <TYPE_YOUR_URL>)
.setProperty(Environment.DIALECT, <TYPE_YOUR_DIALECT>)
.setProperty(Environment.DRIVER, <TYPE_YOUR_DRIVER>);
SchemaExport schema = new SchemaExport(configuration);
schema.setOutputFile("schema.sql");
schema.create(<DO_YOU_WANT_TO_PRINT_TO_THE_CONSOLE>, <DO_YOU_WANT_TO_EXPORT_THE_SCRIPT_TO_THE_DATABASE>);
It will generate a file called schema.sql, which contains your target schema
regards,
Chapter 8. Inheritance Mapping of Hibernate Documentation might help.
Otherwise, I see no problem having multiple ApprovalItem derived class that "do nothing", like you say, since it does differentiate the Approval, it's like having a type of approval. Seeing your model like so, I would recommend using multiple classes, even if they only inherit from your base ApprovalItem class.
Have I well understood your question or am I missing something else more subtle?
In one of my projects, I have an application that manages several clients (or customer if you prefer). For each of them, I have a dedicated schema on a database.
However, the application handles only one client at a time, i.e. the user must switch from one client to another in the application (at runtime, no restart of the application) in order to access the data from this new client.
How would you manage the connections, as well as the persistence layer, for this kind of project?
I want to use Hibernate for that. What are the points on which I must be really carefull when dealing with several database / schemas ?
Can Spring be of any help in this case?
If I am not clear enough, let me explain the situation with an example.
Imagine that my application can handle two clients: clientONE and clientTWO.
I already implemented a class that can provide me the database schema, user, password and connection String for a given client.
Each client have a list of debtors, but unfortunately, the DEBTOR table structure is not the same for clientONE and clientTWO.
Even the names of tables / columns are not the same...
So I can create one debtor class per client (I use Hibernate annotations):
#Entity
#Table(name = "T_DEBTOR_ONE")
...
public class ClientOneDebtor {
#Id
#Column(name = "ID_DEBTOR")
private String idDebtor;
...
}
and:
#Entity
#Table(name = "T_DEBTOR_TWO") // Table names are not the same among the different schemas...
...
public class ClientTwoDebtor {
#Id
#Column(name = "DEBTOR_ID") // It's just to show that the same information is stored in a column that has not the same name.
private String idDebtor;
...
}
Ideally, I will try to have a common Debtor class (here is an Abstract class, but I may use an Interface):
public abstract class AbstractDebtor {
public abstract String getIdDebtor();
...
}
#Entity
#Table(name = "T_DEBTOR_ONE")
...
public class ClientOneDebtor extends AbstractDebtor {
#Id
#Column(name = "ID_DEBTOR")
private String idDebtor;
...
}
#Entity
#Table(name = "T_DEBTOR_TWO")
...
public class ClientTwoDebtor extends AbstractDebtor {
#Id
#Column(name = "DEBTOR_ID") // It's just to show that the same information is stored in a column that has not the same name.
private String idDebtor;
...
}
This way, it will be easier for me to manipulate the Debtor objects in my DAO / Service layer, as I will not need to duplicate my DAO and Services for every client.
For example, the method from DAO to get the list of all Debtors will be public List<AbstractDebtor> getAllDebtors() { ... }.
So, how would I change the context when I change the client managed by my application?
In others words, how would I indicate to Hibernate (or Spring?) that I want to use the correct persistence objects (ClientOneDebtor or ClientTwoDebtor) regarding the client that is currently managed by my application?
If you think that I am going in the wrong direction, do not hesitate to share your ideas on how to solve this kind of problem...
Edit regarding the first answers:
The number of different schemas I will need to handle is around 15 - 20. In addition to that, I will only need to map only a little subset of their tables.
I also know that having one schema per client/customer is not the best solution for storing data. However, this architecture exist since 5 years, and we may move to only one schema during the next year (in the best case ;) ).
If only one at a time will every be required, it makes it much simpler. Simply create a SessionFactory per database. Avoid the HibernateUtils static SessionFactory instance approach and you won't have any problems.
A neat way to do this with Spring if you don't have too many databases (hundreds) is to instantiate a separate Spring ApplicationContext for each one that contains the SessionFactoryBean and DataSource configurations specially for that database.
You can use Spring mechanisms like PropertyOverrideConfigurer and a common parent ApplicationContext to factor out all the common stuff so that your many child ApplicationContexts are small and maintainable.
Then when a request comes in, just select the ApplicationContext you want to work with and start pulling beans out of it.
If you want to do it without Spring, you could also create multiple SessionFactory instances and store the "current" one in a static ThreadLocal.
Unfortunately, the Real World often does require multiple databases/schemas, especially when you have a vendor product whose database must be distinct from your corporate databases.
Making an arbitrary number of databases would be a mess, and for that, you really SHOULD consider a better form of data organization. But for a fixed (hopefully small) set of databases, just define them in the persistence configuration with a separate PersistenceUnit for each (which implies a separate EntityManager).
Using your illustrated inheritance scheme, you would assign the appropriate EntityManager to each derived class, assuming that the framework lets you.