扩展 Spring 数据存储库
Extend Spring Data Repository
我想向我的所有存储库介绍 <T> T findOrCreate(Supplier<Optional<T>> finder, Supplier<T> factory)
。
所以创建了一个新的界面
@NoRepositoryBean
public interface ExtendedJpaRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
T findOrCreate(Supplier<Optional<T>> finder, Supplier<T> factory);
}
.
public class ExtendedJpaRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements ExtendedJpaRepository<T, ID> {
private final JpaEntityInformation entityInformation;
private final EntityManager entityManager;
public ExtendedJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityInformation = entityInformation;
this.entityManager = entityManager;
}
@Override
public T findOrCreate(Supplier<Optional<T>> finder, Supplier<T> factory) {
throw new NotImplementedException("No implemented yet");
}
}
然后我在具体的存储库中使用这个接口,例如RecipeIngredientRepository:
public interface RecipeIngredientRepository extends ExtendedJpaRepository<RecipeIngredient, Long> {}
当我最终将存储库注入我的服务时,出现以下异常:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'recipeIngredientRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property find found for type RecipeIngredient! Did you mean 'id'?
正在我的实体 RecipeIngredient
中搜索 find
属性。我不希望它这样做。我认为这与JPA Query Methods有关。所以我将名称从 findOrCreate
更改为 xxx
以绕过任何查询方法检测 - 但没有成功。然后搜索 xxx
属性。
是什么让 spring 数据寻找这个 属性?
我正在使用 org.springframework.boot:spring-boot-starter-data-jpa
.
您需要通过 @EnableJpaRepositories(repositoryBaseClass = ExtendedJpaRepositoryImpl.class)
.
指定自定义存储库实现
添加到@md911de 回答:
因此,您可以定义一个通用接口,该接口具有您希望在所有存储库中拥有的基本方法:
@NoRepositoryBean
interface BaseGenericReactiveMongoRepository<T> :
ReactiveMongoRepository<T, String> {
fun patch(id: String, fields: Map<String, Any>): Mono<T>
}
然后你需要实现它并通知spring使用实现class来实现接口。
class SimpleBaseGenericReactiveMongoRepository<ENTITY>(
private val entityInformation: MappingMongoEntityInformation<ENTITY, String>,
private val template: ReactiveMongoTemplate
) : SimpleReactiveMongoRepository<ENTITY, String>(entityInformation, template),
BaseGenericReactiveMongoRepository<ENTITY> {
private val eventPublisher: ApplicationEventPublisher?
init {
val context = template.converter.mappingContext as MongoMappingContext
val indexCreator = MongoPersistentEntityIndexCreator(context) { collectionName ->
IndexOperationsAdapter.blocking(template.indexOps(collectionName))
}
eventPublisher = MongoMappingEventPublisher(indexCreator)
}
override fun patch(id: String, fields: Map<String, Any>): Mono<ENTITY> {
val collection = entityInformation.collectionName
val query = Query(Criteria.where("_id").`is`(id))
val document = Document()
return findById(id)
.flatMap { entity ->
maybeEmitEvent(BeforeConvertEvent<ENTITY>(entity, collection))
document.putAll(fields)
val update = Update()
fields
.filter { entry ->
!hashSetOf("_id", "createdAt", "createdBy", "modifiedAt", "modifiedBy").contains(entry.key)
}
.forEach { entry -> update.set(entry.key, entry.value) }
maybeEmitEvent(BeforeSaveEvent<ENTITY>(entity, document, collection))
template.updateFirst(query, update, collection)
}
.then(findById(id)).map { entity ->
maybeEmitEvent(AfterSaveEvent<ENTITY>(entity, document, collection))
entity
}
}
private fun <T> maybeEmitEvent(event: MongoMappingEvent<T>) {
eventPublisher?.publishEvent(event)
}
}
最后一部分是通知spring数据。
@Configuration
@EnableReactiveMongoRepositories(
basePackages = ["**.repository"],
repositoryBaseClass = SimpleBaseGenericReactiveMongoRepository::class
)
class MongoConfiguration
现在您可以将该界面用作存储库的基本界面,并拥有适用于您的域的功能。
interface BookRepository : BaseMongoRepository<Book> {
findByNameContainingIgnoreCaseAndVisibileIsTrue(name:String): Flux<Book>
}
如果您需要一个工作示例,欢迎查看我的媒体:
我想向我的所有存储库介绍 <T> T findOrCreate(Supplier<Optional<T>> finder, Supplier<T> factory)
。
所以创建了一个新的界面
@NoRepositoryBean
public interface ExtendedJpaRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
T findOrCreate(Supplier<Optional<T>> finder, Supplier<T> factory);
}
.
public class ExtendedJpaRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements ExtendedJpaRepository<T, ID> {
private final JpaEntityInformation entityInformation;
private final EntityManager entityManager;
public ExtendedJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityInformation = entityInformation;
this.entityManager = entityManager;
}
@Override
public T findOrCreate(Supplier<Optional<T>> finder, Supplier<T> factory) {
throw new NotImplementedException("No implemented yet");
}
}
然后我在具体的存储库中使用这个接口,例如RecipeIngredientRepository:
public interface RecipeIngredientRepository extends ExtendedJpaRepository<RecipeIngredient, Long> {}
当我最终将存储库注入我的服务时,出现以下异常:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'recipeIngredientRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property find found for type RecipeIngredient! Did you mean 'id'?
正在我的实体 RecipeIngredient
中搜索 find
属性。我不希望它这样做。我认为这与JPA Query Methods有关。所以我将名称从 findOrCreate
更改为 xxx
以绕过任何查询方法检测 - 但没有成功。然后搜索 xxx
属性。
是什么让 spring 数据寻找这个 属性?
我正在使用 org.springframework.boot:spring-boot-starter-data-jpa
.
您需要通过 @EnableJpaRepositories(repositoryBaseClass = ExtendedJpaRepositoryImpl.class)
.
添加到@md911de 回答:
因此,您可以定义一个通用接口,该接口具有您希望在所有存储库中拥有的基本方法:
@NoRepositoryBean
interface BaseGenericReactiveMongoRepository<T> :
ReactiveMongoRepository<T, String> {
fun patch(id: String, fields: Map<String, Any>): Mono<T>
}
然后你需要实现它并通知spring使用实现class来实现接口。
class SimpleBaseGenericReactiveMongoRepository<ENTITY>(
private val entityInformation: MappingMongoEntityInformation<ENTITY, String>,
private val template: ReactiveMongoTemplate
) : SimpleReactiveMongoRepository<ENTITY, String>(entityInformation, template),
BaseGenericReactiveMongoRepository<ENTITY> {
private val eventPublisher: ApplicationEventPublisher?
init {
val context = template.converter.mappingContext as MongoMappingContext
val indexCreator = MongoPersistentEntityIndexCreator(context) { collectionName ->
IndexOperationsAdapter.blocking(template.indexOps(collectionName))
}
eventPublisher = MongoMappingEventPublisher(indexCreator)
}
override fun patch(id: String, fields: Map<String, Any>): Mono<ENTITY> {
val collection = entityInformation.collectionName
val query = Query(Criteria.where("_id").`is`(id))
val document = Document()
return findById(id)
.flatMap { entity ->
maybeEmitEvent(BeforeConvertEvent<ENTITY>(entity, collection))
document.putAll(fields)
val update = Update()
fields
.filter { entry ->
!hashSetOf("_id", "createdAt", "createdBy", "modifiedAt", "modifiedBy").contains(entry.key)
}
.forEach { entry -> update.set(entry.key, entry.value) }
maybeEmitEvent(BeforeSaveEvent<ENTITY>(entity, document, collection))
template.updateFirst(query, update, collection)
}
.then(findById(id)).map { entity ->
maybeEmitEvent(AfterSaveEvent<ENTITY>(entity, document, collection))
entity
}
}
private fun <T> maybeEmitEvent(event: MongoMappingEvent<T>) {
eventPublisher?.publishEvent(event)
}
}
最后一部分是通知spring数据。
@Configuration
@EnableReactiveMongoRepositories(
basePackages = ["**.repository"],
repositoryBaseClass = SimpleBaseGenericReactiveMongoRepository::class
)
class MongoConfiguration
现在您可以将该界面用作存储库的基本界面,并拥有适用于您的域的功能。
interface BookRepository : BaseMongoRepository<Book> {
findByNameContainingIgnoreCaseAndVisibileIsTrue(name:String): Flux<Book>
}
如果您需要一个工作示例,欢迎查看我的媒体: