Java 使用带有联接的查询填充DTO

Java 使用带有联接的查询填充DTO,java,sql,spring,spring-boot,Java,Sql,Spring,Spring Boot,我有一个主产品表: @Table(name = "product") public class Product implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true, updatable = false, nullable = false) pr

我有一个主
产品
表:

@Table(name = "product")
public class Product implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, updatable = false, nullable = false)
    private int id;

    @Column(name = "user_id", length = 20)
    private Integer userId;

    @Column(name = "title", length = 75)
    private String title;

    @Column(name = "meta_title", length = 100)
    private String metaTitle;

    @Column(name = "status", length = 100)
    private String status;
}
用于存储应作为列表返回的类别的附加表:

@Table(name = "product_category")
public class ProductCategory implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, updatable = false, nullable = false)
    private int id;

    @Column(name = "product_id", length = 4)
    private Integer productId;

    @Column(name = "category_id", length = 20)
    private Integer categoryId;

}
@Table(name = "product_payment_methods")
public class ProductPaymentMethods implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, updatable = false, nullable = false)
    private int id;

    @Column(name = "product_id", length = 20)
    private Integer productId;

    @Column(name = "payment_methods", length = 20000)
    private String paymentMethods;
}
存储应作为列表返回的付款方式的附加表:

@Table(name = "product_category")
public class ProductCategory implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, updatable = false, nullable = false)
    private int id;

    @Column(name = "product_id", length = 4)
    private Integer productId;

    @Column(name = "category_id", length = 20)
    private Integer categoryId;

}
@Table(name = "product_payment_methods")
public class ProductPaymentMethods implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, updatable = false, nullable = false)
    private int id;

    @Column(name = "product_id", length = 20)
    private Integer productId;

    @Column(name = "payment_methods", length = 20000)
    private String paymentMethods;
}
我想返回如下结果:

id | title | categoryId | paymentMethods |
1  | test  |    34, 43  |    345, 7, 5   |
5  | test2 |    64,5, 3 |    654, 3, 5   |
我试过这个:

SELECT *
FROM Product
INNER JOIN product_category ON Product.id = product_category.productId
INNER JOIN product_payment_methods ON Product.id = product_payment_methods.productId
WHERE userId = 1
填充此DTO的正确方式是什么

public class ProductFullDTO {
   private int id;

   private Integer userId;

   private List<Integer> categories;

   private List<String> paymentMethods;
}
公共类ProductFullDTO{
私有int-id;
私有整数用户标识;
私人名单类别;
私人清单支付方式;
}

您应该使用TypeHandler来完成此作业。我只是举个例子

    @Results({
            @Result(column = "product.id", property = "id"),
            @Result(column = "user_id", property = "userId"),
            @Result(column = "category_id", property = "categories"),
            @Result(column = "payment_methods", property = "paymentMethods" ,typeHandler= StrListTypeHandler.class),
    })
    @Select("SELECT * FROM Product INNER JOIN product_category ON Product.id = product_category.productId "
        + " INNER JOIN product_payment_methods ON Product.id = product_payment_methods.productId "
        + " WHERE userId = 1")
    List<ProductFullDTO> getProduct();

// the below is TypeHandler implementation
@Component
public class StrListTypeHandler implements TypeHandler<List<String>> {
    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, List<String> strings, JdbcType jdbcType) throws SQLException {
        StringBuffer sb = new StringBuffer();
        for (String s : strings) {
            sb.append(s).append(",");
        }
        preparedStatement.setString(i, sb.toString().substring(0, sb.toString().length() - 1));
    }

    @Override
    public List<String> getResult(ResultSet resultSet, String s) throws SQLException {
        String[] arr = resultSet.getString(s).split(",");
        return Arrays.asList(arr);
    }

    @Override
    public List<String> getResult(ResultSet resultSet, int i) throws SQLException {
        String[] arr = resultSet.getString(i).split(",");
        return Arrays.asList(arr);
    }

    @Override
    public List<String> getResult(CallableStatement callableStatement, int i) throws SQLException {
        String[] arr = callableStatement.getString(i).split(",");
        return Arrays.asList(arr);
    }
}

