具有 MappedSuperclass 和子类的 Spring Data 存储库的 Spring Boot 自定义实现
Posted
技术标签:
【中文标题】具有 MappedSuperclass 和子类的 Spring Data 存储库的 Spring Boot 自定义实现【英文标题】:Spring Boot custom implementations for Spring Data repositories with MappedSuperclass and subclasses 【发布时间】:2015-07-10 15:46:51 【问题描述】:这是一个简化的工作代码。有一个映射的超类和两个它的子类(在现实生活中超类当然包含更多字段)
Animal.java
@MappedSuperclass
@lombok.NoArgsConstructor
@lombok.RequiredArgsConstructor
public abstract class Animal
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@lombok.Getter
private Long id;
@lombok.Getter
@lombok.NonNull
private String name;
Cat.java
@Entity
@Table
@lombok.NoArgsConstructor
public class Cat extends Animal
public Cat(Integer weight, String name)
super(name);
this.weight = weight;
@lombok.Getter
private Integer weight;
Dog.java
@Entity
@Table
@lombok.NoArgsConstructor
public class Dog extends Animal
public Dog(Integer age, String name)
super(name);
this.age = age;
@lombok.Getter
private Integer age;
AnimalRepositoryImpl
和 AnimalRepository
包含一些用于 Cat 和 Dog 存储库的共享代码。
AnimalRepository.java
@NoRepositoryBean
public interface AnimalRepository<T extends Animal> extends JpaRepository<T, Long>
List<T> findAllByName(String name);
AnimalRepositoryImpl.java
public class AnimalRepositoryImpl<T extends Animal>
@Autowired
AnimalRepository<T> animalRepository;
public List<T> findAllBySomeLogic()
return animalRepository.findAll().stream().filter(animal -> !animal.getName().startsWith("Z")).collect(Collectors.toList());
现在我可以添加所有 CatRepositories 并且它仍然可以工作(并且可以正常工作)。
CatRepository.java
@Transactional
public interface CatRepository extends AnimalRepository<Cat>, CatRepositoryCustom
CatRepositoryCustom.java
public interface CatRepositoryCustom
public List<Cat> findAllBySomeLogic();
CatRepositoryImpl.java
public class CatRepositoryImpl extends AnimalRepositoryImpl implements CatRepositoryCustom
这是一个仍然只使用 cat 存储库的测试类。
AnimalRepositoryTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@ActiveProfiles(profiles = "test")
public class AnimalRepositoryTest
@After
public void tearDown()
catRepository.deleteAll();
@Autowired
private CatRepository catRepository;
@Test
public void shouldFindAllBySomeLogic()
// given
catRepository.save(Lists.newArrayList(new Cat(2000, "Luna"), new Cat(2500, "Zoe"), new Cat(1800, "Toby")));
// when
List<Cat> cats = catRepository.findAllBySomeLogic();
// then
assertThat(cats.stream().map(c -> c.getName()).collect(Collectors.toList()), containsInAnyOrder("Luna", "Toby"));
@Test
public void shouldFindAllByName()
// given
catRepository.save(Lists.newArrayList(new Cat(2000, "Luna"), new Cat(2500, "Zoe"), new Cat(1800, "Toby")));
// when
List<Cat> cats = catRepository.findAllByName("Luna");
// then
assertThat(cats.stream().map(c -> c.getName()).collect(Collectors.toList()), containsInAnyOrder("Luna"));
我的编码方式主要是受到this question 的启发(但我的情况更复杂)。
所以...主要问题。 - 如何为Dog
添加存储库(几乎与Cat
相同)而不是获得类似NoUniqueBeanDefinitionException: No qualifying bean of type...
的东西?我已经尝试了@Qualifier
的一些变化,但似乎在这种情况下不起作用。或者我做错了。
【问题讨论】:
你真的需要这个例子的 impl 类吗(即是为了演示问题)? @chuchikaeschtli 是的,我愿意。当然,findAllBySomeLogic()
方法的逻辑可以很容易地通过一个简单的查询来实现——这只是一个例子。但在现实生活中,需要为一些复杂的存储库方法提供自定义实现。
【参考方案1】:
我看到至少一个与您的类的通用定义有关的失败。 CatRepositoryImpl 类扩展了 AnimalRepositoryImpl 类,没有任何泛型类型。 (看你帖子的下面两个代码sn-ps)
public class CatRepositoryImpl extends AnimalRepositoryImpl implements CatRepositoryCustom
public class AnimalRepositoryImpl<T extends Animal>
在我看来应该是这样的。
public class CatRepositoryImpl extends AnimalRepositoryImpl<Cat> implements CatRepositoryCustom
除此之外,我会避免在 Repository 类中做与逻辑相关的事情,并将其移至服务级别。
【讨论】:
以上是关于具有 MappedSuperclass 和子类的 Spring Data 存储库的 Spring Boot 自定义实现的主要内容,如果未能解决你的问题,请参考以下文章
JPA @MappedSuperclass 子类的不同 Id 计数器