Hibernate sql annotation



我目前正在使用Hibernate与SQL Server 2016/AAzure SQL Server进行接口,到目前为止,我一直在使用它。在我的数据库中,我实现了系统版本的时态表。我想通过仅将注释映射到我的Hibernate实体来映射(最好是惰性地)另外两个变量,该实体表示相应表的时间历史中的原始ValidFrom和UpdatedBy字段。

例如,我有一个Accounts的类和表。Account[减去不相关的列、约束等]表如下:

CREATE TABLE [dbo].[Account] (
[Id]          INT                                         IDENTITY (1, 1) NOT NULL,
[UpdatedBy]   INT                                         NOT NULL,
[ValidFrom]   DATETIME2 (7) GENERATED ALWAYS AS ROW START DEFAULT (sysutcdatetime()) NOT NULL,
[ValidTo]     DATETIME2 (7) GENERATED ALWAYS AS ROW END   DEFAULT (CONVERT([datetime2],'9999-12-31 23:59:59.9999999')) NOT NULL,
CONSTRAINT [FK_Account.UpdatedById_Account.Id] FOREIGN KEY ([UpdatedBy]) REFERENCES [dbo].[Account] ([Id]),
PRIMARY KEY CLUSTERED ([Id] ASC),
PERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo])
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[AccountHistory], DATA_CONSISTENCY_CHECK=ON));

获取我想要的数据的SQL语句如下所示(我想每个注释只选择UpdatedBy或ValidFrom,但为了简洁起见,它们现在放在一起了):

SELECT UpdatedBy, ValidFrom FROM dbo.Account
FOR SYSTEM_TIME ALL
WHERE ValidFrom IN
(
SELECT MIN(ValidFrom) OVER (Partition BY Id) AS ValidFrom
FROM dbo.Account
FOR SYSTEM_TIME ALL
WHERE ID = $(passedInIdOfThisEntity)
)

最后,我的Hibernate实体/pojo看起来是这样的(再次,编辑不相关的变量):

@Entity
@Table(name = "Account")
public class Account implements Serializable {
@Id
@Column(name = "Id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "UpdatedBy")
private Account updatedBy;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "ValidFrom", nullable = false, length = 27, insertable = false, updatable = false)
private Date validFrom;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "ValidTo", nullable = false, length = 27, insertable = false, updatable = false)
private Date validTo;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "updatedBy")
private Set<Account> accountsUpdated;
// This is a stub of what I'm hoping you can help me add
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "ValidFrom", fetch = FetchType.LAZY, insertable = false, updatable = false, somesqlselect = SQL_STATEMENT_FROM_ABOVE)
private Date createdOn;
@Column(name = "UpdatedBy", fetch = FetchType.LAZY, insertable = false, updatable = false, somesqlselect = SQL_STATEMENT_FROM_ABOVE)
private Account createdBy
// ... getters and setters below
}

我已经在很大程度上使用了Hibernate,但在查找这方面的信息时遇到了困难,尽管我已经找到并使用了实现本机查询以检索实体而不是使用标准查询的示例。如果你能帮助我解决这个谜题,让我继续使用条件查询来检索数据,并通过注释按需填充这些字段,我将不胜感激

我知道JPA甚至Hibernate本机都不支持您所描述的时态表结构。这些可能是ANSI SQL标准的新功能,尚未得到适当的支持。

也就是说,这并不意味着你不能使用像Hibernate这样的框架来完成任务。如注释中所示,您可以指定一个命名查询并执行该查询,以获得所需的属性。

从JPA 2.1的角度来看,可以使用@SqlResultSetMapping@ConstructorResult

@SqlResultSetMapping(
name = "Account.getWithTemporalAttributes",
classes = {
@ConstructorResult(
targetClass = com.company.domain.AccountTemporalDetails.class,
columns = {
@ColumnResult(name = "col1"),
@ColumnResult(name = "col2")
})
})

要使用它,您需要执行以下操作:

Query query = entityManager.createNativeQuery( 
"SELECT a.col1 as col1, a.col2 as col2 FROM Account a",
"Account.getWithTemporalAttributes");
List<AccountTemporalDetails> results = query.getResultList();

这应该允许您使用Native SQL查询,将它们映射到POJO,然后您可以在应用程序中轻松使用POJO而无需编写样板文件。@ConstructorResult注释旨在模仿JPQLSELECT NEW语法。因此,您只需要确保AccountTemporalDetails有一个构造函数,该构造函数使用正确的类型接受这些参数。

最新更新