Jpa 从POJO 转换成表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jpa 从POJO 转换成表相关的知识,希望对你有一定的参考价值。

我们原来是先建表 然后通过myeclipse 转换为POJO 和配置文件

但是我现在想要的是 如何先写POJO 然后 通过某种方法转为一张表

求高手回答
QQ48187537

Hiberate.cfg.xml配置文件里面 加一条语句:位置<session-factory>
语句:<property name="hbm2ddl.auto">update</property>
</session-facotry>

参考资料:没有参考资料

参考技术A 关注

Spring Data JPA 将原生查询结果映射到非实体 POJO

【中文标题】Spring Data JPA 将原生查询结果映射到非实体 POJO【英文标题】:Spring Data JPA map the native query result to Non-Entity POJO 【发布时间】:2015-05-18 22:00:28 【问题描述】:

我有一个带有本机查询的 Spring Data 存储库方法

@Query(value = "SELECT g.*, gm.* FROM group g LEFT JOIN group_members gm ON g.group_id = gm.group_id and gm.user_id = :userId WHERE g.group_id = :groupId", nativeQuery = true)
GroupDetails getGroupDetails(@Param("userId") Integer userId, @Param("groupId") Integer groupId);

我想将结果映射到非实体 POJO GroupDetails

有可能吗,如果可以,能否举个例子?

【问题讨论】:

【参考方案1】:

我认为最简单的方法是使用所谓的投影。它可以将查询结果映射到接口。使用SqlResultSetMapping 很不方便,而且会让你的代码变得丑陋:)。

来自 Spring Data JPA 源代码的示例:

public interface UserRepository extends JpaRepository<User, Integer> 

   @Query(value = "SELECT firstname, lastname FROM SD_User WHERE id = ?1", nativeQuery = true)
   NameOnly findByNativeQuery(Integer id);

   public static interface NameOnly 

     String getFirstname();

     String getLastname();

  

您也可以使用此方法获取投影列表。

Check out this spring data JPA docs entry for more info about projections.

注 1:

请记住将您的User 实体定义为正常 - 投影接口中的字段必须与该实体中的字段匹配。否则字段映射可能会被破坏(getFirstname() 可能会返回姓氏等值)。

注2:

如果您使用SELECT table.column ... 表示法,请始终定义与实体名称匹配的别名。例如,此代码将无法正常工作(投影将为每个 getter 返回空值):

@Query(value = "SELECT user.firstname, user.lastname FROM SD_User user WHERE id = ?1", nativeQuery = true)
NameOnly findByNativeQuery(Integer id);

但这很好用:

@Query(value = "SELECT user.firstname AS firstname, user.lastname AS lastname FROM SD_User user WHERE id = ?1", nativeQuery = true)
NameOnly findByNativeQuery(Integer id);

如果有更复杂的查询,我宁愿使用 JdbcTemplate 和自定义存储库。

【讨论】:

