Entity framework 已为自跟踪实体加载IsLoaded

Entity framework 已为自跟踪实体加载IsLoaded,entity-framework,Entity Framework,我在EF 4.0中使用了自跟踪实体,我发现对于参与多对多关系的导航对象,没有像标准EF对象那样的IsLoaded属性。因此,如果您正在查询Person,但不包括地址,则Person.Addresses会出现一个空列表,但无法判断地址是否已加载,或者此人根本没有任何地址 有没有办法判断导航属性是否加载到自跟踪实体上 如果没有,是否有一种方法可以从ObjectContext访问当前ObjectQuery,这样我就可以看到用户试图扩展哪些属性并创建自定义IsLoaded属性?EF4中没有更多IsLoa

我在EF 4.0中使用了自跟踪实体,我发现对于参与多对多关系的导航对象,没有像标准EF对象那样的IsLoaded属性。因此,如果您正在查询Person,但不包括地址,则Person.Addresses会出现一个空列表,但无法判断地址是否已加载,或者此人根本没有任何地址

有没有办法判断导航属性是否加载到自跟踪实体上


如果没有,是否有一种方法可以从ObjectContext访问当前ObjectQuery,这样我就可以看到用户试图扩展哪些属性并创建自定义IsLoaded属性?

EF4中没有更多IsLoaded属性。所有默认代码都是通过隐式延迟加载生成的。不再需要调用.Load()


不管当前的SelfTrackingEntities如何,t4都不支持任何类型的延迟加载。如果要访问导航属性,必须立即加载它们。延迟加载是可能的,您只需手动编辑t4模板。

不幸的是,我最初计划在HandleObjectMaterialized方法(从ObjectMaterialized事件调用)中的自跟踪实体上填充IsLoaded属性由于多对多集合仅在事件发生后填充,因此未按预期工作(请参阅文章)。我想在它跟踪的每个实体的上下文中迭代关系,测试IsLoaded属性,并在我的自跟踪实体上设置相应的IsLoaded属性

因此,我为First()和ToList()创建扩展方法,分别称为FirstWithLoaded()和ToListWithLoaded(),以使用反射:

public static T FirstOrDefaultWithLoaded<T>(this IQueryable<T> source) where T : new()
        {     
            T result = default(T);
            if (source != null)
            {       
                //Call the base FirstOrDefault
                result = source.FirstOrDefault();

                var querySource = source as ObjectQuery<T>;
                if (querySource != null)
                {
                    PopulateIsLoaded(result, querySource.Context);
                }
            }
            return result;
        }

        private static void PopulateIsLoaded(object inputEntity, ObjectContext dataContext)
        {
            var entry = dataContext.ObjectStateManager.GetObjectStateEntry(inputEntity);

            //var relationShipManagerProperty = entryType.GetProperty("RelationshipManager");//.GetValue(entityType, null);
            var relationShipManager = GetPropertyValue(entry, "RelationshipManager");// relationShipManagerProperty.GetValue(entry, null);

            if (relationShipManager != null)
            {
                //get the relationships (this is a sealed property)
                var relationships = GetPropertyValue(relationShipManager, "Relationships") as IEnumerable<RelatedEnd>;

                if (relationships != null)
                {
                    foreach (RelatedEnd relationship in relationships)
                    {
                        //check to see whether the relationship is loaded
                        var isLoaded = GetRelatedEndPropertyValue(relationship, "IsLoaded");

                        if (isLoaded != null && (bool)isLoaded)
                        {
                            //if the relationship is loaded then set the
                            //<NavigationPropertyName>IsLoaded on entry to true
                            var navigationProperty = GetRelatedEndPropertyValue(relationship, "NavigationProperty");
                            var identity = GetPropertyValue(navigationProperty, "Identity");

                            //get the IsLoaded property on entry
                            var isLoadedProperty = entry.Entity.GetType().GetProperty(identity + "IsLoaded");
                            if (isLoadedProperty != null)
                            {
                                isLoadedProperty.SetValue(entry.Entity, true, null);
                            }
                        }
                    }
                }
            }
        }

        private static object GetPropertyValue(object inputObject, string propertyName)
        {
            object result = null;

            if (inputObject != null)
            {
                var property = inputObject.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                if (property != null)
                {
                    result = property.GetValue(inputObject, null);
                }
            }

            return result;
        }

        private static object GetRelatedEndPropertyValue(RelatedEnd inputObject, string propertyName)
        {
            object result = null;

            if (inputObject != null)
            {
                PropertyInfo property = null;

                property = inputObject.GetType().GetProperty(propertyName, BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                if (property != null)
                {
                    result = property.GetValue(inputObject, null);
                }
            }

            return result;
        }
public static T FirstOrDefaultWithLoaded(此IQueryable源代码),其中T:new()
{     
T结果=默认值(T);
如果(源!=null)
{       
//调用基FirstOrDefault
结果=source.FirstOrDefault();
var querySource=源作为ObjectQuery;
if(querySource!=null)
{
PopulateIsLoaded(结果,querySource.Context);
}
}
返回结果;
}
私有静态void PopulateIsLoaded(对象inputenty、对象上下文dataContext)
{
var entry=dataContext.ObjectStateManager.GetObjectStateEntry(inputEntity);
//var relationShipManagerProperty=entryType.GetProperty(“RelationshipManager”);/.GetValue(entityType,null);
var relationShipManager=GetPropertyValue(条目,“relationShipManager”);//relationShipManagerProperty.GetValue(条目,null);
if(relationShipManager!=null)
{
//获取关系(这是一个密封的属性)
var relationships=GetPropertyValue(relationShipManager,“relationships”)作为IEnumerable;
if(关系!=null)
{
foreach(关系中的RelatedEnd关系)
{
//检查是否加载了关系
var isLoaded=GetRelatedEndPropertyValue(关系,“isLoaded”);
如果(isLoaded!=null&(bool)isLoaded)
{
//如果已加载关系,则设置
//输入为true时已加载
var navigationProperty=GetRelatedEndPropertyValue(关系,“navigationProperty”);
var identity=GetPropertyValue(navigationProperty,“identity”);
//在条目上获取IsLoaded属性
var isLoadedProperty=entry.Entity.GetType().GetProperty(标识+“IsLoaded”);
if(isLoadedProperty!=null)
{
isLoadedProperty.SetValue(entry.Entity,true,null);
}
}
}
}
}
}
私有静态对象GetPropertyValue(对象inputObject,字符串propertyName)
{
对象结果=空;
if(inputObject!=null)
{
var property=inputObject.GetType().GetProperty(propertyName,BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if(属性!=null)
{
结果=property.GetValue(inputObject,null);
}
}
返回结果;
}
私有静态对象GetRelatedEndPropertyValue(RelatedEnd inputObject,字符串propertyName)
{
对象结果=空;
if(inputObject!=null)
{
PropertyInfo属性=null;
property=inputObject.GetType().GetProperty(propertyName,BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if(属性!=null)
{
结果=property.GetValue(inputObject,null);
}
}
返回结果;
}
这个解决方案有点令人失望,因为我必须访问密封的属性“NavigationProperty”,然后访问NavigationProperty.Identity才能获得正确的导航(例如Person.Addresses而不是Person.Address)。希望将来会有更优雅的东西出现

注意:为了实现这一点,我更新了我的类型T4模板,为我创建了IsLoaded属性,例如,在Person上,我为地址创建了AddresseSloaded属性,如下所示:

<#
    if (navProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
        {
#>
    //The IsLoaded property for use on the client side when including collections
    [DataMember]
    <#=Accessibility.ForReadOnlyProperty(navProperty)#> bool <#=code.Escape(navProperty)#>IsLoaded
    {
        get; set;
    }
<#
        }
#>

//包含集合时在客户端使用的IsLoaded属性
[数据成员]
布尔孤岛
{