NHibernate插入子查询

3

我有一个表格结构:

------------------------------------------------
|  id  |daily_index|monthly_index|   created   |
------------------------------------------------
| GUID |     1     |      1      |  10-12-2014 |
| GUID |     2     |      2      |  10-12-2014 |
| GUID |     1     |      3      |  11-12-2014 |
| GUID |     1     |      1      |  01-01-2015 |
------------------------------------------------

我的目标是拥有一个交易对象,其代码格式灵活自然,例如

INV-{daily_index}/{month_in_roman}/{year_in_roman}/{monthly_index}

或者

INV{ddmmyyyyhhiiss}-{monthly_index}-{daily_index}

或者用户希望的任何格式。
该类将具有一个Code属性,用于将这些私有字段编织在一起,仅供UI使用。
在纯mysql查询中,我会这样做: INSERT INTO transaction VALUES (// Some GUID, (SELECT COUNT(*) + 1 FROM transaction WHERE DATE(created) = DATE(NOW)), (SELECT COUNT(*) + 1 FROM transaction WHERE MONTH(created) = MONTH(NOW)), NOW()); 我的问题是是否有一种方法可以在NHibernate中重现这种INSERT机制?
我考虑了另一种选择,即使用COUNT查询进行SELECT查询,但我不知道是否可以在NHibernate中实现。
另一个选择是制作一个MySQL触发器,但我很想知道是否可以直接在我的项目中完成这个操作。
2个回答

2
NHibernate提供覆盖默认插入语句的选项:sql-insert
使用此元素在映射文件中,您可以像这样更改插入/更新语句:
<class name="Student">
  <id name="Id" type="Int32">
    <generator class="assigned" />
  </id>
  <property name="Code" length="2000" />

  <many-to-one name="Class" column="ClassId" not-null="true"/>
  <sql-insert>insert into Student (Code, ClassId, Id) values (UPPER(?), ? , ?)</sql-insert>
</class>

当然,您还需要自定义sql-update。确定每个列的正确位置有些棘手。这是来自NH文档的内容:

您可以通过启用NHibernate.Persister.Entity级别的调试日志来查看预期顺序。启用此级别后,NHibernate将打印用于创建、更新、删除等实体的静态SQL。(要查看预期顺序,请记住不要在映射文件中包含自定义SQL,因为这将覆盖NHibernate生成的静态SQL。)

参考: 自定义创建、更新和删除的SQL

1

这就是我喜欢 NHibernate 的原因...即使这里有一个解决方案。我们需要的是:

13.3. DML 操作

小引用:

正如已经讨论过的那样,自动和透明的对象/关系映射涉及到对象状态的管理。这意味着对象状态在内存中可用,因此直接在数据库中操作(使用 SQL 数据操作语言(DML)语句:INSERT、UPDATE、DELETE)数据将不会影响内存状态。但是,NHibernate 提供了通过 Hibernate 查询语言(HQL)执行批量 SQL 风格的 DML 语句的方法。

关于 INSERT (小摘录)

INSERT 语句的伪语法为:INSERT INTO 实体名称 属性列表 select_statement。需注意以下几点:

  • 仅支持 INSERT INTO ... SELECT ... 表单;不支持 INSERT INTO ... VALUES ... 表单。
  • properties_list类似于SQL INSERT语句中的列规范。对于涉及映射继承的实体,只能在该给定类级别上直接定义的属性可用于properties_list中。不允许使用超类属性;子类属性没有意义。换句话说,INSERT语句本质上是非多态的。
  • ...

来自文档的示例:

ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();

var hqlInsert = "insert into DelinquentAccount (id, name) " + 
                " select c.id, c.name from Customer c where ...";
int createdEntities = s.CreateQuery( hqlInsert )
        .ExecuteUpdate();
tx.Commit();
session.Close();

解决方案

有了这个,我们可以创建类似于下面的选择:

var hqlSelect = 

// HQL select clause
" SELECT " +
// guid on the DB side
"  UUID(), " +
// this will return matches for today only
"  CAST(SUM(CASE WHEN DAY(created)=DAY(CURRENT_TIMESTAMP) THEN 1 ELSE 0 END) as int),"+
// this will return matches for this month - see WHERE
"  CAST(Count(*) as int)," +
// the time stamp into created
"   CAST(CURRENT_TIMESTAMP as DateTime)" +

// From means - from some entity (the transaction here)
" FROM transaction" +

// Where is here restricting current month
// here we filter just this year and this month records
"   WHERE MONTH(created) = MONTH(CURRENT_TIMESTAMP)  " +
"     AND  YEAR(created) =  YEAR(CURRENT_TIMESTAMP)  ";

这将是完整的插入。
var hqlInsert = "INSERT INTO AuditLog (id, daily_index, monthly_index, created ) " 
              + hqlSelect; // the above select

这将按预期执行:

ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();

var hqlInsert = ... // see code above to create DML HQL
int createdEntities = session
     .CreateQuery( hqlInsert )
     .ExecuteUpdate();
tx.Commit();
session.Close();

只是一个小注释,但是非常重要。除了使用SELECT进行INSERT之外的任何其他解决方案,在数据库端计算所有内容的情况下,可能会导致意想不到的问题。查看此问答以获取一些关于如果使用其他类型的INSERT可能会发生什么的想法,即我们按照上述描述执行:https://dev59.com/SXnZa4cB1Zd3GeqPqXm9(在C#中计算内容并且稍后进行INSERT时出现的问题) - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接