使用SubQuery的NHibernate插入

时间:2014-12-11 15:14:43

标签: c# mysql .net nhibernate insert

我有一个表结构:

------------------------------------------------
|  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 个答案:

答案 0 :(得分: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。)

参考: Custom SQL for create, update and delete

答案 1 :(得分:1)

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

13.3. DML-style operations

小引用:

  

如前所述,自动和透明的对象/关系映射与对象状态的管理有关。这意味着对象状态在内存中可用,因此直接在数据库中操作(使用SQL数据操作语言(DML)语句:INSERT,UPDATE,DELETE)数据不会影响内存状态。但是,NHibernate提供了通过Hibernate查询语言(HQL)执行批量SQL样式DML语句执行的方法。

关于INSERT (小提取)

  

INSERT语句的伪语法是:INSERT INTO EntityName properties_list select_statement。有些要点需要注意:

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

示例:

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)  ";

这将是COMPLETE插入

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();