@结果({
@结果(column=“product.id”,property=“id”),
@结果(column=“user\u id”,property=“userId”),
@结果(column=“category\u id”,property=“categories”),
@结果(column=“payment\u methods”,property=“paymentMethods”,typeHandler=StrListTypeHandler.class),
})
@选择(“选择*从Product.id上的Product Internal JOIN Product\u category=Product\u category.productId”
+“product.id上的内部联接产品\付款\方法=产品\付款\方法.productId”
+“其中userId=1”)
列出getProduct();
//下面是TypeHandler实现
@组成部分
公共类StrListTypeHandler实现TypeHandler{
@凌驾
public void setParameter(PreparedStatement PreparedStatement,int i,列表字符串,JdbcType JdbcType)抛出SQLException{
StringBuffer sb=新的StringBuffer();
用于(字符串s:字符串){
某人加上(“,”);
}
preparedStatement.setString(i,sb.toString().substring(0,sb.toString().length()-1));
}
@凌驾
公共列表getResult(ResultSet ResultSet,字符串s)引发SQLException{
String[]arr=resultSet.getString.split(“,”);
返回数组.asList(arr);
}
@凌驾
公共列表getResult(ResultSet ResultSet,int i)引发SQLException{
String[]arr=resultSet.getString(i).split(“,”);
返回数组.asList(arr);
}
@凌驾
public List getResult(CallableStatement CallableStatement,int i)抛出SQLException{
String[]arr=callableStatement.getString(i).split(“,”);
返回数组.asList(arr);
}
}

如果如您的评论所示,您需要使用HQL查询您的信息,那么可以通过以下方法继续操作

首先,修改您的
产品
实体,包括
产品类别
产品付款方法
的关系,例如:

@表(name=“product”)
公共类产品实现可序列化{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
@列(name=“id”,unique=true,updateable=false,nullable=false)
私有int-id;
@列(name=“user\u id”,长度=20)
私有整数用户标识;
@列(name=“title”,长度=75)
私有字符串标题;
@列(name=“meta_title”,长度=100)
私有字符串元标题;
@列(name=“status”,长度=100)
私有字符串状态;
@OneToMany(mappedBy=“product”,cascade=CascadeType.ALL,orphan=true)
私人名单类别;
@OneToMany(mappedBy=“product”,cascade=CascadeType.ALL,orphan=true)
私有列表paymentMethods;
//setter和getter,为简洁起见省略
}
修改
ProductCategory
ProductPaymentMethods
以适应实体关系:

@表(name=“产品类别”)
公共类ProductCategory实现可序列化{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
@列(name=“id”,unique=true,updateable=false,nullable=false)
私有int-id;
//请随意将可插入和可更新属性更改为
//适合你的需要
@列(name=“product_id”,长度=4,可插入=false,可更新=false)
私有整数productId;
@manytone(fetch=FetchType.LAZY)
@JoinColumn(name=“产品标识”)
私人产品;
@列(name=“category\u id”,长度=20)
私有整数类别ID;
//setter和getter,为简洁起见省略
}
@表(name=“产品\付款\方式”)
公共类ProductPaymentMethods实现可序列化{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
@列(name=“id”,unique=true,updateable=false,nullable=false)
私有int-id;
//请随意将可插入和可更新属性更改为
//适合你的需要。顺便问一下,为什么这里的长度是20而不是4?
@列(name=“product_id”,长度=20,可插入=false,可更新=false)
私有整数productId;
@manytone(fetch=FetchType.LAZY)
@JoinColumn(name=“产品标识”)
私人产品;
@列(name=“付款方式”,长度=20000)
私有字符串支付方法;
}
使用此设置,正如您在中所看到的-它适用于旧的Hibernate版本,但现在是正确的,您可以使用fetch Join来获取所需的信息:

“fetch”联接允许使用单个select将值的关联或集合与其父对象一起初始化。这在集合的情况下特别有用

对于您的示例,考虑下面的HQL(假设外部联接语义,适当地修改它):

选择产品
从产品到产品
左连接获取产品.categories
left join fetch product.paymentMethods
其中product.userId=1
这将为您提供
userId
1
的产品列表,以及对类别和支付方法的所有相关引用

实体和DTO之间的转换应简单明了:

会话=。。。 列表产品=session.createQuery( “选择产品”+ “从产品到产品”