将验证移至 JPQL 查询级别
Posted
技术标签:
【中文标题】将验证移至 JPQL 查询级别【英文标题】:move validation to the JPQL query level 【发布时间】:2021-04-12 12:32:12 【问题描述】:我正在寻找一种将验证方法从服务移动到存储库的方法
一张图片有一个图片数据。
这是方法:
// TODO .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 ();
【问题讨论】:
【参考方案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。但是对于具有逻辑的查询将需要查询注释 看起来不错!可选以上是关于将验证移至 JPQL 查询级别的主要内容,如果未能解决你的问题,请参考以下文章