3

I am getting this error on return of ByParameter because of KeyColumn I guess, how can I make this work?

could not resolve property: ParentId of: Entity.MenuItem

Entity.MenuItem.READ.ByParameter("ParentId", 3);

Code:

public static IList<T> ByParameter(String Parameter, Object Value)
{
    using (var session = NHibernateHelper<T>.OpenSession())
    {
        var conjunction = new Conjunction();

        conjunction.Add(Restrictions.Eq(Parameter, Value));

        return session.CreateCriteria(typeof(T)).Add(conjunction).List<T>();
    }
}

class MenuItemMap : Mapper<MenuItem>
{
    public MenuItemMap()
    {
        Id(x => x.MenuItemId);
        Map(x => x.Text);
        HasMany(x => x.Children).KeyColumn("ParentId").Fetch.Select();
        References(x => x.Parent).Fetch.Select();
    }
}
Mert
  • 6,432
  • 6
  • 32
  • 68
  • Why you need to call as string the parameters? have you tried to use lambdas to use strong typed calls? – Najera May 11 '15 at 15:57
  • 1
    Mert, I observed your issue, and tried to be sure that I can replicate that locally. If your case is similar, the answer should help to solve... – Radim Köhler May 12 '15 at 07:15

2 Answers2

1

If you are not using conventions to change the column name in the Reference method. The default will be Parent_id, you must to specify as ParentId:

References(x => x.Parent).Column("ParentId").Fetch.Select();
Najera
  • 2,869
  • 3
  • 28
  • 52
1

Based on the Exception I would say, that we can face this issue in case - that the calling side looks like this:

var list = ByParameter<MenuItem>("ParentId", 123);

And because the snippet above does not show that class MenuItem contains ValueType (non-reference) property ParentId:

public class MenuItem
{
    // the <id>
    public virtual int MenuItemId { get; set; }

    // References (many-to-one)
    public virtual MenuItem Parent { get; set; }
    // this seems to be not presented on MenuItem
    // public virtual int ParentId { get; set; }

    // HasMany (one-to-many)
    public virtual IList<MenuItem> Children { get; set; }

Solution(s)

  1. Extend model

We can add that into model

public virtual int ParentId { get; set; }

And extend the mapping

// many-to-one is using the same column - so this will be WRITABLE
References(x => x.Parent).Fetch.Select();
// just a ValueType property - READONLY
Map(x => x.ParentId)
    .Readonly() // or .Update(false).Insert(false)
     ;

this would work now

var list = ByParameter<MenuItem>("ParentId", 123);
  1. Just change the param

In fact, this would be the most simple solution... Change the calling side to be targeting existing mapping:

var list = ByParameter<MenuItem>("Parent.MenuItemId", 123);

Because Parent's property MenuItemId (the <id> or Id()) is presented (it is the column ParentId) - we do not need JOIN. NHibernate will generate expectable simple query

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • worked like a charm! Why we made ParentId Readonly and how can I make it by using Convention? – Mert May 12 '15 at 08:12
  • 1
    That's really great. Readonly is not an issue when querying - but in case that we would start to WRITE - NHibernate would try to insert into one column two values (here I tried to get more view on that http://stackoverflow.com/a/30116507/1679310). I would not expect that creating custom convention should be an issue (https://github.com/jagregory/fluent-nhibernate/wiki/Conventions) - just check if it Ends with Id and if you can find the same property without Id at the end (which is class not value type). In such case... it should be readonly. Hope it helps a bit... – Radim Köhler May 12 '15 at 08:20