2011-01-26 6 views
14

मैं एक सामान्य भंडार है कि एक IQueryable<T> इस तरह उजागर करता है उपयोग कर रहा हूँ:मैं अपने सार भंडार के अंदर Linq2NHibernate के फ़ेच और .henFetch को कैसे लपेटूं?

public IQueryable<T> AllEntities 
{ 
    get 
    { 
     return session.Query<T>(); 
    } 
} 

मैं इस तरह क्वेरी कर सकते हैं:

var results = 
    (from e in repository.AllEntities 
    where e.SomeProperty == "some value" 
    select e).ToList(); 

हालांकि, अगर T एक माता पिता और दादा-दादी इकाई है और मैं चाहता हूँ उन्हें बेसब्री से लोड करते हैं, मैं यह करने के लिए है:

var results = 
    (from e in repository.AllEntities 
    where e.SomeProperty == "some value" 
    select e) 
    .Fetch(x => x.Parent) 
    .ThenFetch(x => x.Grandparent) 
    .ToList(); 

यह काम करता है, लेकिन .Fetch और .ThenFetch दोनों Linq2Nhibernate विशिष्ट एक्सटेंशन के तरीकों, जो दो कारण समस्याएं हो रही हैं:

  1. मैं अपनी फ़ाइल के शीर्ष पर एक using NHibernate.Linq; बयान शामिल करने के लिए की है। हालांकि, इस बिंदु पर कि मैं यह प्रश्न कर रहा हूं, यह कार्यान्वयन अज्ञेयवादी होना चाहिए।

  2. मैं इकाई परीक्षण जब IQueryable<T> कि मेरी नकली भंडार प्रदान करता है के खिलाफ मार डाला इस, .Fetch और .ThenFetch तरीकों विफल करने का प्रयास करते।

मैं अपने IRepository<T> इंटरफेस के इन अंदर कैसे लपेट कर सकते हैं, या कुछ सामान्य विस्तार के तरीकों के अंदर?

अद्यतन: मेरी NHibernate भंडार कार्यान्वयन के लिए

IQueryable<T> EagerLoadParent<U>(IQueryable<T> query, 
    Expression<Func<T, U>> parentExpression); 
IQueryable<T> EagerLoadParent<U, V>(IQueryable<T> query, 
    Expression<Func<T, U>> parentExpression, 
    Expression<Func<U, V>> grandparentExpression); 

... और इस:

अब तक सब मैं ले कर आए हैं मेरी भंडार इंटरफ़ेस में जोड़ने के लिए है

public IQueryable<T> EagerLoadParent<U>(IQueryable<T> query, 
    Expression<Func<T, U>> parentExpression) 
{ 
    return query 
     .Fetch(parentExpression); 
} 

public IQueryable<T> EagerLoadParent<U, V>(IQueryable<T> query, 
    Expression<Func<T, U>> parentExpression, 
    Expression<Func<U, V>> grandparentExpression) 
{ 
    return query 
     .Fetch(parentExpression) 
     .ThenFetch(grandparentExpression); 
} 

इस एपीआई के उपभोक्ता अब इस करता है:

var query = 
    (from e in repository.AllEntities 
    where e.SomeProperty == "some value" 
    select e); 
var results = repository 
    .EagerLoadParent(query, e => e.Parent, p => p.Grandparent) 
    .ToList(); 

लेकिन इसमें अच्छा विस्तार विधि वाक्यविन्यास नहीं है जो मैं चाहूंगा। मैं .Fetch और .ThenFetch वाक्यविन्यास के करीब कुछ ढूंढ रहा हूं।

उत्तर

13

कुछ जांच के बाद मुझे लगता है कि मेरे पास एक नुस्खा है: अपने स्वयं के कार्यान्वयन के लिए बारीकी से NHibernate.Linq कार्यान्वयन का पालन करें और अपने क्लाइंट कोड में एक स्पष्ट NHibernate.Linq निर्भरता से बचें। आपको बस NHibernate.Linq.EagerFetchingExtensionMethods कक्षा बहुत बारीकी से पुन: पेश करने की आवश्यकता है। IFetchRequest, एक वर्ग FetchRequestIFetchRequest लागू करने और एक स्थिर वर्ग EagerFetch को लागू विस्तार तरीके:

यह एक अंतरफलक लेता है। यह NHibernate.Linq.EagerFetchingExtensionMethods वर्ग का क्लोन का एक प्रकार है।

बस को परिभाषित:

public interface IFetchRequest<TQueried, TFetch> : IOrderedQueryable<TQueried> {} 

जो की नकल करता है NHibernate.Linq.INhFetchRequest<TQueried, TFetch>

तो एक कार्यान्वयन को परिभाषित:

