我怎样才能让 NHibernate 映射到自定义 Class?

How can I get NHibernate to map to a custom Class?

我最近实际上问了一个非常相似的问题,但是虽然标题提到了 classes,但我的内容主要是指一个元组,并且(非常棒的)答案反映了这一点。当我尝试用 class 替换元组时,出现 TargetParameterCountException: Parameter count mismatch. 异常。


我有以下方法从数据库中获取结果列表。

public static IList<T> Find<T>(DetachedCriteria crit) where T : class
{
    lock (_locker)
    {
        return crit.GetExecutableCriteria(InstanceSession)
            .List<T>();
    }
}

这通常效果很好。但是,我已经更改了一个调用上面方法的方法。

public IList<FooBarResult> FindResults(FooBarTask st)
{
    return DataAccess.Find<FooBarResult>(DetachedCriteria.For<FooBarResult>()
        .Add(Restrictions.Eq("Task", st))).ToList();
}

对此有效(因为我不想 return 整个 FooBarResult,只是上面的某些列)。

public IList<MyCustomClass> FindResults(FooBarTask st)
{
    var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
    return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
        .Add(Restrictions.Eq("Task", st))
        .SetProjection(
            Projections.ProjectionList()
                .Add(
                    Projections.Property("FieldOne") //this is a DateTime
                )
                .Add(
                    Projections.Property("FieldTwo") //this is a Guid
                )
                .SetResultTransformer(Transformers.AliasToBeanConstructor(typeConstructor))
        )
    );
}

这是 class。

public class MyCustomClass
{
    public MyCustomClass()
    {
        //placeholder
    }

    public MyCustomClass(DateTime FieldOne, Guid FieldTwo)
    {
        this.FieldOne = FieldOne;
        this.FieldTwo = FieldTwo;
    }

    public DateTime FieldOne { get; set; }
    public Guid FieldTwo { get; set; }
}

如前所述,当 运行 return crit.GetExecutableCriteria(InstanceSession).List<T>(); 代码时,我得到一个 TargetParameterCountException: Parameter count mismatch. 异常。

有什么方法可以使它 return 成为我的 MyCustomClass 的列表?

我没有测试过这个,但你应该使用 Transformers.AliasToBean 查看别名以使转换器工作:

public IList<MyCustomClass> FindResults(FooBarTask st)
{
    var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
    return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
        .Add(Restrictions.Eq("Task", st))
        .SetProjection(
            Projections.ProjectionList()
                .Add(Projections.Property("FieldOne"), "FieldOne")
                .Add(Projections.Property("FieldTwo"), "FieldTwo")        
        )
        .SetResultTransformer(Transformers.AliasToBean(typeof(MyCustomClass)))
        .List<MyCustomClass>()
}

这一行:

var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];

您将获得第一个默认构造函数,其签名显然不匹配。最简单的解决方法是:

var typeConstructor = typeof(MyCustomClass).GetConstructors()[1];

但最干净的解决方案是沿着这些思路(未经测试,也有点简化):

var typeConstructor = GetMatchingConstructorOrThrow<MyCustomClass>
    (typeof(DateTime), typeof(Guid));

// ...

private ConstructorInfo GetMatchingConstructorOrThrow<T>(params Type[] requiredSignature)
where T : class
{
    foreach (var c in typeof(T).GetConstructors())
    {
        var currentSignature = c.GetParameters().Select(p => p.ParameterType);
        if (currentSignature.SequenceEqual(requiredSignature))
        {
            return c;
        }
    }

    throw new NoMatchingConstructorFoundException();
}