Geesh_SO
Geesh_SO

Reputation: 2205

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

I actually asked a very similar question recently, but while the title mentioned classes, my content mostly referred to a tuple, and the (really great) answer reflected that. When I've tried to substitute a class in for the tuple, I get TargetParameterCountException: Parameter count mismatch. exception.

How can I get NHibernate to map to a Tuple or Class?


I have the following method to get a list of results from the database.

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

This generally works well. However, I've changed a method that calls the method above from.

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

Which works, to this (as I don't want to return the whole of FooBarResult, just certain columns on it).

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

And this is the 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; }
}

As mentioned earlier, when running the return crit.GetExecutableCriteria(InstanceSession).List<T>(); code I get a TargetParameterCountException: Parameter count mismatch. exception.

Is there any way I can make it return a list of my MyCustomClass?

Upvotes: 0

Views: 149

Answers (2)

BartoszKP
BartoszKP

Reputation: 35921

In this line:

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

you will get the first, default constructor and its signature obviously doesn't match. The simplest fix for your case is:

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

But the cleanest solution would be something along these lines (untested and also a bit simplified):

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

Upvotes: 1

Najera
Najera

Reputation: 2879

I have not tested this, but you should use Transformers.AliasToBean take a look in to the aliases to let the transformer work:

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

Upvotes: 2

Related Questions