TL; DR
T findOne(ID id)(eski API'deki Optional<T> findById(ID id)ad ) / (yeni API'daki ad), EntityManager.find()bir varlığın istekli yüklemesini gerçekleştirdiğine dayanır .
T getOne(ID id)EntityManager.getReference()bir varlık tembel yükleme gerçekleştirir dayanır . Bu nedenle, işletmenin etkin bir şekilde yüklenmesini sağlamak için, üzerine bir yöntem çağırılması gerekir.
findOne()/findById()gerçekten daha net ve kullanımı kolaydır getOne().
Yani vakaların çok çoğunda, iyilik findOne()/findById()üzerine getOne().
API Değişikliği
En azından 2.0sürüm Spring-Data-Jpadeğiştirildi findOne().
Önceden, CrudRepositoryarayüzde şu şekilde tanımlanmıştı :
T findOne(ID primaryKey);
Şimdi, findOne()bulacağınız tek yöntem CrudRepository, QueryByExampleExecutorarayüzde hangi yöntemin tanımlandığıdır :
<S extends T> Optional<S> findOne(Example<S> example);
Bu, nihayet arabirimin SimpleJpaRepositoryvarsayılan uygulamasıyla uygulanır CrudRepository.
Bu yöntem, örnek arama ile yapılan bir sorgudur ve bunun yerine yedek olarak istemezsiniz.
Aslında, aynı davranışa sahip yöntem hala yeni API'dadır, ancak yöntem adı değişmiştir.
Bu yeniden adlandırıldı findOne()için findById()de CrudRepositorybir arayüz:
Optional<T> findById(ID id);
Şimdi bir Optional. Önlemek o kadar da kötü değil NullPointerException.
Yani, asıl seçim şimdi Optional<T> findById(ID id)ve arasında T getOne(ID id).
İki farklı JPA EntityManager alma yöntemine dayanan iki farklı yöntem
1) Optional<T> findById(ID id)Javadoc şunları söylüyor:
Bir varlığı kimliğiyle alır.
Uygulamaya baktığımızda EntityManager.find(), geri alma işlemine dayandığını görebiliriz :
public Optional<T> findById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
Class<T> domainType = getDomainClass();
if (metadata == null) {
return Optional.ofNullable(em.find(domainType, id));
}
LockModeType type = metadata.getLockModeType();
Map<String, Object> hints = getQueryHints().withFetchGraphs(em).asMap();
return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));
}
Ve işte em.find()şöyle EntityManagerbildirilen bir yöntem:
public <T> T find(Class<T> entityClass, Object primaryKey,
Map<String, Object> properties);
Javadoc şöyle diyor:
Belirtilen özellikleri kullanarak birincil anahtarla bulma
Bu nedenle, yüklü bir varlığın geri alınması bekleniyor.
2) T getOne(ID id)Javadoc belirtirken (vurgu benimdir):
Belirtilen tanımlayıcıya sahip varlığa bir başvuru döndürür .
Aslında, referans terminolojisi gerçekten tahtadır ve JPA API herhangi bir getOne()yöntem belirtmez .
Yani Bahar sarıcısının ne yaptığını anlamak için yapılacak en iyi şey uygulamaya bakmaktır:
@Override
public T getOne(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
return em.getReference(getDomainClass(), id);
}
İşte em.getReference()olarak EntityManagerbildirilen bir yöntem:
public <T> T getReference(Class<T> entityClass,
Object primaryKey);
Ve neyse ki, EntityManagerjavadoc niyetini daha iyi tanımladı (vurgu benimdir):
Durumu tembel bir şekilde getirilebilecek bir örnek alın . İstenen örnek veritabanında yoksa , örnek durumuna ilk kez erişildiğinde EntityNotFoundException oluşturulur . (Kalıcılık sağlayıcı çalışma zamanının, getReference çağrıldığında EntityNotFoundException özel durumunu atmasına izin verilir.) Uygulama, varlık yöneticisi açıkken uygulama tarafından erişilmedikçe , örnek durumunun ayrılma üzerine kullanılabilir olmasını beklememelidir .
Bu nedenle, çağırmak getOne()tembel olarak getirilmiş bir varlığı döndürebilir.
Burada tembel getirme, varlığın ilişkilerini değil, varlığın kendisini ifade eder.
Bu, eğer çağırırsak getOne()ve sonra Kalıcılık bağlamı kapanırsa, varlığın asla yüklenemeyeceği ve dolayısıyla sonucun gerçekten öngörülemez olduğu anlamına gelir.
Örneğin, proxy nesnesi serileştirilmişse, nullserileştirilmiş sonuç olarak bir başvuru alabilirsiniz veya proxy nesnesinde bir yöntem çağrılırsa, böyle bir istisna LazyInitializationExceptionatılır.
Dolayısıyla bu tür bir durumda, bunun bir hata durumu olarak veritabanında bulunmayan bir örneği işlemek EntityNotFoundExceptioniçin kullanılmasının ana nedeni getOne(), varlık mevcut olmadığında asla gerçekleştirilemez.
Her durumda, yüklenmesini sağlamak için oturumu açarken varlığı değiştirmelisiniz. Varlık üzerindeki herhangi bir yöntemi çağırarak bunu yapabilirsiniz.
Veya findById(ID id)yerine daha iyi bir alternatif kullanım .
Neden bu kadar belirsiz bir API?
Bitirmek için, Spring-Data-JPA geliştiricileri için iki soru:
neden daha açık bir belgeye sahip değilsiniz getOne()? Varlık tembel yükleme gerçekten bir ayrıntı değil.
neden getOne()sarmak için tanıtmak gerekiyor EM.getReference()?
Neden sadece sarılı yönteme bağlı kalmıyorsunuz getReference()? Bu EM yöntemi gerçekten çok getOne() özelken çok basit bir işlemdir.