使用MappedSuperclass和子类

时间:2015-04-30 19:31:34

标签: java spring spring-boot spring-data spring-data-jpa

这是一个简化的工作代码。有一个映射的超类和两个子类(在现实生活中,超类当然包含更多的字段)

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的一些变体,但似乎在这种情况下不起作用。或者我可能完全错了。

1 个答案:

答案 0 :(得分:1)

我发现至少有一个与类的泛型定义相关的失败。 CatRepositoryImpl类扩展了没有任何泛型类型的classe AnimalRepositoryImpl。 (请参阅帖子的以下两个代码段)

public class CatRepositoryImpl extends AnimalRepositoryImpl implements CatRepositoryCustom {

}

public class AnimalRepositoryImpl<T extends Animal> {

}

在我看来应该是这样的。

public class CatRepositoryImpl extends AnimalRepositoryImpl<Cat> implements CatRepositoryCustom {

}

除此之外,我会避免在Repository类中执行与逻辑相关的事情并将其移至服务级别。