2016-06-22 7 views
3

をロードされているかどうかをテストするために:私は、ユーザーをこのように取得する場合どのように私はタグが遅延ロードされた状態で、ユーザーがあると遅延ロードされた子コレクションは

public class User 
{ 
    public int UserId { get; set; } 

    public virtual ICollection<Tag> Tags { get; set; } 
} 

、私はタグが読み込まれていないことを知っています:

User myUser; 
using (var context = new MyContext()) 
{ 
    myUser = context.Users.Find(4); 
} 

どのように私はusing句の外にTagsコレクションの存在をテストするのですか?

if (myUser.Tags == null) // throws an ObjectDisposedException 

私はtry/catchを使用できますが、より良い方法が必要です。

+0

@Tuco。そのエンティティを読み込むためのいくつかの方法(いくつかは 'Include'を持たないものもあります)があると、いくつかの外部コードが利用可能な子コレクションに適応できるはずです。 – Mart

答えて

2

私が考えることができる唯一の方法は、(派生クラスでbase.Somethingを行うときと同様の)非仮想呼び出しをクラスプロパティゲッターに行うことです。

using System; 
using System.Linq.Expressions; 
using System.Reflection; 
using System.Reflection.Emit; 

public static class Utils 
{ 
    public static TValue GetClassValue<TSource, TValue>(this TSource source, Expression<Func<TSource, TValue>> selector) 
     where TSource : class 

    { 
     Func<TSource, TValue> getValue = null; 
     if (source.GetType() != typeof(TSource)) 
     { 
      var propertyAccessor = selector.Body as MemberExpression; 
      if (propertyAccessor != null) 
      { 
       var propertyInfo = propertyAccessor.Member as PropertyInfo; 
       if (propertyInfo != null) 
       { 
        var getMethod = propertyInfo.GetGetMethod(); 
        if (getMethod != null && getMethod.IsVirtual) 
        { 
         var dynamicMethod = new DynamicMethod("", typeof(TValue), new[] { typeof(TSource) }, typeof(Utils), true); 
         var il = dynamicMethod.GetILGenerator(); 
         il.Emit(OpCodes.Ldarg_0); 
         il.EmitCall(OpCodes.Call, getMethod, null); 
         il.Emit(OpCodes.Ret); 
         getValue = (Func<TSource, TValue>)dynamicMethod.CreateDelegate(typeof(Func<TSource, TValue>)); 
        } 
       } 
      } 
     } 
     if (getValue == null) 
      getValue = selector.Compile(); 
     return getValue(source); 
    } 
} 
:純粋なC#または反射して、私が代わりに通常の CallvirtCall IL命令を発するように System.Reflection.Emit LCG(軽量コード生成)を利用し、次のヘルパーメソッドになってしまったことを実行する方法はありませんので、

それはこのように、単一およびコレクション型ナビゲーションプロパティの両方に使用することができます。

if (myUser.GetClassValue(x => x.Tags) == null) 
+0

印象的です。したがって、ロードされている場合は実際の値を返し、そうでない場合はnullを返します。この呼び出しのコストを、try/catchと比較して見積もることができますか? – Mart

+0

はい - あなたはそれを試すことができます:)はい、それはコストがかかるので、パフォーマンスが懸念される場合は、委任キャッシュが必要になります。 –

0

他の回答と比較して、パフォーマンスがわからないナイーブのtry/catch、使用して別の解決策:

を10
using System; 

public static class EntityFrameworkExtensions 
{ 
    public static bool IsCollectionLoaded<TSource, TValue>(this TSource source, Func<TSource, TValue> selector) 
     where TSource : class 
    { 
     try 
     { 
      return (selector(source) != null); 
     } 
     catch (ObjectDisposedException) 
     { 
      return false; 
     } 
    } 
} 

使用:私はちょうど彼らが読み込まれているかどうかをテストする、それらをロードしたくない

if (myUser.IsCollectionLoaded(x => x.Tags)) 
関連する問題