public class FetchRequest<TQueried, TFetch> : IFetchRequest<TQueried, TFetch> { 

    #region IEnumerable<TQueried> Members 

    public IEnumerator<TQueried> GetEnumerator(){ 
     return NhFetchRequest.GetEnumerator(); 
    } 

    #endregion 

    #region IEnumerable Members 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return NhFetchRequest.GetEnumerator(); 
    } 

    #endregion 

    #region IQueryable Members 

    public Type ElementType { 
     get { return NhFetchRequest.ElementType; } 
    } 

    public System.Linq.Expressions.Expression Expression { 
     get { return NhFetchRequest.Expression; } 
    } 

    public IQueryProvider Provider { 
     get { return NhFetchRequest.Provider; } 
    } 

    #endregion 

    public FetchRequest(INhFetchRequest<TQueried, TFetch> nhFetchRequest){ 
     NhFetchRequest = nhFetchRequest; 
    } 

    public INhFetchRequest<TQueried, TFetch> NhFetchRequest { get; private set; } 
} 

यह एक बस एक nHibernate कार्यान्वयन और आगे कि सदस्य के लिए हर विधि रखती है।

अंत:

public static class EagerFetch { 
/* 
    replacing methods from NHibernate.Linq.EagerFetchingExtensionMethods 
    private static INhFetchRequest<TOriginating, TRelated> CreateFluentFetchRequest<TOriginating, TRelated>(MethodInfo currentFetchMethod, IQueryable<TOriginating> query, LambdaExpression relatedObjectSelector); 
    public static INhFetchRequest<TOriginating, TRelated> Fetch<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector); 
    public static INhFetchRequest<TOriginating, TRelated> FetchMany<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector); 
    public static INhFetchRequest<TQueried, TRelated> ThenFetch<TQueried, TFetch, TRelated>(this INhFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, TRelated>> relatedObjectSelector); 
    public static INhFetchRequest<TQueried, TRelated> ThenFetchMany<TQueried, TFetch, TRelated>(this INhFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, IEnumerable<TRelated>>> relatedObjectSelector); 
*/ 
    public static IFetchRequest<TOriginating, TRelated> Fetch<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector){ 
     var fetch = EagerFetchingExtensionMethods.Fetch(query, relatedObjectSelector); 
     return new FetchRequest<TOriginating, TRelated>(fetch); 
    } 

    public static IFetchRequest<TOriginating, TRelated> FetchMany<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector){ 
     var fecth = EagerFetchingExtensionMethods.FetchMany(query, relatedObjectSelector); 
     return new FetchRequest<TOriginating, TRelated>(fecth); 
    } 

    public static IFetchRequest<TQueried, TRelated> ThenFetch<TQueried, TFetch, TRelated>(this IFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, TRelated>> relatedObjectSelector){ 
     var impl = query as FetchRequest<TQueried, TFetch>; 
     var fetch = EagerFetchingExtensionMethods.ThenFetch(impl.NhFetchRequest, relatedObjectSelector); 
     return new FetchRequest<TQueried, TRelated>(fetch); 
    } 

    public static IFetchRequest<TQueried, TRelated> ThenFetchMany<TQueried, TFetch, TRelated>(this IFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, IEnumerable<TRelated>>> relatedObjectSelector){ 
     var impl = query as FetchRequest<TQueried, TFetch>; 
     var fetch = EagerFetchingExtensionMethods.ThenFetchMany(impl.NhFetchRequest, relatedObjectSelector); 
     return new FetchRequest<TQueried, TRelated>(fetch); 
    } 
} 
+0

यह वास्तव में अच्छा है (मैं एक सहयोगी अपने आप की तुलना में कहीं अधिक कुशल को यह, क्रेडिट नहीं लिखा था), लेकिन अब मैं IFetchRequest कि वस्तुओं के लिए LINQ के साथ काम करता लागू करने के लिए की जरूरत है? – Sly

+0

अंततः मुझे इसका समाधान मिला। धन्यवाद! – Chris

+0

@Chris - क्या आप कृपया साझा करेंगे कि आपको कौन सा समाधान मिला? – Sam

1

बिल्डिंग गुइडो के जवाब पर, यहाँ एक जो भंडार इंटरफ़ेस से सभी NHibernate निर्भरता डिस्कनेक्ट है। बॉयलर प्लेट का थोड़ा सा हिस्सा और शायद एक अच्छी तकनीक नहीं है यदि आप बहुत सारी एनएचबीर्नेट विशिष्ट कार्यक्षमता का उपयोग करना चाहते हैं; फिर NHibernate.dll का संदर्भ अधिक उपयुक्त हो सकता है।

पहले इंटरफेस:

