映射和查询UserTypes - DB中的Nullable可以在域中为Nulullable

时间:2011-02-16 00:21:20

标签: c# nhibernate nhibernate-mapping linq-to-nhibernate

我有一个遗留应用程序,数据库中有一个可以为空的DateTime列 - 一个NULL值用于表示+ Infinity。我的应用程序使用相当标准的NHibernate + DDD设置,包括Fluent-NHibernate和Linq2NHib。

假设我有以下代表实体的C#类。

class Discount
{
    DateTime? ExpirationDate { get; set; }
    // ... etc.
}

事实证明,我想要封装的ExpirationDate管理规则,例如,它必须在午夜,并且可以具有值Infinity。在遗留应用NULL == Infinity中,就像在数据库中一样。我想将它转换为更像这组类的东西:

class Discount
{
    OpenBusinessDate ExpirationDate { get; set; } // assume not nullable
}

class OpenBusinessDate // immutable
{
    private DateTime _Value;
    private bool _IsInfinity;

    OpenBusinessDate(DateTime? value)
    {
        if (null == value)
        {
            _IsInfinity = true;
            _Value = DateTime.MaxValue; // or SqlDateTime.MaxValue if you must
        }
        else
        {
            ErrorIfNotMidnight(value);
            _Value = value;
        }
    }

    DateTime ToDateTime() { return _Value; }

    // ... casters, comparison methods, etc...
}

我目前没有选择将DB中的所有现有NULL转换为常量,但我很乐意在我的域内查询这样的内容......

IList<Discount> GetAll(OpenBusinessDate expiringAfterDate)
{
    return (from d in session.Linq<Discount>()
           where d.ExperationDate > expiringAfterDate
           select d).ToList();
}

......让NH知道要翻译成这个......

SELECT * FROM Discount 
WHERE (ExpirationDate IS NULL 
    OR ExpirationDate > @expiringAfterDate)

/* ...or possibly this... */

SELECT * From Discount
WHERE (COALESCE(ExpirationDate, '9999-12-31') > @expiringAfterDate)

我一直在看看NH中的用户类型并且已经将IUserType从Infinity转换为NULL并返回(以及实际的DateTime),但我还没有发现让查询按我想要的方式编写。也就是说,现在,上面的Linq和我的代码将生成查询:

SELECT * FROM Discount
WHERE (ExpirationDate > 'Infinity')
/* b/c OpenBusinessDate.ToString() on Infinity 
   produces "Infinity" for debugging purposes */

有没有人对于在哪里寻找或拥有类似工作示例有任何建议?我似乎无法找到正确的关键字集来找到我认为已经解决的问题的匹配。这纯粹是一个NH问题需要解决,还是会涉及Linq2NH的一些工作?

1 个答案:

答案 0 :(得分:1)

我这样做的方法是为ExpirationDate映射一个受保护的属性,然后为OpenBusinessDate公开一个公共的readonly属性,如下所示:

public class Discount
{
    private DateTime _value;
    protected DateTime? ExpirationDate 
    {
        get { return _value; }
        set { 
                _value = value; 
                ExpirationDate = new OpenBusinessDate(value); 
            }
    }
    public OpenBusinessDate OpenExpirationDate {get; private set;}
}

然后覆盖折扣类的映射,如下所示:

public PersonMap : ClassMap<Discount>
{  
    public PersonMap()  
    {  
        Map(Reveal.Property<Discount>("ExpirationDate ")) 
    }  
}

然后在您的linq查询中,您将能够自己应用无限逻辑

 return (from d in session.Linq<Discount>
           where d.ExpirationDate > expiringAfterDate || d.ExpirationDate != null
           select d).ToList();