I'm a little confused with some basic Spring Data concepts.
As I know, typical DAO level structure looks like this:
- dao
- MyFirstObjectDao
- MySecondObjectDao
- jpa
- MyFirstObjectDaoImpl
- jdbc
- MySecondObjectDaoImpl
With this concept, I can use JPA as implementation for my first DAO interface, and JDBC - for the second one.
Now i want to understand Spring Repository abstraction. Every Spring Data tutorial specifies, that I should have an interface, which should extends from JpaRepository, for example. So having this interface, i've already locked with JPA, right?
What if i want to provide different implementations, like jpa/jdbc in DAO?
There's normally not a very good reason to want to mix JPA and JDBC persistence for the same objects; if you're already annotating everything as JPA entities, you might as well use the same persistence setup everywhere. You ought to rethink why you're wanting to do this.
That said, you could potentially do this if you really needed to:
interface FooBaseRepository extends PagingAndSortingRepository<Long, Foo> {}
interface FooJpaRepository extends FooBaseRepository, JpaRepository<Long, Foo> {}
interface FooJdbcRepository extends FooBaseRepository, JdbcRepository<Long, Foo> {}
#Autowired FooBaseRepository surpriseRepository
Update: If you're just talking about having different persistence strategies for different classes (that don't have relationships), there's nothing particularly complicated. You could mix Jpa and Jdbc repositories; they're just interfaces.
Related
I am currently going through a Spring Boot tutorial to build a Spring Data REST application.
The EmployeeRepository interface extends the Crud Repository interface. It is then used in a DatabaseLoader where we use its save, find, and delete methods that are inherited from EmployeeRepository.
My question is how can a class use an inherited method of an interface without defining it? I always thought that on implementation of an interface I must override all of its methods.
From the tutorial: "That is how we can write an empty interface and inherit already built save, find, and delete operations."
Spring data will create an implementation of that interface when the app is running and creating the necessatu beans and of course the persistance context and entity manager too
for that reason when you extends from CrudRepository you need to add the object class and the type of the id of your entity like arguments in order to create this specific object to be persisited in your database
Remember Spring Data JPA will help you with a jpa provider in this case hibernate in order to avoid EntityManagerFactory object and so on.
you can find more information about it here.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference
EmployeeRepository is an interface in your example, not an implementation, so it need not implement the methods. The actual implementation of the interfaces you are using is being provided by Spring Data.
How would you guys elegantly name/baptize these classes, assuming prefix/sulfix like I, Impl, Dao, etc, are bad conventions!
I know it is possible to find many topics about naming convensions, but they are more about it than suggesting on how to handle those cases.
The ideia is to decouple any possible implementation between layers/modules and let the container to handle injections.
model: Company
company service interface: ICompanyService
service implementation class: CompanyService implements ICompanyService
persistence interface: ICompanyDao
persistence implementation class: CompanyDao implements ICompanyDao
I can't get rid of "I" at interface names cause interface and implementations would be named as the same (I know it is possible to use full name including package, but it is even uglier). Same case for CompanyDao. Also the same issue when DAO sulfix is removed because of model class name.
I want to create a DAO class named BaseDAO that should have the JPA and JDBC capabilities in Spring. I mean, I want to extend JPADAOSupport and JDBCDAOSupport classes of spring in to my BaseDAO class. I am aware that multiple inheritance is not an option in Java.
I have created two separate Base classes like BaseJPADao and BaseJdbcDao extending the respective classes. Is it possible to have a single class to extend both? Is there any design pattern solving this issue. Please advise.
Why don't you have a DaoGateway bean having injected the actual JPA DAO and the JDBC DAO beans.
This gateway can then decide which DAO to delegate a given request (to JPA or to JDBC).
You should always favour composition vs inheritance when reusing functionalities.
no it is not. if it was possible, you would still have the same result as in
one class extending JPADAOSupport and JDBCDAOSupport, which you yourself say you know is not possible because multiple inheritance is impossible.
you can write to an interface, and provide two implementations, though.
This would be easy to do with delegation if they both had interface level access you want:
public class MyUberClass implements WhateverJPADAOSupportDoes, WhateverJDBCDAOSupportDoes {
private JPADAOSuport jpa;
private JDBCDAOSupport jdbc;
// now implement all methods specified by the interfaces on the class signature and delegate to their respective member
}
But it seems you want access to all of their public methods. As there is no interface for both you can do the same as above but it can't be of both types simultaneously. The language expressly denies you this.
Your only other option is to create an adapter interface that your code can rely on and then use the combination delegation. If you're hoping to have one class that you can just drop in as a substitution for both then the answer is you can't.
I want to create a DAO layer for my application. After some googling I found that many peoples uses Generic DAO approach (Don't repeat the DAO!).
But I did not like this approach.
What if I need slightly different interfaces between DAO for different DAO implementations? (i.e. methods in generic interface not exactly same which I want to create in my DAO implementations)
What if my entity's primary key consists of more than one attribute?
If you need a slightly different DAO for a particular entity, you can always extend a generic one(MySpecificDAO <....> extends GenericDAO<....>). Primary key can be composite itself, but it's impossible to have 2 primary keys .
Straight from the article you linked to:
Extending GenericDAO
The interface for each DAO is, of course, based on the GenericDao interface. I just need to adapt the interface to a specific domain class and extend it to include my finder methods. In Listing 6, you can see an example of the GenericDao interface extended for a specific purpose
Regarding your last question: by definition, an entity has one and only one primary key.
Disadvantage: you still have to implement the DAO. Stop following advice from 6 years ago, and use Spring Data repositories instead. Then you don't have to write any implementations at all.
What if I need slightly different interfaces between DAO for different
DAO implementations?
you can override the method in your GenericDaoImpl class. or create a new method.
What if my entity have 2 or more primary keys?
I guess you meant compound-key scenario. Note that usually the findOne/readOne/getOne method in GenericDao would expect a parameter, (T key) the T here is type, it could be composite primary key.
for example:
class PersonPK{
private String name;
private Date birthday;
.....
}
You can find here a Generic DAO a working and improved implementation of that very article. Just checkout the Example.java at the bottom of the page. In this example you can see how you can define "slightly different interfaces between DAO for different DAO
implementations".
there is a situation. For example, I am designing simple blog. There are articles and photographies. Users can add their comment to both of them. So when I write it in Java, it looks like this:
public interface Commentable { ... }
public class Article implements Commentable { ... }
public class Photo implements Commentable { ... }
public class Comment {
...
private Commentable commentTo;
}
This is clear and I hope that design is correct. But now I would like to persist it in database and I want to use JPA annotations. Primarily I have to use JPA 1.0 but if there is not solution I would like to know how to do it in JPA 2.0. I found out that there is a way with classic inheritance but I think that Commentable shouldn't be a parent of these object, it is only extension in light of design.
Is there any way how to persist it without changing of desing, please? Thanks a lot
Is there any way how to persist it without changing of design, please? Thanks a lot
JPA doesn't really support your design (to be precise, you can map a relation pointing to an interface if there is a single implementation, but that's not your case). Your JPA provider might have some support for this though (e.g. EclipseLink has a #VariableOneToOne annotation).
With standard JPA, the usual approach would be to use an abstract class (with or without your interface) and to use inheritance. For example (keeping the interface):
public class Comment {
...
#OneToOne(targetEntity=MyAbstractBaseClass.class)
private Commentable commentTo;
}
Where both Article and Photo would extend MyAbstractBaseClass and implment the interface.
The JPA wikibook has two good sections on this topic, see below.
Resources
JPA Wikibook:
My relationship target is an interface
Variable and Heterogeneous Relationships