public interface IFetchableQueryable<TQueried> : IQueryable<TQueried> { 
     IFetchRequest<TQueried, TRelated> Fetch<TRelated>(Expression<Func<TQueried, TRelated>> relatedObjectSelector); 

     IFetchRequest<TQueried, TRelated> FetchMany<TRelated>(Expression<Func<TQueried, IEnumerable<TRelated>>> relatedObjectSelector); 
} 

public interface IFetchRequest<TQueried, TFetch> : IOrderedQueryable<TQueried> { 
     IFetchRequest<TQueried, TRelated> ThenFetch<TRelated>(Expression<Func<TFetch, TRelated>> relatedObjectSelector); 

     IFetchRequest<TQueried, TRelated> ThenFetchMany<TRelated>(Expression<Func<TFetch, IEnumerable<TRelated>>> relatedObjectSelector); 
} 

और फिर कार्यान्वयन:

public class FetchableQueryable<TQueried> : IFetchableQueryable<TQueried> { 
    public FetchableQueryable(IQueryable<TQueried> query) { 
     this.Query = query; 
    } 

    public IQueryable<TQueried> Query { get; private set; } 

    #region IEnumerable<TQueried> Members 

    public IEnumerator<TQueried> GetEnumerator() { 
     return this.Query.GetEnumerator(); 
    } 

    #endregion 

    #region IEnumerable Members 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { 
     return this.Query.GetEnumerator(); 
    } 

    #endregion 

    #region IQueryable Members 

    public Type ElementType { 
     get { return this.Query.ElementType; } 
    } 

    public Expression Expression { 
     get { return this.Query.Expression; } 
    } 

    public IQueryProvider Provider { 
     get { return this.Query.Provider; } 
    } 

    #endregion 

    #region IFetchableQueryable<TQueried> Members 

    public IFetchRequest<TQueried, TRelated> Fetch<TRelated>(Expression<Func<TQueried, TRelated>> relatedObjectSelector) { 
     return new FetchRequest<TQueried, TRelated>(this.Query.Fetch<TQueried, TRelated>(relatedObjectSelector)); 
    } 

    public IFetchRequest<TQueried, TRelated> FetchMany<TRelated>(Expression<Func<TQueried, IEnumerable<TRelated>>> relatedObjectSelector) { 
     return new FetchRequest<TQueried, TRelated>(this.Query.FetchMany<TQueried, TRelated>(relatedObjectSelector)); 
    } 

    #endregion 
} 

public class FetchRequest<TQueried, TFetch> : IFetchRequest<TQueried, TFetch> { 

    public FetchRequest(INhFetchRequest<TQueried, TFetch> nhFetchRequest) { 
     NhFetchRequest = nhFetchRequest; 
    } 

    public INhFetchRequest<TQueried, TFetch> NhFetchRequest { get; private set; } 

    #region IEnumerable<TQueried> Members 

    public IEnumerator<TQueried> GetEnumerator() { 
     return NhFetchRequest.GetEnumerator(); 
    } 

    #endregion 

    #region IEnumerable Members 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { 
     return NhFetchRequest.GetEnumerator(); 
    } 

    #endregion 

    #region IQueryable Members 

    public Type ElementType { 
     get { return NhFetchRequest.ElementType; } 
    } 

    public System.Linq.Expressions.Expression Expression { 
     get { return NhFetchRequest.Expression; } 
    } 

    public IQueryProvider Provider { 
     get { return NhFetchRequest.Provider; } 
    } 

    #endregion 

    #region IFetchRequest<TQueried,TFetch> Members 

    public IFetchRequest<TQueried, TRelated> Fetch<TRelated>(Expression<Func<TQueried, TRelated>> relatedObjectSelector) { 
     var fetch = EagerFetchingExtensionMethods.Fetch(this.NhFetchRequest, relatedObjectSelector); 
     return new FetchRequest<TQueried, TRelated>(fetch); 
    } 

    public IFetchRequest<TQueried, TRelated> FetchMany<TRelated>(Expression<Func<TQueried, IEnumerable<TRelated>>> relatedObjectSelector) { 
     var fecth = EagerFetchingExtensionMethods.FetchMany(this.NhFetchRequest, relatedObjectSelector); 
     return new FetchRequest<TQueried, TRelated>(fecth); 
    } 

    public IFetchRequest<TQueried, TRelated> ThenFetch<TRelated>(Expression<Func<TFetch, TRelated>> relatedObjectSelector) { 
     var fetch = EagerFetchingExtensionMethods.ThenFetch(this.NhFetchRequest, relatedObjectSelector); 
     return new FetchRequest<TQueried, TRelated>(fetch); 
    } 

    public IFetchRequest<TQueried, TRelated> ThenFetchMany<TRelated>(Expression<Func<TFetch, IEnumerable<TRelated>>> relatedObjectSelector) { 
     var fetch = EagerFetchingExtensionMethods.ThenFetchMany(this.NhFetchRequest, relatedObjectSelector); 
     return new FetchRequest<TQueried, TRelated>(fetch); 
    } 

    #endregion 
} 
0

