开发者

Eagerly fetch multiple collection properties (using QueryOver/Linq)?

开发者 https://www.devze.com 2023-03-01 01:01 出处:网络
I found 2 similar questions: Multiple Fetches in linq to nhibernate Is this the right way of using ThenFetch() to load multiple collections?

I found 2 similar questions:

  • Multiple Fetches in linq to nhibernate
  • Is this the right way of using ThenFetch() to load multiple collections?

According to this page:

Be careful not to eagerly fetch multiple collection properties at the same time. Although this statement will work fine:

var employees = session.Query<Employee>()
    .Fetch(e => e.Subordinates)
    .Fetch(e => e.Orders).ToList();

It executes a Cartesian product query against the database, so the total number of rows returned will be the total Subordinates times the total orders.

Lets say I have the following model:

public class Person
{
    public virtual int Id { get; private set; }
    public virtual ICollection<Book> Books { get; set; }
    public virtual ICollection<Article> Articles { get; set; }
开发者_StackOverflow中文版    public virtual ICollection<Address> Addresses { get; set; }
}

What is the simplest way to eagerly load all persons with their Books, Articles, and Addresses using QueryOver/Linq (without returning a Cartesian product)?

Thanks


Update:

See cremor's answer below and Florian Lim's answer in this thread. The following code works nicely, only one round-trip to the database.

var persons = session.QueryOver<Person>()
    .Future<Person>();
var persons2 = session.QueryOver<Person>()
    .Fetch(x => x.Books).Eager
    .Future<Person>();
var persons3 = session.QueryOver<Person>()
    .Fetch(x => x.Articles).Eager
    .Future<Person>();
var persons4 = session.QueryOver<Person>()
    .Fetch(x => x.Addresses).Eager
    .Future<Person>();


I prefer to use the linq provider if at all possible especially if you are using newer versions of nhibernate (>= 4.0). As long as you have your collections mapped as ISets (requires .net framework >= 4) which we converted to such that we could do eager loading and avoid cartesian products. I feel like this isn't something that is heavily advertised but I prefer this method where applicable over anything else :

public class Person
{
    public virtual int Id { get; private set; }
    public virtual ISet<Book> Books { get; set; }
    public virtual ISet<Article> Articles { get; set; }
    public virtual ISet<Address> Addresses { get; set; }
}

public Person()
{
    this.Books = new HashSet<Book>();
    this.Articles = new HashSet<Article>();
    this.Addresses = new HashSet<Address>();
}

If you have your collections defined like the above then you can do the following and still avoid cartesian product issues:

var persons = session.Query<Person>()
                     .FetchMany(x => x.Books)
                     .FetchMany(x => x.Articles)
                     .FetchMany(x => x.Addresses)
                     .ToList();


public IList<Person> GetAll()
{
    var persons = session.QueryOver<Person>()
        .Future<Person>();

    session.QueryOver<Person>()
        .Fetch(x => x.Books).Eager
        .Future<Person>();

    session.QueryOver<Person>()
        .Fetch(x => x.Articles).Eager
        .Future<Person>();

    session.QueryOver<Person>()
        .Fetch(x => x.Addresses).Eager
        .Future<Person>();

    return persons.ToList();
}
0

精彩评论

暂无评论...
验证码 换一张
取 消