使用QueryOver <t>()方法</t>更新N列圆柱的N-1列

时间:2012-06-24 07:13:31

标签: c# nhibernate queryover

我想只使用NHibernate QueryOver语法更新包含N列的表中的N-1列的一些列。

我尝试的查询是这样的。

    public T UpdatePost(Object DateUpdated, object DateExpires, object Id)
    {
        using (var session=sessionFactory.OpenSession())
        {
            using (var transaction=session.BeginTransaction())
            {
                session.Update(DateUpdated, Id);
                session.Update(DateExpires, Id);
                transaction.Commit();
                return session.Get<T>(Id);
            }
        }
    }

调用方法是

obj.UpdatePost(DateTime.Now, DateTime.Now.AddDays(30), 3);

错误是

  

您的映射存在问题。您可能正在尝试将System.ValueType映射到NHibernate不允许的地方,或者您错误地使用映射到a的IDictionary。 ValueType(System.DateTime)不能与IdentityKey一起使用。

如何实现这一目标?

2 个答案:

答案 0 :(得分:2)

您的UpdatePost方法毫无意义。 NHibernate的session.Update期望一个应该更新的实体对象。您尝试使用的重载文档是:

  

更新与给定标识符关联的持久状态。

第一个参数应该是整个实体对象。

如果您尝试分析代码,NHibernate无法知道您要更新哪个实体。 Update方法不是通用的,Session也不是。你只是想给它一个日期值和一个id。 NHibernate将如何知道要更新哪个表和哪个列?

为了使用NHibernate进行部分更新,您需要使用HQL update queries(DML样式的操作)。

以下是您的情况:

public T UpdatePost(Object DateUpdated, object DateExpires, object Id)
{
    using (var session=sessionFactory.OpenSession())
    {
        using (var transaction=session.BeginTransaction())
        {
            string hqlUpdate = 
                 "update Post p set p.DateUpdated = :dateUpdated, p.DateExpires = :dateExpires where p.id = :id";
            session.CreateQuery(hqlUpdate)
                   .SetDateTime("dateUpdated", DateUpdated)
                   .SetDateTime("dateExpires", DateExpires)
                   .SetParameter("id", Id)
                   .ExecuteUpdate();
            transaction.Commit();
            return session.Get<T>(Id);
        }
    }
}

另外,由于您在更新后已经获得了实体,因此您可以先加载实体,更改其属性并保存。您仍然可以进行两次数据库操作。

public T UpdatePost(DateTime DateUpdated, DateTime DateExpires, object Id)
{
    using (var session=sessionFactory.OpenSession())
    {
        using (var transaction=session.BeginTransaction())
        {
            T post = session.Get<T>(Id);
            post.DateUpdated = DateUpdated;
            post.DateExpires = DateExpires;
            session.Update(post);
            transaction.Commit();
            return post;
        }
    }
}

如果确实想强制NHibernate仅更新已更改的列,则可以在class mapping declaration中指定dynamic-update =“true”。

  

dynamic-update(可选,默认为false):指定应在运行时生成UPDATE SQL,并且仅包含值已更改的列。

答案 1 :(得分:0)

这将是最佳解决方案,因为SetDateTime仅接受DateTime类型作为其参数值。虽然一般地声明这种方法,但我们必须根据其实体类型格式化查询。

public T UpdatePost(DateTime DateUpdated, DateTime DateExpires, object Id) <-- DateTime parameters
        {
            using (var session = sessionFactory.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    string hqlUpdate = string.Format(
                 "update {0} p set p.DateUpdated = :dateUpdated, p.DateExpires = :dateExpires where p.id = :id", typeof(T)); <-- passing the type of the entity.
                    session.CreateQuery(hqlUpdate)
                           .SetDateTime("dateUpdated",DateUpdated)
                           .SetDateTime("dateExpires", DateExpires)
                           .SetParameter("id", Id)
                           .ExecuteUpdate();
                    transaction.Commit();
                    return session.Get<T>(Id);
                }
            }
        }