这是一个更清洁的解决方案。我已经检查过,但性能比使用 SqlResultSetMapping 差得多(它慢了大约 30-40% :( ) 效果很好!如果您想在其他地方使用该界面,请将其公开 如果要提取 XML 类型 (clob) 字段,则不起作用。有什么建议吗? @Ashish 我宁愿使用JdbcTemplate (docs.spring.io/spring-framework/docs/current/javadoc-api/org/…)。您可以在 resultSet 上使用 getClob 方法来获取 clob InputStream。例如:rs.getClob("xml_column").getCharacterStream(). @SalmanKazmi 我什至不会考虑这样做,因为如果数据库中的表发生更改,您的视图对象也必须更改,因此维护此投影将是一个地狱。但是如果投影中的字段与接口/dto中的字段相同,它应该可以工作。【参考方案2】:

假设 GroupDetails 与 orid 的答案相同,您是否尝试过 JPA 2.1 @ConstructorResult?

@SqlResultSetMapping(
    name="groupDetailsMapping",
    classes=
        @ConstructorResult(
            targetClass=GroupDetails.class,
            columns=
                @ColumnResult(name="GROUP_ID"),
                @ColumnResult(name="USER_ID")
            
        )
    
)

@NamedNativeQuery(name="getGroupDetails", query="SELECT g.*, gm.* FROM group g LEFT JOIN group_members gm ON g.group_id = gm.group_id and gm.user_id = :userId WHERE g.group_id = :groupId", resultSetMapping="groupDetailsMapping")

并在存储库界面中使用以下内容:

GroupDetails getGroupDetails(@Param("userId") Integer userId, @Param("groupId") Integer groupId);

根据 Spring Data JPA documentation,spring 将首先尝试查找与您的方法名称匹配的命名查询 - 因此通过使用 @NamedNativeQuery@SqlResultSetMapping@ConstructorResult,您应该能够实现该行为

【讨论】:

为了让spring数据能够匹配到NamedNativeQuery,域实体的Class名后跟一个点,需要在NamedNativeQuery的名字前面加上前缀。所以名字应该是(假设域实体是Group)'Group.getGroupDetails'。 如何返回此类对象的列表? 要让它工作,GroupDetails 应该用@Entity 标记吗?如果可能的话,你能告诉哪个类注释@NamedNativeQuery 必须应用? @SqlResultSetMapping@NamedNativeQuery 注释必须存在于 Spring Data 存储库中使用的实体上(例如,对于 public interface CustomRepository extends CrudRepository&lt;CustomEntity, Long&gt;,它是 CustomEntity 类) 别忘了把@Query(nativeQuery = true) 放在GroupDetails getGroupDetails(@Param("userId")...【参考方案3】:

我认为 Michal 的方法更好。但是,还有另一种方法可以从本机查询中获取结果。

@Query(value = "SELECT g.*, gm.* FROM group g LEFT JOIN group_members gm ON g.group_id = gm.group_id and gm.user_id = :userId WHERE g.group_id = :groupId", nativeQuery = true)
String[][] getGroupDetails(@Param("userId") Integer userId, @Param("groupId") Integer groupId);

现在,您可以将此二维字符串数组转换为您想要的实体。

【讨论】:

简约优雅 如何将二维数组转换为类? 这太冒险了。如果表中的列顺序发生更改(例如 - 添加了新列,或修改了现有列),则结果值将能够混合。例如。如果您的实体有 ClientId 字段,但列从 client_id 更改为 user_id 则很难检测到此更改,因为缺少列名验证。【参考方案4】:

您可以按照自己的方式编写本机或非本机查询,并且可以使用自定义结果类的实例来包装 JPQL 查询结果。 使用查询中返回的列的相同名称创建 DTO,并创建具有与查询返回的相同序列和名称的全参数构造函数。 然后使用以下方式查询数据库。

@Query("SELECT NEW example.CountryAndCapital(c.name, c.capital.name) FROM Country AS c")

创建 DTO:

package example;

public class CountryAndCapital 
    public String countryName;
    public String capitalName;

    public CountryAndCapital(String countryName, String capitalName) 
        this.countryName = countryName;
        this.capitalName = capitalName;
    

【讨论】:

更正:相同的名称不是强制性的...只是构造函数中的参数序列和返回的结果集相同。 仅当 Country 是您的 java 实体类时才有效。如果 Country 不是您的 java 实体类,则不会。 你说这也适用于原生查询?你能举个例子吗? OP 要求本地查询,但给出的示例是非本地查询【参考方案5】:

使用接口中的默认方法,获取EntityManager,获得设置ResultTransformer的机会,然后就可以返回纯POJO了,像这样:

final String sql = "SELECT g.*, gm.* FROM group g LEFT JOIN group_members gm ON g.group_id = gm.group_id and gm.user_id = ? WHERE g.group_id = ?";
default GroupDetails getGroupDetails(Integer userId, Integer groupId) 
    return BaseRepository.getInstance().uniqueResult(sql, GroupDetails.class, userId, groupId);

BaseRepository.java 是这样的:

@PersistenceContext
public EntityManager em;

public <T> T uniqueResult(String sql, Class<T> dto, Object... params) 
    Session session = em.unwrap(Session.class);
    NativeQuery q = session.createSQLQuery(sql);
    if(params!=null)
        for(int i=0,len=params.length;i<len;i++)
            Object param=params[i];
            q.setParameter(i+1, param);
        
    
    q.setResultTransformer(Transformers.aliasToBean(dto));
    return (T) q.uniqueResult();

此解决方案不会影响存储库接口文件中的任何其他方法。

【讨论】:

【参考方案6】:

使用 JPA 投影 在您的情况下,可能需要将数据检索为自定义类型的对象。这些类型反映了根类的部分视图,只包含我们关心的属性。这就是预测派上用场的地方。 首先将Entity声明为@immutable

@Entity
@Immutable

公开课地址

@Id
private Long id;

设置您的存储库

public interface AddressView 
    String getZipCode();

然后在存储库界面中使用它:

public interface AddressRepository extends Repository<Address, Long> 
      @Query("EXEC SP_GETCODE ?1")
    List<AddressView> getAddressByState(String state);

【讨论】:

【参考方案7】:

你可以这样做

@NamedQuery(name="IssueDescriptor.findByIssueDescriptorId" ,

    query=" select new com.test.live.dto.IssuesDto (idc.id, dep.department, iss.issueName, 
               cat.issueCategory, idc.issueDescriptor, idc.description) 
            from Department dep 
            inner join dep.issues iss 
            inner join iss.category cat 
            inner join cat.issueDescriptor idc 
            where idc.id in(?1)")

而且必须有像构造函数这样的

public IssuesDto(long id, String department, String issueName, String issueCategory, String issueDescriptor,
            String description) 
        super();
        this.id = id;
        this.department = department;
        this.issueName = issueName;
        this.issueCategory = issueCategory;
        this.issueDescriptor = issueDescriptor;
        this.description = description;
    

【讨论】:

问题是关于原生查询,而不是用 HQL 编写的查询。

以上是关于Jpa 从POJO 转换成表的主要内容,如果未能解决你的问题,请参考以下文章

JPA:如何将原生查询结果集转换为 POJO 类集合

sql server 使用外连接结果转换成表格式

Spring:JPA 将原生 SQL 转换为非实体 pojo

1.18.2.8与DataStream和DataSet API结合,Scala隐式转换,通过DataSet或DataStream创建视图,将DataStream或DataSet转换成表 等

r语言 怎样将数据框转换成表

sql把字符数组转换成表 :把字符串1,2,3变成表里的行数据