Domanda

I'm quite new to LINQ, but I already know the basic difference between IQueryable and IEnumerable (i.e. conditions applied to the first one are likely to be executed by the remote engine, in my case - translated to SQL).

Now, all the NHibernate tutorials I've ever seen use IList<T> for related collections. I'd like to know if there's any way to use IQueryable instead, so the filtering could be efficient.

Unfortunately, if I try to use IQueryable<T> as the property type for related collection, it causes an error:

Unable to cast object of type 'NHibernate.Collection.Generic.PersistentGenericBag1[....PersonalDocument]' to type 'System.Linq.IQueryable

Therefore to keep the filtering of related collections SQL-side, I need to query the related type directly providing the extra condition which "binds" the relation. This is quite inconvenient, and I'd like to avoid this (since the relationship condition is already declared ...)

To clarify a bit:

I have two models, as follows:

public partial class Person
{
    public virtual int Id { get; set; }
    // ....
    public virtual IEnumerable<PersonalDocument> Documents { get; set; }
}

public class PersonalDocument
{
// ...
    public virtual int Id { get; set; }
    public virtual Person Owner { get; set; }
    public virtual string Type { get; set; } 
}

and the mapping code for Person:

HasMany<DomainModel.PersonalDocument>(x => x.Documents)
            .KeyColumn("Owner_Id")
            .Inverse()
            .Cascade.Delete()
            .AsBag();

and the query code

personInstance.Documents.Where(d => d.Type == "xx").Count()

is being translated to non-optimal SQL (no "type" filter applied to SQL, count done client-side) related

while this one:

s.Query<PersonalDocument>().Count(x => x.Owner == personInstance && x.Type == "xx");

translates to a nice SQL:

enter image description here

is there any way to write DRY LINQ queries like the first one, yet have resulting SQL optimal like the second one?

È stato utile?

Soluzione

Altri suggerimenti

Use IList/ISet/IDictionary!

You can create a collection for each document type in the class Person. In the mapping you can do:

HasMany(x => x.Documents)
            .KeyColumn("Owner_Id")
            .Inverse()
            .Cascade.Delete()
            .Where("Type=xx")
            .AsBag();

I do not like this solution. I also do not like how your Product class is partial. If I were you I would try the WHERE suggestion and after everything is working I would take a look at my design.

Also take a look at NHibernate inheritance strategies. Actually I think this is exactly what you want:

http://www.nhforge.org/doc/nh/en/#inheritance
http://ayende.com/blog/3941/nhibernate-mapping-inheritance http://lostechies.com/jimmybogard/2008/08/27/strategies-and-discriminators-in-nhibernate/

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top