具有 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;

AnimalRepositoryImplAnimalRepository 包含一些用于 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 计数器

Doctrine 不会生成继承类的属性

@MappedSuperclass 使用 EclipseLink 和多个 jar 进行静态编织

@MappedSuperclass注解的使用说明

@MappedSuperclass的用法

BaseEntity实体的继承:@MappedSuperclass