0

I'm new both to spring and hibernate so take that into consideration in your answer.

I have a many-to-many relationship were the link-table must also contain information. I will try to solve this according to:

How Do I Create Many to Many Hibernate Mapping for Additional Property from the Join Table?

My Question is related to:

hibernate: Custom code on insert / update

But I just repeat it here so no clicking on link is required:

Lets say we have colors. A user can create a Mixture of n colors and store that mixture in the database. Later if a user searches for color "blue" all Mixtures containing blue should be displayed.

Business rule is that any color should only be in the database once. So if a new mixture is inserted, it must first be checked if all the colors are already in the database and if yes that color should be reused (referenced) and if not a new one should be created.

If a mixture is changed say "blue" is replaced with "red", the behavior must be that the initial "blue" remains untouched and the system checks if "red" exists and either reuses it or creates it and then adds it to the mixture.

The important part is that "Colors" are managed by the system and an existing color must never change."red" will always be "red" and should never be changed to "blue". Since I'm new to Hibernate and Spring I'm kind of lost on how to implement this rule and at what level.IMHO I would put that logic at the lowest level possible so that it doesn't break if you (the developer) forgets to check it. does that make sense? Better ideas or suggestions?

Community
  • 1
  • 1
beginner_
  • 7,230
  • 18
  • 70
  • 127

2 Answers2

0

If we can use the same example of Color and Mixture, they may look like this:

public class Color {
  String name;
  List<Mixture> mixtures;
  public String getName() { return name; }
  ...    
}

public class Mixture {
  String name;
  List<Color> colors;
}

So I think the easiest way to make sure your Color is never renamed, you just don't provide a setter setName. It becomes a little trickier to make sure your colours are never deleted. However if you were to provide DAO methods for your persistence, then don't provide a deleteColor method.

I'm not sure if it's a very strong requirement not to be able to delete colours that aren't in use (not referenced by any mixtures) - what's the gain from this? And for ones that are referenced, there will be referential integrity constraints in the database - or at least there should be.

maksimov
  • 5,792
  • 1
  • 30
  • 38
  • You are right if a Color is unused it can be deleted. But assume I change a Mixture of "red" and "blue" to "green" and "blue". Checking if "red" can be deleted just adds overhead. but I guess you would not check and just delete it and rely on database restricting the delete? But then you basically must add logic for swallowing the exception thrown on restrict? If I have no setter for name how will hibernate populate that field when loading the entity? Isn't the setter required? – beginner_ Oct 04 '12 at 11:01
  • What's the use-case for deletion? It's driven from UI then it's a valid case for relying on the DB restriction. It's not much harm either to do the checking in the business layer if `color.mixtures.size() > 0`. On the setter question I think you're correct. Sorry for misleading. In this case, you may want to restrict this on the DAO level, i.e. don't provide the `updateColor` method. That being said, one level lower it would always be possible to persist/merge Color objects through the EntityManager. – maksimov Oct 04 '12 at 12:51
0

So here my current solution:

  1. Unique constraint in color
  2. In DAO update method check if the color to update already exists in database. if yes use it, if no create a new one
  3. Point 2 has an issue if the change to the color and the update happens in the same hibernate session. Then it will update that color from red to blue as the query done in 2. will always return the Color we are updating! I solved this by adding @Immutable to the Color entity class.

Code for 2.

public Color update(final Color color) {
    SQLQuery query = this.getCurrentSession().createSQLQuery(
        "select * from colors where color = :color")
        .addEntity(Color.class);        
    query.setString("color", color.getColor());
    Color result = (Color) query.uniqueResult();
    if (result == null) {
        Color newColor = 
                new Color(color.getColor());
        this.getCurrentSession().persist(newColor);
        return newColor;
    } else {
        return (Color) this.getCurrentSession().merge(result);
    }
}
beginner_
  • 7,230
  • 18
  • 70
  • 127