How to do Hibernate ORM mapping for a 2D Array - java

I am new to ORM and got stuck on the following issue (simplified for the discussion here):
I am modelling a tournament, with competitors and disciplines. Both have their own entity class. Competitors compete in each discipline exactly once, and receive a score. As long as a competitor has not yet competed in a given discipline, there is no score.
Data Model:
A straightforward DB design would be a scores table with foreign keys to both the competitors table and the disciplines table. That is, I would set up two one-to-many relationships, plus integrity constraints on the foreign keys - I cannot delete a competitor or a discipline as long as there are scores that reference either one.
But how do I map this 2D Array (competitors/disciplines) onto my classes? I am using Java and Hibernate.
My current solution is to put a collection of scores into the Competitor entity class, and similarly for the Disciplines class. This creates a bidirectional relationship with a join table for each of the two entity classes. Is this the recommended way to do the mapping?
It does map the relationship form the perspective of each domain class, but it misses out on the 2D array structure. I want to output the entire array - on a UI, for example - with rows for competitors, columns for disciplines, and the scores in the corresponding table cell. Building such an output from the entity classes as just described is tedious and requires (a) to iterate through the competitor collection and then (b) look up the corresponding discipline - or the other way around.
Ideally, I would like to have a hash map with two keys, like the Guava Table, or a nested hash map. I suppose that there is no native Hibernate mapping for this kind of advanced collection. But maybe there is a best practice how to implement it using custom queries?

