spring-projects / spring-data-jpa

Simplifies the development of creating a JPA-based data access layer.
https://spring.io/projects/spring-data-jpa/
Apache License 2.0
2.98k stars 1.41k forks source link

Add getReference method to the SimpleJpaRepository [DATAJPA-83] #510

Closed spring-projects-issues closed 10 years ago

spring-projects-issues commented 13 years ago

Marcin Kuthan opened DATAJPA-83 and commented

SimpleJpaRepository does not expose EntityManager#getReference method. This method is quite useful when the entity id is known, but you don't need load record from database to attach entity to the session.

As a quick workaround I implemented my own repository factory.


Affects: 1.0 GA

Referenced from: commits https://github.com/spring-projects/spring-data-jpa/commit/e7505b40a5a9f2e3df20187fb67e03abf45d5b3a

7 votes, 8 watchers

spring-projects-issues commented 11 years ago

Ittai Zeidman commented

@Oliver, Is there an objection to this or is it a matter of priority? Put it otherwise- will a pull request which simply adds this method to the interface and the implementation be accepted?

Thanks

spring-projects-issues commented 11 years ago

Oliver Drotbohm commented

I am not eager to add JPA specific methods to SimpleJpaRepository and JpaRepository actually. You expose the used store by actually doing so, which subverts the idea of using a repository interface in the first place. I suggest to use ….getReference() on the EntityManager in a custom implementation so that the usage can be hidden behind the repository interface rather than being exposed by it

spring-projects-issues commented 11 years ago

Ittai Zeidman commented

I actually read a blog post by you, after commenting here, where you said pretty much the same thing so I'm not surprised. I very much value your position, as I am in polyglot persistence and the unified interface is helpful, but I also see a valid usecase where I'd like the same repository to return a hydrated instance on one occassion (the traditional Read operation on a RESTful WS for example) and on a different occasion i'd like only the proxy/other provider implementation (a service layer which only needs to update the name of the instance and so does not need to load the entire instance). Don't you think this is a decision one should make when deciding between CRUDRepository and JPARepository? I actually see merit in both options but it seems that JPA specific methods are already out there (especially if you take into account the JPASpecificationExecutor)

spring-projects-issues commented 11 years ago

Marcin Kuthan commented

I would remark that JPA is very leaky abstraction. For example save methods sometimes modifies given entity, sometimes not. I cannot imagine situation when developer is totally unaware of underlying persistence, it's a short path to the disaster in the project.

For me lack of getRefernce method is just a limitation in spring-data-jpa library. The method does not break any contract for JPA specific repository and does not expose what should be encapsulated. If I would be a purist I could always use CrudRepositor instead of JpaRepository, than I will be abstracted from persistence (in theory, as I said).

Thanks, Marci

spring-projects-issues commented 11 years ago

Abhay commented

I agree that lack of getReference equivalent is a limitation. But this is a very useful feature to have. Can't CrudRepository or JpaRepository provide such a feature ?

spring-projects-issues commented 11 years ago

Nicolas Labrot commented

am not eager to add JPA specific methods to SimpleJpaRepository and JpaRepository actually.

This sentence is a bit odd. SimpleJpaRepository is by nature JPA specific. It's even odd as JpaRepository contains the flush method (bad practive to flush).

I have to create an entity A with a reference to an entity B (without loading B). What should I do? A RepositoryA method's "saveWithBId"? I my opinion business logic should not be in repository...

I agree, lack of getRefernce method is just a limitation in spring-data-jpa library.

spring-projects-issues commented 10 years ago

Samuel Padou commented

It seem to me that the lack of getReference is a serious limitation when working with JPA. I don't see any other way to initialize a reference when creating or updating an entity without loading the reference entity which wouldn't be very optimal. And as Nicolas said, JpaRepository seem like the logical place to put JPA specific methods.

As a workaround for now I did my own extended implementation of SimpleJpaRepository adding the getReference method but its a little overkill to just add a simple method.

Is there some plan to add the getReference method (or equivalent) in the future or a better workaround than extending the SimpleJpaRepository?

Thanks

spring-projects-issues commented 10 years ago

Neale Upstone commented

Surely a DSL approach would be far better here. We could provide save() implementations that support saveWithReferenceTo[fieldName](entity, referenceId)?

For example:

class Foo {
    private Bar bar;

    // etc
}

interface FooRepository extends CrudRepository<Foo, Long> {

    Foo saveWithReferenceToBar(Foo entity, Long barId);
}
spring-projects-issues commented 10 years ago

Oliver Drotbohm commented

Would you mind opening a separate ticket for that? I'd like to keep the tickets as focused as possible, esp. as this has been marked as fixed already

spring-projects-issues commented 10 years ago

Neale Upstone commented

Thinking a little more on get reference. The above avoids a leak of anything JPA specific, and allows underlying implementation to avoid materialising an object just for the sake of making a reference (and is covered in DATAJPA-422).

When implementing data import via Spring Data, I'm finding I need to do the above repeatedly. An alternative way of looking at this issue which might be worth considering would be to support findOneLazyById() which in the case of JPA would use getReference(). I suspect we're still dealing with issues that are very JPA specific, as elsewhere the primary key for a reference is often a client-generated UUID (e.g. ObjectId for MongoDB & fuzzydb)