Private collection mapping in fluent nhibernate

2019-01-24 12:19发布

问题:

How can I map this:

public class Customer
{
   private IList<Order> _orders;
   public IEnumerable<Order> 
   GetAllOrders()
   {
      return _orders;     
   }
}

On the project page are some samples but none is about this situation. There is this sample:

// model   
public class Account   
{   
  private IList<Customer> customers = new List<Customer>();   

  public IList<Customer> Customers   
  {   
    get { return customers; }   
  }   
}

// mapping   
HasMany(x => x.Customers)   
  .Access.AsCamelCaseField();  

But it assumes that Account has public field Customers and that scenario is different as mine. I tried some possible options but none works:

HasMany(x => Reveal.Propertie("_orders"))

Private fields works fine in simple property mapping but collection mapping is quite different. Any idea? Thanks

回答1:

The easiest solution is to expose your collection as a public property Orders instead of the GetAllOrders() method. Then your mapping is

HasMany(x => x.Orders)
    .Access.AsCamelCaseField(Prefix.Underscore);

and your class is

public class Customer
{
    private IList<Order> _orders = new List<Order>();

    public IEnumerable<Order> Orders 
    { 
        get { return _orders; }
    }
}

If that doesn't work for you, it is possible to map private properties using Fluent NHibernate's Reveal mapping.

Edited to add: Having just done this, the correct answer is:

HasMany<Order>(Reveal.Property<Customer>("_orders")) etc.

The collection must be exposed as a protected virtual property to allow proxying:

protected virtual IList<Order> _orders { get; set; }

This answer put me on the right track.



回答2:

Thanks. Your solution is fine. However, there could be situations(hypotetical) when you dont want to reveal your private collection. This mapping scenario is not explained in your linked post because there is difference between mapping simple propertie as descibed in that post and collection mapping. My attempt to use HasMany(x => Reveal.Propertie("_orders")) failed because of raised exception.



回答3:

You can map a completely private collection using Reveal.Member(), but it has a specific and non-obvious restriction: the Expression that HasMany() accepts has to return either IEnumerable<TReferenced> or object.

For your class:

public class Customer
{
    private IList<Order> _orders;
    public IEnumerable<Order> GetAllOrders()
    {
        return _orders;     
    }
}

the following line will populate the _orders collection:

HasMany(Reveal.Member<Customer, IEnumerable<Order>>("_orders"));
    //additional mapping behaviors

For completeness - the following line gives a compiler error:

HasMany(Reveal.Member<Customer, IList<Order>>("_orders"));