【问题标题】:move validation to the JPQL query level将验证移至 JPQL 查询级别
【发布时间】:2021-04-12 12:32:12
【问题描述】:

我正在寻找一种将验证方法从服务移动到存储库的方法

一张图片有一个图片数据。

这是方法:

// TODO 将验证移至 JPQL 查询级别 .filter(pic -> pic.getPictureData().getFileName() != null)

这是我的服务

@Service
@ConditionalOnProperty(name = "picture.storage.type", havingValue = "file")
public class PictureServiceFileImpl implements PictureService {

    private static final Logger logger = LoggerFactory.getLogger(PictureServiceFileImpl.class);

    @Value("${picture.storage.path}")
    private String storagePath;

    private final PictureRepository repository;

    @Autowired
    public PictureServiceFileImpl(PictureRepository repository) {
        this.repository = repository;
    }

    @Override
    public Optional<String> getPictureContentTypeById(long id) {
        return repository.findById(id)
                // TODO move validation to the JPQL query level
                .filter(pic -> pic.getPictureData().getFileName() != null)
                .map(Picture::getContentType);
    }

    @Override
    public Optional<byte[]> getPictureDataById(long id) {
        return repository.findById(id)
                // TODO move validation to the JPQL query level
                .filter(pic -> pic.getPictureData().getFileName() != null)
                .map(pic -> Path.of(storagePath, pic.getPictureData().getFileName()))
                .filter(Files::exists)
                .map(path -> {
                    try {
                        return Files.readAllBytes(path);
                    } catch (IOException ex) {
                        logger.error("Can't open picture file", ex);
                        throw new RuntimeException(ex);
                    }
                });
    }

    @Override
    public PictureData createPictureData(byte[] picture) {
        String fileName = UUID.randomUUID().toString();
        try (OutputStream os = Files.newOutputStream(Path.of(storagePath, fileName))) {
            os.write(picture);
        } catch (IOException ex) {
            logger.error("Can't create picture file", ex);
            throw new RuntimeException(ex);
        }
        return new PictureData(fileName);
    }
}

实体

@Entity
@Table(name = "pictures")
public class Picture {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "content_type", nullable = false)
    private String contentType;

    @OneToOne(fetch = FetchType.LAZY, cascade= CascadeType.ALL, optional = false, orphanRemoval = true)
    @JoinColumn(name="picture_data_id")
    private PictureData pictureData;

    @ManyToOne
    private Product product;

    public Picture() {
    }

    public Picture(String name, String contentType, PictureData pictureData, Product product) {
        this.name = name;
        this.contentType = contentType;
        this.pictureData = pictureData;
        this.product = product;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public PictureData getPictureData() {
        return pictureData;
    }

    public void setPictureData(PictureData pictureData) {
        this.pictureData = pictureData;
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }
}

@Entity
@Table(name = "pictures_data")
public class PictureData {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Lob
    @Type(type="org.hibernate.type.BinaryType") // для правильной работы PostgreSQL
    @Column(name = "data", length = 33554430) // для правильной hibernate-валидации в MySQL
    private byte[] data;

    @Column(name = "file_name")
    private String fileName;

    public PictureData() {
    }

    public PictureData(byte[] data) {
        this.data = data;
    }

    public PictureData(String fileName) {
        this.fileName = fileName;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public byte[] getData() {
        return data;
    }

    public void setData(byte[] data) {
        this.data = data;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }
}

我正在努力让查询在 JPQL 中工作。

public interface PictureRepository extends JpaRepository<Picture, Long> {

    @Query ("SELECT p FROM Picture p JOIN p.pictureData d WHERE d.data  IS NOT NULL ")
    Picture filterPictureWherePictureDataIsNotNull ();
}

【问题讨论】:

    标签: spring jpql


    【解决方案1】:

    既然你已经有实体级join,你可以直接使用下面的方法

    public interface PictureRepository extends JpaRepository<Picture, Long> 
    {
    
        @Query ("SELECT p FROM Picture p WHERE p.pictureData.data  IS NOT NULL ")
        Picture filterPictureWherePictureDataIsNotNull ();
    }
    

    另一个观察结果,

    您的 repo 方法可能会返回图片列表而不是一张图片。因此,理想情况下,返回类型应该是

    @Query ("SELECT p FROM Picture p WHERE p.pictureData.data  IS NOT NULL ")
        List<Picture> filterPictureWherePictureDataIsNotNull ();
    

    【讨论】:

    • 感谢您的回答。我不知道为什么,但是 p.pictureData.data 不起作用。 IntellijIdea 无法解析符号“数据”
    • 嗯。今天一切正常。 Intellij 的一些奇怪行为
    • 不知道是不是一定要用@Query 还是方法名够对了,剩下的就做SpringData?
    • 是的。对于 findByFieldname、existsByFieldName 等基本方法,不需要 @query。但是对于具有逻辑的查询将需要查询注释
    • 看起来不错!可选 findPictureByIdAndPictureData_FileNameIsNotNull(Long id);
    猜你喜欢
    • 2017-11-22
    • 2020-12-03
    • 2018-02-23
    • 2023-03-10
    • 2011-12-10
    • 1970-01-01
    • 2011-11-02
    • 1970-01-01
    • 2013-07-19
    相关资源
    最近更新 更多