如何测试是否已加载延迟加载的子集合

时间:2016-06-22 12:32:18

标签: entity-framework-6

假设我的用户标记为延迟加载:

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);
}

如何在Tags子句之外测试using集合存在?

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

我可以使用try / catch但必须有更好的方法。

2 个答案:

答案 0 :(得分:2)

我能想到的唯一方法是能够在类属性getter中执行非虚拟调用(类似于在派生类中执行base.Something时)。由于没有办法用纯C#或反射来做到这一点,我最终得到了以下帮助方法,该方法利用System.Reflection.Emit LCG(轻量级代码生成)发出Call IL指令而不是正常Callvirt

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);
    }
}

它可以用于单一和集合类型的导航属性,如下所示:

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

答案 1 :(得分:0)

使用天真的try / catch的另一个解决方案,与其他答案相比,不确定性能:

if (myUser.IsCollectionLoaded(x => x.Tags))

用法:

EXEC PROC_A @p_para = 'Test'