问题描述:

I keep getting an annoying error with NHibernate when I try to transform returned data from SQL to a class with classes inside. Lets say I these classes.

[DataContract()]

public class Person {

[DataMember]

public string Name { get; set; }

[DataMember]

public Dog Dog { get; set; }

}

[DataContract()]

public class Dog {

[DataMember]

public int Age { get; set; }

}

And I have this SQL-query.

SELECT

p_name AS 'Name',

p_dog_age AS 'Dog.Age'

FROM People WHERE p_name = 'Foo';

And to transform this into a Person class I

var person = Session.CreateSQLQuery(Sql.GetPerson)

.SetResultTransformer(new AliasToBeanResultTransformer(typeof(Person)))

.Future<Person>().FirstOrDefault();

Whenever I do this, I get the following error

An exception of type 'NHibernate.PropertyNotFoundException' occurred in NHibernate.dll but was not handled in user code

Complaining that it can't find the property of Dog.Age and that it does not have a setter property. I know it should be possible to do this but I can't figure it out.

I know that the values that are returned from the SQL query are not null.

网友答案:

It sounds like you're trying to map a component. Using FluentNHibernate:

public class PersonMap : ClassMap<Person>
{ 
    public PersonMap() 
    {
        Table("Person");
        Id(p => p.Id, "Id").GeneratedBy.Native().Not.Nullable();
        Map(p => p.Name, "Name").Length(255).Not.Nullable();

        Component(p => p.Dog, d =>
        {
            d.Map(dog => dog.Name, "DogName").Not.Nullable();
            d.Map(dog => dog.Age, "DogAge").Not.Nullable();
        }
    }    
}

you'd need a table with 4 columns for this:

  • id
  • name (person's name)
  • dogname (the person's dog's name)
  • dogage (the person's dog's age)

but - what if a person has two dogs? or no dogs?

public class PersonMap : ClassMap<Person>
{ 
    public PersonMap() 
    {
        Table("Person");
        Id(p => p.Id, "Id").GeneratedBy.Native().Not.Nullable();

        References(p => p.Dog, "Dog").Nullable();
    }
}

public class DogMap : ClassMap<Dog>
{
    Map(d => d.Id, "Id").GeneratedBy.Native();

    References(p => p.Person, "Person").Nullable();
    Map(d => d.Name, "Name").Not.Nullable();
    Map(d => d.Age, "Age").Not.Nullable();
    }    
}

this needs two tables and would benefit from a couple of foreign keys referencing Id's.

using NHibernate's Linq implementation you can directly query the dog's name and age from a person:

var dog = 
   _session.Query<Person>()
           .Where(p => p.Name == "Charlie Brown")
           .Where(p => p.Dog.Name == "Snoopy")
           .Select(p => p.Dog)
           .SingleOrDefault();
网友答案:

Solution

After looking around and trying some different approaches I came up with this.

private void doStuff(){
    var listOfRows = Session.CreateSQLQuery(Sql.GetPerson)
        .List();

    var listOfPersonRows = new List<Person>();

    if (listOfRows.Count != 0)
    {
        for (var i = 0; i < listOfRows.Count; i++)
        {
            var item = (object[])listOfRows[i];
            listOfPersonRows.Add(ConvertToRow(item));
        }
    }
}

private Person ConvertToRow(object[] item)
{
    var personRow = new Person();

    personRow.Name = (string)item[0];
    personRow.Dog.Age = (int)item[1];


    return personRow;
}

This way I still only have to query the database once instead of multiple times.

相关阅读:
Top