Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
IUserType上的NHibernate查询_Nhibernate_Queryover_Iusertype - Fatal编程技术网

IUserType上的NHibernate查询

IUserType上的NHibernate查询,nhibernate,queryover,iusertype,Nhibernate,Queryover,Iusertype,首先让我为这篇文章的篇幅道歉,虽然大部分都是代码,所以我希望你们都能容忍我 我有一个处理遗留数据库的场景,我需要使用NHibernate 3.2编写一个IUserType,以获取一个2个字符的“status”字段并从中返回一个布尔值。状态字段可以包含3个可能的值: * 'DI' // 'Disabled', return false * ' ' // blank or NULL, return true * NULL 以下是我简化的内容 表格定义: CREATE T

首先让我为这篇文章的篇幅道歉,虽然大部分都是代码,所以我希望你们都能容忍我

我有一个处理遗留数据库的场景,我需要使用NHibernate 3.2编写一个IUserType,以获取一个2个字符的“status”字段并从中返回一个布尔值。状态字段可以包含3个可能的值:

* 'DI'     // 'Disabled', return false
* '  '     // blank or NULL, return true
* NULL     
以下是我简化的内容

表格定义:

CREATE TABLE [dbo].[Client](
    [clnID] [int] IDENTITY(1,1) NOT NULL,
    [clnStatus] [char](2) NULL,
    [clnComment] [varchar](250) NULL,
    [clnDescription] [varchar](150) NULL,
    [Version] [int] NOT NULL
)
Fluent映射:

public class ClientMapping : CoreEntityMapping<Client>
{
    public ClientMapping()
    {
        SchemaAction.All().Table("Client");
        LazyLoad();

        Id(x => x.Id, "clnId").GeneratedBy.Identity(); 
        Version(x => x.Version).Column("Version").Generated.Never().UnsavedValue("0").Not.Nullable();
        OptimisticLock.Version();

        Map(x => x.Comment, "clnComment").Length(250).Nullable();
        Map(x => x.Description, "clnDescription").Length(250).Nullable();
        Map(x => x.IsActive, "clnStatus").Nullable().CustomType<StatusToBoolType>();
    }
}
public class StatusToBoolType : IUserType
{
    public bool IsMutable { get { return false; } }
    public Type ReturnedType { get { return typeof(bool); } }
    public SqlType[] SqlTypes { get {  return new[] { NHibernateUtil.String.SqlType }; } }

    public object DeepCopy(object value)
    {
        return value;
    }
    public object Replace(object original, object target, object owner)
    {
        return original;
    }
    public object Assemble(object cached, object owner)
    {
        return cached;
    }
    public object Disassemble(object value)
    {
        return value;
    }

    public new bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
           return x.Equals(y);
    }
    public int GetHashCode(object x)
    {
        return x == null ? typeof(bool).GetHashCode() + 473 : x.GetHashCode();
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);
        if (obj == null) return true;

        var status = (string)obj;
        if (status == "  ") return true;
        if (status == "DI") return false;
        throw new Exception(string.Format("Expected data to be either empty or 'DI' but was '{0}'.", status));
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var parameter = ((IDataParameter) cmd.Parameters[index]);
        var active = value == null || (bool) value;
        if (active)
            parameter.Value = "  ";
        else
            parameter.Value = "DI";
    }
}
然而,这不起作用。此单元测试因计数不准确而失败

[TestMethod]
public void GetAllActiveClientsTest()
{
    //ACT
    var count = Session.QueryOver<Client>()
        .Where(x => x.IsActive)
        .SelectList(l => l.SelectCount(x => x.Id))
        .FutureValue<int>().Value;

    //ASSERT
    Assert.AreNotEqual(0, count);
    Assert.AreEqual(1721, count);
}
但我需要它来生成这个:

SELECT count(this_.clnID) as y0_ FROM Client this_ WHERE (this_.clnstatus = @p0 <b> OR this_.clnstatus IS NULL);</b>
但这是NHibernate!!!像这样攻击sql语句不可能是正确的处理方法吗?对吧?

因为它是一个共享的遗留数据库,所以我不能将表模式更改为NOTNULL,否则我会这样做,并避免这种情况

最后,在所有这些前奏之后,我的问题很简单,我在哪里可以告诉NHibernate为这个IUserType生成一个定制的SQL条件语句

提前谢谢大家

解决了

在我发布了我的问题之后,我回到了绘图板,我提出了一个解决方案,它不需要在IUserType实现中破解生成的SQL。事实上,这个解决方案根本不需要IUserType

这就是我所做的

首先,我更改了IsActive列以使用公式来处理null检查。这修复了我的QueryOver失败的问题,因为现在每次NHibernate处理IsActive属性时,它都会注入我的sql公式来处理null

这种方法的缺点是,在我输入公式后,所有save测试都失败了。事实证明,公式属性实际上是只读属性

为了解决这个问题,我向实体添加了一个受保护的属性,以保存数据库中的状态值

接下来,我更改了IsActive属性,将protectedstatus属性设置为“”或“DI”。最后,我更改了FluentMapping,将受保护状态属性显示给NHibernate,以便NHibernate可以跟踪它。既然NHibernate知道了状态,它就可以将其包含在INSERT/UPDATE语句中

我将在下面列出我的解决方案,以防其他人感兴趣

客户端类

public class Client 
{
    ...

    protected virtual string Status { get; set; }
    private bool _isActive;
    public virtual bool IsActive
    {
        get { return _isActive; }
        set
        {
            _isActive = value;
            Status = (_isActive) ? "  " : "DI";
        }
    }
}
对流畅映射的更改

public class ClientMapping : CoreEntityMapping<Client>
{
    public ClientMapping()
    {
        ....

        Map(Reveal.Member<E>("Status"), colName).Length(2);
        Map(x => x.IsActive).Formula("case when clnStatus is null then '  ' else clnStatus end");
    }
}
public类ClientMapping:CoreEntityMapping
{
公共ClientMapping()
{
....
地图(显示成员(“状态”),colName)。长度(2);
Map(x=>x.IsActive).Formula(“当clnStatus为null时,则为“”否则clnStatus end”);
}
}
public class Client 
{
    ...

    protected virtual string Status { get; set; }
    private bool _isActive;
    public virtual bool IsActive
    {
        get { return _isActive; }
        set
        {
            _isActive = value;
            Status = (_isActive) ? "  " : "DI";
        }
    }
}
public class ClientMapping : CoreEntityMapping<Client>
{
    public ClientMapping()
    {
        ....

        Map(Reveal.Member<E>("Status"), colName).Length(2);
        Map(x => x.IsActive).Formula("case when clnStatus is null then '  ' else clnStatus end");
    }
}