क्या मैं चारों ओर इस EagerlyFetch मेरी वस्तु के लिए अपने भंडार में एक public virtual समारोह बनाने के लिए है काम करने के लिए किया है। फिर, मेरे यूनिट परीक्षणों में मैं उस स्टब का उपयोग करता हूं जो मेरे EagerlyFetch विधि को छोड़कर सबकुछ से गुजरता है, जो सिर्फ एक सूची देता है।

public class PersistenceBroker 
{ 
    private ISession _session; 

    public IQueryable<T> Query<T>() 
    { 
     return Session.Query<T>(); 
    } 
    . 
    . 
    . 
} 

public class PersonRepository : IPersonRepository 
{ 
    private PersistenceBroker _persistenceBroker; 

    public List<Person> PeopeWhoLiveIn(string city) 
    { 
     var people = _persistenceBroker.Query<Person>() 
      Where(x => x.City == city)l 

     return EagerlyFetch(people); 
    } 

    public virtual List<Person> EagerlyFetch(IQueryable<Person> people) 
    { 
     return people.Fetch(x => x.Mom) 
      .FetchMany(x => x.Children) 
      .ToList(); 
    } 
} 

और फिर मेरी परीक्षणों में, मैं बस एक PersonRepositoryStub प्रदान करते हैं:: यहाँ मैं क्या किया है का एक उदाहरण है

public class PersonRepositoryStub : PersonRepository 
{ 
    public override List<Person> EagerlyFetch(IQueryable<Person> people) 
    { 
     return people.ToList(); 
    } 
} 

यह ऊपर कुछ उत्तर के लिए एक विकल्प हो सकता है (जो मैंने कोशिश नहीं की है), लेकिन यह मेरे लिए काम करता है।

चीयर्स,

लेवी

0

वैकल्पिक रूप से अपने परीक्षण डाटा एक ठूंठ कि IFutureValue लागू करता है में IEnumerable लपेट (नायब इस remotion http://relinq.codeplex.com/ उपयोग करता है)।

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using NHibernate; 
using Remotion.Linq; 

namespace SomeNameSpaceNearYou 
{ 
    public class NhStubQueryable<TData> : QueryableBase<TData>, IEnumerable<TData>, IFutureValue<TData> 
    { 
     private readonly IEnumerable<TData> _enumerable; 

     public NhStubQueryable(IEnumerable<TData> enumerable) 
      : base(new NhStubQueryProvider()) 
     { 
      _enumerable = enumerable; 
     } 

     /// <summary> 
     /// This constructor is called by Provider.CreateQuery(). 
     /// </summary> 
     //public NhStubQueryable(NhStubQueryProvider<TData> provider, Expression expression) 
     public NhStubQueryable(NhStubQueryProvider provider, Expression expression) 
      : base(provider, expression) 
     { 
      if (provider == null) 
      { 
       throw new ArgumentNullException("provider"); 
      } 

      if (expression == null) 
      { 
       throw new ArgumentNullException("expression"); 
      } 

      if (!typeof(IQueryable<TData>).IsAssignableFrom(expression.Type)) 
      { 
       throw new ArgumentOutOfRangeException("expression"); 
      } 
     } 
     #endregion 

     #region Enumerators 
     IEnumerator<TData> IEnumerable<TData>.GetEnumerator() 
     { 
      if (_enumerable != null) 
       return _enumerable.GetEnumerator(); 
      return (Provider.Execute<IEnumerable<TData>>(Expression)).GetEnumerator(); 
     } 
     IEnumerator IEnumerable.GetEnumerator() 
     { 
      if (_enumerable != null) 
       return _enumerable.GetEnumerator(); 
      return (Provider.Execute<IEnumerable<TData>>(Expression)).GetEnumerator(); 
     } 
     public new IEnumerator<TData> GetEnumerator() 
     { 
      if (_enumerable != null) 
       return _enumerable.GetEnumerator(); 
      return (Provider.Execute<IEnumerable<TData>>(Expression)).GetEnumerator(); 
     } 


     #endregion 
     public IEnumerable Enumerable { get { return _enumerable; } } 

     public TData Value { get { return this.FirstOrDefault(); } } 
    } 

    public class NhStubFutureValue<TData> : IFutureValue<TData> 
    { 
     public NhStubFutureValue(TData value) 
     { 
      Value = value; 
     } 

     public TData Value { get; private set; } 
    } 
}