IsLoaded для самостоятельных отслеживаний - PullRequest
3 голосов
/ 21 декабря 2009

Я использую объекты самоконтроля в EF 4.0 и вижу, что для объектов навигации, которые участвуют в отношениях «многие ко многим», отсутствует свойство IsLoaded, как в стандартных объектах EF. Поэтому, если вы запрашиваете информацию о персоне и не включаете адреса, тогда для персоны появляется пустой список. Адреса, но невозможно определить, были ли загружены адреса или у человека просто нет адресов.

Есть ли способ узнать, было ли загружено свойство навигации на объектах с самообследованием?

А если нет, то есть ли способ получить доступ к текущему ObjectQuery из ObjectContext, чтобы я мог видеть, какие свойства пытается расширить пользователь и создавать собственные свойства IsLoaded?

Ответы [ 2 ]

1 голос
/ 07 января 2010

К сожалению, мой первоначальный план по заполнению свойств IsLoaded самосопровождаемыми объектами в методе HandleObjectMaterialized (вызываемом из события ObjectMaterialized) не сработал должным образом, так как множество для многих коллекций заполняется только после события (см. этот пост). И я хотел перебрать отношения в контексте для каждой сущности, которую он отслеживает, протестировать свойство IsLoaded и установить соответствующее свойство IsLoaded в моей сущности Self-tracking.

Поэтому вместо этого я создаю методы расширения для 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;
        }

Это решение слегка разочаровывает тем, что мне пришлось получить доступ к запечатанному свойству "NavigationProperty", а затем NavigationProperty.Identity, чтобы получить правильную навигацию (например, Person.Addresses вместо Person.Address). Надеюсь, что в будущем появится что-то более элегантное.

Обратите внимание, чтобы это работало, я обновил свой шаблон Types T4, чтобы создать для меня свойства IsLoaded, например, для Person я создал свойство AddressesIsLoaded для адресов как:

<#
    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;
    }
<#
        }
#>
0 голосов
/ 21 декабря 2009

В EF4 больше нет IsLoaded. Весь код по умолчанию генерируется с неявной ленивой загрузкой. Больше не нужно вызывать .Load ().

Независимо от текущей версии SelfTrackingEntities t4 не поддерживает отложенную загрузку. Вы должны стремиться загрузить свойства навигации, если вы хотите получить к ним доступ. Возможна отложенная загрузка, вам просто нужно будет вручную редактировать шаблон t4.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...