But how do I map this 2D Array (competitors/disciplines) onto my classes? I am using Java and Hibernate. My current solution is to put a collection of scores into the Competitor entity class, and similarly for the Disciplines class. This creates a bidirectional relationship with a join table for each of the two entity classes. Is this the recommended way to do the mapping?
IIRC, an implicit join table doesn't allow to add the score. Even if it did, I would't like it as the scores are actually the main information. So I'd go for an explicit table.
class Score {
#ManyToOne(optional=false)
Competitor competitor;
#ManyToOne(optional=false)
Discipline discipline;
}
This should provide everything you need. You may also want a Set<Score> or even Map<Discipline, Score> in the class Competitor (and vice versa in the other class), but you may not need it. The mapping would probably use #ManyToMany(mappedBy="competitor") and #MapKey... I haven't used it for long as I found out I don't really need it.
Ideally, I would like to have a hash map with two keys, like the Guava Table, or a nested hash map.
Using the default #ManyToOne(fetch=EAGER), the needed competitors and disciplines get fetched automatically using a JOIN. I'm afraid, a List is all you can get, but iterating it once and filling a Guava Table is trivial:
list.stream()
.forEach(score -> table.put(score.competitor, score.discipline, score));
Just don't forget that the entities are mutable but mustn't be mutated when used as keys. Obviously, you should only fetch the entities you need rather than filtering the Table. However, once you have the Table, you can use all its operations at will; Hibernate won't help you here anymore, but you don't need it (and you don't want to hit the DB again).

Related

Sql to object, many to many with field

I am working on a little website. The database was created and we need to create objects from sql now.
Usually, in "Many to many" relation, I use a list to represent this relation. (List of ingredient in recipe, and if I need, a list of recipe in ingredient).
But I don't know what is the best way when the junction table contain field.
For example with theses tables:
###### #################### ##########
RECIPE INGREDIENT_IN_RECIPE INGREDIENT
id id_ingredient id
name id_recipe name
quantity
other
Is there a best way to create object from this sql?
I don't know if:
I need to create an third object "IngredientInRecipe". And list it on recipe/ingredient?
Maybe create fields quantity/other in ingredient and use it only when I want to handle ingredient as "ingredientinrecipe"?
Or create a Subclass of Ingredient with quantity/other?
Maybe I'm totally wrong and I just have to create list in recipe and use sql query or array for other things but I'm little bit lost.
This is a simple association class and you would model it like this:
You concrete object model with single tables it pretty fine.
The answer here is based on the question is the INGREDIENT_IN_RECIPE an entity by itself, or is it just a relational table to create the many to many in the db.
Currently, INGREDIENT_IN_RECIPE contains additional information, that is really important and further specifies the relation between RECIPE and INGREDIENT, so this qualifies it is a proper entity.
IMHO, the best way here is to create a entity class for the INGREDIENT_IN_RECIPE table and list it on the RECIPE entity class at least. You need to check if the relation from the INGREDIENT entity is really needed and useful.

one to many association in hibernate

The hibernate documentation gives some rules when we use one-to-many association in Hibernate:
http://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html/collections.html#collections-onetomany
A one-to-many association links the tables of two classes via a
foreign key with no intervening collection table. This mapping loses
certain semantics of normal Java collections:
An instance of the contained entity class cannot belong to more than
one instance of the collection.
An instance of the contained entity
class cannot appear at more than one value of the collection index.
Please help me in understanding these statements.
Suppose I have a Product and it has collection of parts, now as per the points what kind of restrictions applied on my Product and its parts?
A Part cannot belong to 2 or more Products
A Part cannot appears more than one time in the Collection of Parts of a Product

Normalize repeating values in Hibernate - Java

I have a String property of an entity, which is often repeated by other entities - which would (in traditional databases) be mapped to its own table.
For example: I could having a clothing entity, with each item of clothing having its own object or row. Each item will have a brand, but this brand (String) could be repeated by many other clothing items. - it should essentially be a manyToOne mapping, though brand is not an entity on its own, its just a String.
How would I do this in hibernate? Or should I rather create an entity for each brand and use ManyToOne?
Any help will be appreciated!
I think that, just in terms of database normalization (most specifically 3NF), if you are expecting a column to have repeated values, you should export those values to their own table and have a foreign key column. That way, if one of those values changed you could change them all at once.
That would allow you to use ManyToOne in Hibernate as well.
However, if that isn't possible, I would recommend using an Enum.

Hibernate Master-SubDetails Mapping

I'd like to explore Hibernate and used it in my project instead of JDBC.
My table design is highly normalized.
Suppose, I have this use case: Each insurance applied by a customer has one associated rateplan. Usually, in RDBMS this is implemented using two tables like below.
Table Insurance:
id long;
accountHolder varchar;
ratePlanId int; -->Rate Plan Id is Foreign Key to the RatePlanTable
Table RatePlan:
ratePlanId int;
ratePlanDesc varchar;
discountRate double;
Now, my question is..does this qualify as a onetomany relationship?
Most of the examples that I am seeing on the net regarding onetomany, involves some sort of collections (e.g An Order has a list of products). And when represented in class is translated below, which I think is really a one to many case?
public class Order{
private List products;
}
But how about my case? I don't think that it is a onetomany or I am just mislead by the examples?
How can I do a hbm mapping for my two classes? In my case, I would create two class to represent the two tables, but I am not sure how the hbm.xml would look like for the two class.
Yes, it is a one to many relationship, in that one rate plan is associated with many insurance policies. In entity traversal, when you would go from the Policy, you would get one Plan object, and conversely, from a Plan object, you would get a list of Policy objects.

How do I map a Map from an Entity to a Value with hibernate annotations?

I have Shipment and Product entities. Each shipment consists of any amount of any numbers of products. I.e. a shipment has a field named products which is a java.util.Map where they key is the product being shipped and the value is the number of instances of that product being shipped.
How do I map that to a db with hibernate annotations?
This is what you have to do. The field map belongs to the Shipment class, and it maps each Product to the number of products shipped.
This will not work unless you properly define equals and hashCode methods in the class Product that do not depend on hibernate generated ids. (Or read the full story here).
#CollectionOfElements(targetElement=Integer.class)
#MapKeyManyToMany(targetEntity=Product.class)
private Map<Product, Integer> map = new HashMap<Product, Integer>();
This seems like a bit of an odd design to me, but if I understand correctly you'll want a database schema that has:
a shipment table which has an id
a product table which has a foreign key referencing this id
This is all kind of basic, as the relation is a basic one-to-many relationship from the shipment side and many-to-one on the reverse of course. I could give you examples but really the hibernate docs (scroll down to bottom for a map example) seem to have that covered. Some really hard thinking about how that xml maps to the annotations should tide you over. If you're trying to do it in pure JPA you might turn into some trouble, as the linked example seems to use formula.

Categories