In my Hibernate+Spring project I've got several entities quite similar; that's why I'm using inheritance type: Table Per Class. The thing is similar to this
class CommonEntity {
private Integer id;
private String name;
private String description;
// Constructors & Setters & Getters
}
class InheritedClass1 extends CommonEntity {
private boolean active;
// Constructors & Setters & Getters
}
class InheritedClass2 extends CommonEntity {
}
As I'm using XML mapping, the mapping for the 1st inherited class contains both CommonEntity and InheritedClass1 fields/columns.
Everything's fine so far.
Here the question is, what would be the best way to implement Repositories/DAOs for the inherited entities? As they will contain common fields (for instance, probably it would end up in implementing a findByName DAO method).
My main point is to avoid implement the same findByName for all inherited class as the only difference would be the name of the Named Query (i.e. InheritedClass1_FindByName and InheritedClass2FindByName).
You could use generics to make a single DAO method that would work for any class which extends your CommonEntity like this:
public <T extends CommonEntity > T getByName(Class<T> clazz, String name) {
Criteria crit = sessionFactory.getCurrentSession().createCriteria(clazz, "named");
crit.add(Restrictions.eq("named.name", name));
return (T)crit.uniqueResult();
}
Obviously if name is not unique you would need to call crit.list() rather than uniqueResult()
Related
I have a project that I've recently inherited that has 2 tables that share a lot of common fields. I'm new to hibernate and want to know if I can use composition to generate the table instead of inheritance? B and D are basically the same class with a different table name.
Current Hierarchy is
B extends A extends BaseClass
D extends C extends BaseClass
My problem at the moment is that a lot of other classes extend BaseClass which don't have the shared fields and the 2 child classes don't share a common parent so I cannot add another level into the Hierarchy and use #MappedSuperclass.
Because of this I'd like to know if I can group my common fields into a single class and compose my child classes with this new class somehow?
Apologies for the cryptic names but as always; confidentiality...
edit - found something simmilar with #Embeddable https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/domain/embeddables.html
If you are using the JPA interface to Hibernate, you can use #Embedded and #Embeddable, to get more or less what you want. Be aware that the change will not be transparent: where you had:
#Entity
public class B extends A {
#Basic
private int foo;
...
}
that you referenced in JPQL by using b.foo, you will have:
#Embeddable
public classs Common {
#Basic
private int foo;
...
}
#Entity
public class B extends A {
#Embedded
private Common common;
...
}
which you will have to reference in JPQL using b.common.foo.
Read more about embeddable entities here:
https://en.wikibooks.org/wiki/Java_Persistence/Embeddables
You could potentially use #Embedded and embed the same object for both B and D, perhaps something like:
#Embeddable
public class CommonFieldObject {
#Column(name="COMFIELD1")
private String commonField1;
#Column(name="COMFIELD2")
private String commonField2;
...
}
#Table
public class C extends A {
#Embedded
#AttributeOverrides({
#AttributeOverride(name="commonField1", column=#Column(name="CFO_COMFIELD1")),
#AttributeOverride(name="commonField2", column=#Column(name="CFO_COMFIELD2"))
})
private CommonFieldObject commonFieldObj; //CFO_ prefix for this reference - in case we have a second field referencing a CommonFieldObject - use a different prefix..
...
}
You should then get the columns CFO_COMFIELD1 and CFO_COMFIELD2 in your table and you can recycle the CommonFieldObject for class D.
I can create a repository via defining an interface on the appropriate JPA class A like the following:
public interface ARepository extends CrudRepository<A, Long>
{
}
and I can use that in my Controller (for example) via
#Autowired
private ARepository aRepository;
and just can do things like this:
aRepository.save(..);
aRepository.findAll();
..
No problem so far.
But my problem is that I have ca. 500 JPA classes and need to access each table which means to define 500 Repositories in the style of above.
So does exist an thing to create that either dynamically via some Spring Data "magic" which from my point of view should exist otherwise the above would not be possible. It looks like this is similar to my problem.
Apart from that one more issue related to the above. I can define findBy... methods in the interface and in the background there will be generated a query method for this particular attribute. The question is also if this can be done in a dynamic way related to the previous question, cause I have groups of tables which need supplemental query methods..
There is spring-data-generator which can automatically generate the interfaces for you.
Regarding your 2nd question I don't think you that can be done in a dynamic way. Java is statically compiled and there's no way to add members dynamically. There could be a tool that generates code for those methods but if that tool generates methods for all combinations of columns you will end up with a huge amount of methods.
You can make a base abstract entity for your 500 classes an then create one repo for this class. (I think it's a common practice to have a BaseEntity class with id, version etc. for every entity in the project).
For simple repo methods (like save, findAll etc.) it will work right from the box (note - entities must have the equal id type). For example:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstarct class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
}
#Entity
public class Entity1 extends BaseEntity {
private String name;
}
#Entity
public class Entity2 extends BaseEntity {
private String name;
}
public interface BaseEntityRepo extends JpaRepository<BaseEntity, Long> {
}
Note that BaseEntity must have #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) to prevent of using singe table base_entity for every entity. And their ids must not intersect (see #GeneratedValue(strategy = GenerationType.SEQUENCE)).
Usage:
#RunWith(SpringRunner.class)
#SpringBootTest
public class BaseEntityRepoTest {
#Autowired private BaseEntityRepo repo;
#Before
public void setUp() throws Exception {
repo.save(asList(
new Entity1("entity1"),
new Entity2("entity2")
));
}
#Test
public void readingTest() throws Exception {
List<BaseEntity> entities = repo.findAll();
assertThat(entities).hasSize(2);
}
}
Related to your second question you can use this approach:
public interface BaseEntityRepo extends JpaRepository<BaseEntity, Long> {
<T> T findById(Long id, Class<T> type);
}
Usage:
#Test
public void findById() {
final Entity1 entity1 = repo.findById(1L, Entity1.class);
final Entity2 entity2 = repo.findById(2L, Entity2.class);
assertThat(entity1).isNotNull();
assertThat(entity2).isNotNull();
}
But you can build repo query methods only for 'common' properties of inherited entities which are present in the base class. To make this method work you must move the name parameter to the BaseEntity:
<T> List<T> findAllByNameLike(String name, Class<T> type);
I know this is a common question, but I haven't found another that solves my doubts.
Usually, if the project is small, I've persistence annotations in the same object that represents the domain object. This allows to load the entity from database and keep all the setters private, ensuring any instance is always in a valid state. Something like:
#Entity
class SomeEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
protected SomeEntity() {}
/* Public getters */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
/* Expose some behaviour */
public void updateAttributes(String attribute1, String attribute2) {
/* do some validations before updating */
}
}
My problem appears if I want to hava a different persistent model. Then I would have something like:
/* SomeEntity without persistent info */
class SomeEntity {
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
protected SomeEntity() {}
/* Public getters */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
/* Expose some behaviour */
public void updateAttributes(String attribute1, String attribute2) {
/* do some validations before updating */
}
}
and DAO:
#Entity
class SomeEntityDAO {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
public SomeEntityDAO() {}
/* All getters and setters */
}
My question is, how can I map SomeEntityDAO to SomeEntity without exposing SomeEntity's attributes?
If I create a constructor like: public SomeEntity(String attribute1, String attribute2, ...) {}, then anyone can create an invalid instance of SomeEntity. The same occurs if I make all setters public in SomeEntity.
I also don't think is a valid solution build the object using updateAttributes() since this will execute some validations I don't whant to execute at this point (we trust the data that's persistet in database).
I'm thinking in having all the setters protected, so the DAO can extend the Entity and have access to setters... but I'm not sure if this is a good option.
Which is the best or common approach to solve this problem?
I've had the same kind of problem. And looking around I've found no solution. Believe me, if it exists is well hidden somewhere. None that suggests what to do when you have to deal with an old project where ORM entities are everywhere and there's a big step between Domain and ORM model.
Given this, I've deducted that if you really want to keep your Domain entities pure (so non get and set - the latter I would NEVER accept!) you have to do some deals. Because there's no way to share the internals without giving the entities some extra knowledge. Beware, this doesn't mean that you have to make the Domain entities aware of the ORM layer, nor that you have to use getters. Just, what I've concluded, the Domain entities should have ways to expose them as a different model.
So, in conclusion, what I would do in your situation is to build up a Visitor pattern. The Domain entity EntityA would implement the EntityAVisitable interface to accept a EntityAVisitor or something like this.
interface EntityAVisitable {
accepts(EntityAVisitor visitor);
}
The builder implements the interface required by the Visitor, EntityAVisitor.
interface EntityAVisitor<T>{
setCombinedValue1_2(String attribute1_attribute2_combinedInEntity);
<T> build();
}
The build() function of the interface EntityAVisitor uses a generic type T. In this way the Domain entity is agnostic about the return type of the concrete implementation of the EntityAVisitor.
Is it perfect? No.
Perfect solution would be to get rid of the ORM (actually I would say that I hate them, because the way are used is most of the times wrong - but this is my personal thought).
Is it nice? No.
A nice solution is not allowed due to language restrictions (I suppose you use Java).
Does it a good work in encapsulating the real content of your Domain entity? Yes.
Not only, in this way you can decide exactly what could be exposed and how. So, in my opinion, is a good deal between keeping the entity pure and having to work with an ORM under the seat.
Domain entity should be self-validating meaning it should only validate itself based on it's internal values. If update requires validation that depends on external dependencies, then I would create an updater class that is responsible for the update. From the updater class, you can use specification pattern (as an injectable dependency) to implement the validation.
Use domain entities when modifying, and DTOs for read-only projections. There are performance and simplification gains when you use straight DTOs in read-only. This is used in CQRS patterns.
class SomeEntity {
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
public SomeEntity() {}
/* Public getters/setter */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
public Long setId() { ... }
public String setAttribute1() { ... }
public String setAttribute2() { ... }
}
//classes/interfaces named for clarity
class EntityUpdater implements IEntityUpdater {
public EntityUpdater (ISpecification spec){
}
public updateEntity(SomeEntity entity){
//assert/execute validation
}
}
Some ORMs allow setting entity values through field access (as opposed to setter methods).
JPA uses the #Access annotation. See What is the purpose of AccessType.FIELD, AccessType.PROPERTY and #Access
I created an ORM, sormula, that can use field access. See #Row fieldAccess and test case org.sormula.tests.fieldaccess.
I have a Spring MVC project using JPA which I have worked on for some time in the past without this issue. But now for some reason (likely an environmental issue as I have switch to a new laptop since I last worked on it) I am getting this weird error.
The project is essentially a tool for creating and performing surveys which are just a set of questions. There are multiple types of question such as "auto complete question", "multiple choice question", "integer question", etc which collect different types of data. Each of this question types is modeled by a subclass which extends an abstract class called DdmQuestion which looks something like this:
#Entity
#Table(name = "ddm_question")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING, name = "question_type")
#JsonIgnoreProperties({"dataType"})
#JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#question_type")
#JsonSubTypes(value = { #Type(DdmTextQuestion.class),#Type(DdmDateQuestion.class),#Type(DdmTimeQuestion.class),#Type(DdmNumberIntegerQuestion.class),#Type(DdmChoiceMultiQuestion.class),#Type(DdmAutoCompleteQuestion.class) })
public abstract class DdmQuestion {
#Id
#GeneratedValue
#Column(name = "question_id")
private int questionId;
#Column(name = "name")
private String name;
public int getQuestionId() {
return questionId;
}
public void setQuestionId(int questionId) {
this.questionId = questionId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#JsonIgnore
public abstract String getDataType();
}
Note the getDataType() method.
Then, for each question type, I have a subclass extending this which looks something like this:
#Entity
#DiscriminatorValue("ddm_question_date")
public class DdmDateQuestion extends DdmQuestion {
final private String DATA_TYPE = "Long"; // this is the line with the error
#Override
public String getDataType() {
return DATA_TYPE;
}
}
Now, I've never encountered this error before (that I can recall) but Eclipse is throwing up an error here that says:
"The Java field for attribute "DATA_TYPE" is final". That's all it
says.
If I remove the #Entity annotation from the class, this error disappears so evidently something in JPA doesn't like something about this but I never had this error before so I'm thinking something changed in a newer version. My POM is not particularly explicit with dependency versions so this would not be surprising.
Can anyone explain to me why this is happening and what the correct resolution is? I could just remove the "final" from the field declaration but this seems wrong to me as it is definitely a final value...
Thanks in advance.
If it is a field that should not be persisted in the database you usually should take advantage of the transient annotation which would tell the persistence provider to ommit that field in its processing.:
#Transient
final private String DATA_TYPE = "Long";
If Eclipse is smart enough, it should stop highlighting the error altogether.
in this linkshttp://docs.oracle.com/javaee/5/tutorial/doc/bnbqa.html#Entities;
An entity class must follow these requirements:
The class must be annotated with the javax.persistence.Entity annotation.
The class must have a public or protected, no-argument constructor. The class may have other constructors.
The class must not be declared final. No methods or persistent instance variables must be declared final.
If an entity instance be passed by value as a detached object, such as through a session bean’s remote business interface, the class must implement the Serializable interface.
Entities may extend both entity and non-entity classes, and non-entity classes may extend entity classes.
Persistent instance variables must be declared private, protected, or package-private, and can only be accessed directly by the entity class’s methods. Clients must access the entity’s state through accessor or business methods.
I have a problem trying to map an inheritance tree. A simplified version of my model is like this:
#MappedSuperclass
#Embeddable
public class BaseEmbedded implements Serializable {
#Column(name="BE_FIELD")
private String beField;
// Getters and setters follow
}
#MappedSuperclass
#Embeddable
public class DerivedEmbedded extends BaseEmbedded {
#Column(name="DE_FIELD")
private String deField;
// Getters and setters follow
}
#MappedSuperclass
public abstract class BaseClass implements Serializable {
#Embedded
protected BaseEmbedded embedded;
public BaseClass() {
this.embedded = new BaseEmbedded();
}
// Getters and setters follow
}
#Entity
#Table(name="MYTABLE")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
public class DerivedClass extends BaseClass {
#Id
#Column(name="ID", nullable=false)
private Long id;
#Column(name="TYPE", nullable=false, insertable=false, updatable=false)
private String type;
public DerivedClass() {
this.embedded = new DerivedClass();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Embeddable
public static NestedClassA extends DerivedEmbedded {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
}
public DerivedClassA() {
this.embedded = new NestedClassA();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Embeddable
public static NestedClassB extends DerivedEmbedded {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
}
public DerivedClassB() {
this.embedded = new NestedClassB();
}
// Getters and setters follow
}
At Java level, this model is working fine, and I believe is the appropriate one. My problem comes up when it's time to persist an object.
At runtime, I can create an object which could be an instance of DerivedClass, DerivedClassA or DerivedClassB. As you can see, each one of the derived classes introduces a new field which only makes sense for that specific derived class. All the classes share the same physical table in the database. If I persist an object of type DerivedClass, I expect fields BE_FIELD, DE_FIELD, ID and TYPE to be persisted with their values and the remaining fields to be null. If I persist an object of type DerivedClass A, I expect those same fields plus the FIELD_CLASS_A field to be persisted with their values and field FIELD_CLASS_B to be null. Something equivalent for an object of type DerivedClassB.
Since the #Embedded annotation is at the BaseClass only, Hibernate is only persisting the fields up to that level in the tree. I don't know how to tell Hibernate that I want to persist up to the appropriate level in the tree, depending on the actual type of the embedded property.
I cannot have another #Embedded property in the subclasses since this would duplicate data that is already present in the superclass and would also break the Java model.
I cannot declare the embedded property to be of a more specific type either, since it's only at runtime when the actual object is created and I don't have a single branch in the hierarchy.
Is it possible to solve my problem? Or should I resignate myself to accept that there is no way to persist the Java model as it is?
Any help will be greatly appreciated.
Wow. This is the simplified version? I assume that the behavior that you are seeing is that BaseEmbedded field is persisted but not the FIELD_CLASS_A or B?
The problem is that when Hibernate maps the DerivedClassA and B classes, it reflects and sees the embedded field as a BaseEmbedded class. Just because you then persist an object with the embedded field being a NestedClass, the mapping has already been done and the FIELD_CLASS_A and B are never referenced.
What you need to do is to get rid of the NestedClass* and embedded field and instead have the fieldClassA and B be normal members of DerivedClassA and B. Then add add a name field to the #Entity which will put them both in the same table I believe. This will allow you to collapse/simplify your class hierarchy a lot further.
See: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e1168
#Entity(name = "DerivedClass")
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
...
#Entity(name = "DerivedClass")
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
...