简体   繁体   English

Spring Hibernate查询与非主键的一对一关系

[英]Spring Hibernate Query One to One relationship with non primary key

I am developing a web application on Spring with Hibernate.我正在使用 Hibernate 在 Spring 上开发 Web 应用程序。

This web application is basically an online commercial website with a number of products under a specific category.此 Web 应用程序基本上是一个在线商业网站,其中包含特定类别下的许多产品。

This application supports multiple languages for a product and different sized pictures for a single product image for the sake of optimization based on different user devices.本应用支持一个产品多种语言,单个产品图片支持不同尺寸的图片,以便根据不同的用户设备进行优化。 Therefore, users can choose in which language they'd like to see the description of products and will get different sized product image according to their device type such as mobile, iPad, desktop.因此,用户可以根据自己的设备类型(例如移动设备、iPad、桌面设备)选择他们希望使用的语言来查看产品描述,并会获得不同尺寸的产品图像。

So, I have six tables at the moment as shown below.所以,我现在有六个表,如下所示。

在此处输入图片说明

The product table contains products as shown产品表包含如图所示的产品

在此处输入图片说明

The product_info table contains the same description in different languages for a product like English, Spanish, and Korean as shown in the picture below. product_info 表包含不同语言的产品(如英语、西班牙语和韩语)的相同描述,如下图所示。

在此处输入图片说明

The product_image contains relative paths to the different sized images of the same picture for a product as shown in the picture below. product_image 包含产品相同图片的不同尺寸图像的相对路径,如下图所示。

在此处输入图片说明

Let's say that a user requests a list of products under category_id = 1 (Furniture), support_language_id = 1 (English), and device_type_id = 1 (mobile).假设用户请求 category_id = 1(家具)、support_language_id = 1(英语)和 device_type_id = 1(移动)下的产品列表。 Then, I'd like to query something like the following, but in HQL.然后,我想查询如下内容,但使用 HQL。

Select * from product pr
left join product_info pf
on p.id = pf.product_id
left join product_image pi
on p.id = pi.product_id
where category_id = category_id of user choice
and support_language_id = support_language_id of user choice
and device_type_id = device_type_id of user device

When I execute this HQL query, I expect to get a list of product objects with each product object having only one product_info object and only one product_image object based on user-selected category_id, support_language_id, and device_type_id.当我执行这个 HQL 查询时,我希望得到一个产品对象列表,每个产品对象只有一个 product_info 对象和一个 product_image 对象,基于用户选择的 category_id、support_language_id 和 device_type_id。

Following the example above, I will get a product object with id = 1 because there is only one object with category_id = 1. Then, the products object will have product_info object with id = 1 and product_image object with id = 1.按照上面的例子,我将得到一个 id = 1 的产品对象,因为只有一个 category_id = 1 的对象。然后,products 对象将有 id = 1 的 product_info 对象和 id = 1 的 product_image 对象。

How can I implement this relationship into JPA with Hibernate?如何使用 Hibernate 在 JPA 中实现这种关系?

I've tried this and that way but end up having errors like binding with non-primary key or others.我已经尝试过这种方式,但最终会出现错误,例如与非主键或其他键绑定。 So I am wondering if my database design has a structural problem in the first place.所以我首先想知道我的数据库设计是否存在结构问题。

Can you guys provide me a full working code example with all those JPA annotations like @JoinColumn, @OneToMany, @OneToOne and so on considered, please?你们能给我提供一个完整的工作代码示例,其中包含所有这些 JPA 注释,例如 @JoinColumn、@OneToMany、@OneToOne 等等,好吗?

You can change, add, and remove columns or tables as long as I can have the desired result.只要可以获得所需的结果,您就可以更改、添加和删除列或表。

这里有一个不使用注解,只使用hql的解决方案,不知道能不能满足你。

select p from Product p,ProductInfo pf,ProductImage pi where p.id = pf.productId and p.id = pi.productId and...

Easy, assuming you don't have a 10 year old version of JPA then you can create two interfaces (repositories in this case) and name the methods as the JPA naming convention says.很简单,假设您没有 10 年前的 JPA 版本,那么您可以创建两个接口(在本例中为存储库)并按照 JPA 命名约定命名方法。 This means that if you have a class ProductInfo so defined:这意味着,如果您定义了一个 ProductInfo 类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductInfo {

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

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id")
    private Product product;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "language_id")
    private Language language;

    private String description;

}

