JPA 没有主键的数据表,创建实体类,并查询某个字段值最大的那条数据,结果中有大量重复数据

数据表简介:

该数据表用于记录某个设备发送的数据。在该表中,有大量重复的数据,因此,无论给哪个字段添加主键,或者设置联合主键都是不可行的。

codecreateTimeequipNumreqTimewight
83011629788252000SNU2348972021-08-24 15:14:2930
83011629788261000SNU2480932021-08-24 15:22:0322
83011629787680000SNU2348972021-08-24 15:18:1832
83051629787680000GBY2984562021-08-24 15:20:0230
83051629795000000GBY2984562021-08-24 17:18:0130
83021629794700000GBY2984562021-08-24 17:20:0230
83011629794700000SNU2348972021-08-24 17:16:0232
83011629794700000GBY2984562021-08-24 15:18:0230

而Jpa强制实体类中需要有主键。所以就很随便的选了第一个字段,在它上边加了注解@Id

实体类
@Entity
@Table(name = "equip")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Equip{

    @Id
    @Column(name = "code")
	private String code;
    
    @Column(name = "createTime")
	private String createTime;
    
    @Column(name = "equipNum")
	private String equipNum;
    
    @Column(name = "reqTime")
	private String reqTime;
    
    @Column(name = "wight")
	private String wight;

}

业务场景需求:

查询特定时间段内,某个设备(equipNum)最新(createTime)的那条记录。

实现思路:

按createTime范围进行筛选,之后按设备号(equipNum)进行分组,并获得某个设备号所对应的createTime值最大的那条记录

mysql
SELECT DISTINCT
	code,
	createTime,
	equipNum,
	reqTime,
	wight 
FROM
	equip eq
	JOIN (
	SELECT
		max( createTime ) mtime,
		equipNum meq,
		max( reqTime ) mreqt 
	FROM
		equip eq 
	WHERE
		createTime BETWEEN '1629424800000' 
		AND '1629425399999' 
	GROUP BY
		eq.equipNum 
	) AS maxtime ON eq.equipNum = maxtime.meq 
	AND eq.createTime = maxtime.mtime 
	AND eq.reqt = maxtime.mreqt 
ORDER BY
	equipNum;
持久层
@Repository
public interface EquipDao extends JpaRepository<Equip,String>{
    
    @Query(nativeQuery = true, value = "SELECT DISTINCT code,createTime,equipNum,reqTime,wight FROM equip eq JOIN ( SELECT max( createTime ) mtime, equipNum meq, max( reqTime ) mreqt FROM equip eq  WHERE createTime BETWEEN ?1  AND ?2 GROUP BY eq.equipNum ) AS maxtime ON eq.equipNum = maxtime.meq AND eq.createTime = maxtime.mtime AND eq.reqt = maxtime.mreqt ORDER BY equipNum;")
    public List<Equip> findAllByCreateTimeBetween(String startTime, String endTime);
}

问题:

运行后发现,输出的数据好多重复的,但是list.size()的大小和数据库中查的记录条数一致。

问题分析

其实问题是出在实体类中。@Id 这个注解虽然加了,但是我们去查看表结构的时候会发现,code 字段并没有成为主键,当然这也是我当前场景下所希望的结果,不要出现任何主键。然而,加了 @Id 注解的属性,却要临时的担起主键的部分职责,那就是唯一。但很明显,code 字段重复的记录很多,所以在最终的查询结果中,凡是 code 字段的值一样的记录,其他字段的值也都和第一条一样了。

解决
  • 方案1:找个不会重复的字段就可以了。在不会重复的属性上边加上 @Id,如果需要用联合主键的,那么就给多个属性上边加 @Id

    public class Equip{
    
        @Id
        @Column(name = "code")
    	private String code;
        
        @Id
        @Column(name = "createTime")
    	private String createTime;
        
        @Id
        @Column(name = "equipNum")
    	private String equipNum;
        
        @Column(name = "reqTime")
    	private String reqTime;
        
        @Column(name = "wight")
    	private String wight;
    }
    
  • 方案2:然而我这个表实在特殊,无论哪个字段都会重复,甚至会出现两条一模一样的记录,单个主键和联合主键都行不通。
    但是我这儿最终查询的结果,是基于 equipNum 分组的,group by equipNum,也就意味着最终的查询结果里的equipNum是唯一的,那就只需要给 equipNum 属性加上 @Id 注解即可

    public class Equip{
    
        @Column(name = "code")
    	private String code;
        
        @Column(name = "createTime")
    	private String createTime;
        
        @Id //查询结果中equipNum不会重复,所以加在这里
        @Column(name = "equipNum")
    	private String equipNum;
        
        @Column(name = "reqTime")
    	private String reqTime;
        
        @Column(name = "wight")
    	private String wight;
    }
    
测试通过,大功告成
  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以按照以下步骤生成JPA实体类: 1. 定义实体类 首先,在Java Package创建一个新类,该类将成为您的数据表实体类。这个类应该包含所有的字段,以及它们的getter和setter方法。 例如,如果您要创建一个名为“Person”的实体类,可以包含以下字段: ``` @Column(name="id") private Long id; @Column(name="name") private String name; @Column(name="age") private int age; ``` 2. 定义主键JPA,每个实体类都必须有一个主键。您可以使用@Id注解来定义主键字段。 例如: ``` @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="id") private Long id; ``` 这个例子,我们使用@Id注解来标识id字段作为主键,并使用@GeneratedValue注解来指定主键的生成策略。 3. 定义关联关系 如果您的数据表与其他表有关联关系,例如一对多或多对多关系,您需要使用@OneToMany、@ManyToOne或@ManyToMany注解来定义它们。 例如,如果您的Person实体类需要与Address实体类建立一对多关系,可以使用以下代码: ``` @OneToMany(mappedBy = "person", cascade = CascadeType.ALL) private List<Address> addresses; ``` 这个例子,使用@OneToMany注解来定义一对多关系,并使用mappedBy属性来指定关系的反方向属性。 4. 定义其他注解 您还可以使用其他JPA注解来定义实体类,例如@Table、@Column、@Temporal等。 例如,如果您要指定数据表的名称和日期字段的类型,可以使用以下代码: ``` @Entity @Table(name = "person") public class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="id") private Long id; @Column(name="name") private String name; @Column(name="age") private int age; @Temporal(TemporalType.DATE) @Column(name="date_of_birth") private Date dateOfBirth; // ... } ``` 这个例子,我们使用@Entity和@Table注解指定实体类对应的数据表和名称,使用@Temporal注解指定日期字段的类型。 5. 生成数据库表 最后,您可以使用JPA提供的自动创建表功能来生成数据库表。只需在应用程序启动时添加以下代码即可: ``` EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence-unit"); EntityManager em = emf.createEntityManager(); ``` 这个例子,我们使用Persistence.createEntityManagerFactory()方法创建一个EntityManagerFactory对象,并使用它来创建一个EntityManager对象。您可以使用EntityManager对象来执行各种数据库操作,例如插入、更新、删除和查询数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值