This will be its respective Repository method you will need, and yes, you will need to pass the entire Product if you want to make it clean and simple.这将是您需要的相应 Repository 方法,是的,如果您想让它干净和简单,您将需要传递整个产品。

 @Repository
 public interface ProductImageRepository extends JpaRepository<ProductImage, Long> {

    public Optional<ProductImage> findByProductAndDevice(Product product, Device device);

}

Same goes for the ProductImage ProductImage 也是如此

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductImage {

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

    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "device_id")
    private Device device;

    private String image;

}

Whose repository method will be谁的存储库方法将是

@Repository
public interface ProductImageRepository extends JpaRepository<ProductImage, Long> {

    public Optional<ProductImage> findByProductAndDevice(Product product, Device device);

}

Then you would want something to contain the product info然后你会想要一些包含产品信息的东西

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductToDisplay {

    private Product product;
    private String description;
    private String imageLocation;
}

And a service to then create that object based on the info you have然后根据您拥有的信息创建该对象的服务

@Service
public class ProductToDisplayService {

    @Autowired
    private ProductInfoRepository productInfoRepository;
    @Autowired
    private ProductImageRepository productImageRepository;

    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private DeviceRepository deviceRepository;
    @Autowired
    private LanguageRepository languageRepository;

    public ProductToDisplay getProduct(long productID, long languageID, long deviceID) throws Exception {
        Product product =
                productRepository.findById(productID).orElseThrow(()-> new Exception(
                        "There is no such product"));

        return new ProductToDisplay(product,
                productInfoRepository.findByProductAndLanguage(product,
                        languageRepository.findById(languageID).orElseThrow(()-> new Exception(
                                "There is no such product"))).orElseThrow(()-> new Exception(
                        "There is no such product info")).getDescription(),
                productImageRepository.findByProductAndDevice(product,
                        deviceRepository.findById(deviceID).orElseThrow(()-> new Exception(
                                "There is no such product"))).orElseThrow(()-> new Exception(
                        "There is no such product Image")).getImage());
    }
}

Which might seem a little bit confusing here and I'm sorry about that but this is a little bit more clear这可能看起来有点令人困惑,对此我很抱歉,但这更清楚一点

public ProductToDisplay getProductClear(long productID, long languageID,
                                     long deviceID) throws Exception {
    Product product =
            productRepository.findById(productID).orElseThrow(()-> new Exception(
                    "There is no such product"));

    Language language = languageRepository.findById(languageID).orElseThrow(()-> new Exception(
            "There is no such language"));
    ProductInfo prodInfo = productInfoRepository.findByProductAndLanguage(product, language)
            .orElseThrow(()-> new Exception(
            "There is no such product info"));

    Device device =  deviceRepository.findById(deviceID).orElseThrow(()-> new Exception(
            "There is no such image"));
    ProductImage prodImg = productImageRepository.findByProductAndDevice(product, device)
            .orElseThrow(()-> new Exception(
            "There is no such product Image"));

    return new ProductToDisplay(product,
            prodInfo.getDescription(), prodImg.getImage());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在非主键上使用休眠注释设置单向一对一关系? - how to set unidirectional one-to-one relationship using hibernate annotation on a non-primary key? 没有主键或连接表的休眠多对一关系 - Hibernate Many-To-One Relationship without Primary Key or Join Table 关系非主键@OneToOne Hibernate JPA - relationship non primary key @OneToOne Hibernate JPA Hibernate:在非主键列上一对多映射 - Hibernate: Mapping with one-to-many on non-primary-key columns 如何确保 hibernate 5 在与共享主键的一对一关系中以正确的顺序持续存在 - How to make sure hibernate 5 persists in the correct order in a one-to-one relationship with shared primary key 如何在不通过休眠中的共享主键以一对一关系插入子对象的情况下保存父实体? - How to save parent entity without inserting child in one to one relationship by shared primary key in hibernate? 如何正确级联在Hibernate 3.6中保存主键上的一对一双向关系 - How do I properly cascade save a one-to-one, bidirectional relationship on primary key in Hibernate 3.6 一对一关系中的外键Hibernate - Foreign Key in One to One RelationShip Hibernate Spring 引导数据 JPA:与共享主键的一对一关系 - Spring Boot Data JPA: One-to-One Relationship with Shared Primary Key Hibernate查询一对一关系 - Hibernate query one-to-one relationship
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM