2009-12-21 6 views
3

EF 4.0과 함께 자체 추적 엔티티를 사용하고 있으며, 표준 EF 개체에있는 것과 같이 다 대다 관계에 참여하는 탐색 개체의 IsLoaded 속성이 없음을 알았습니다. 따라서 Person을 쿼리하고 Include Addresses를 사용하지 않으면 Person.Addresses에 대한 빈 목록이 나오지만 주소가로드되었는지 또는 주소가 없는지 여부를 알 수있는 방법이 없습니다.IsLoaded 자체 추적 엔티티

탐색 속성이 자체 추적 엔터티에로드되었는지 여부를 확인하는 방법이 있습니까?

그리고 현재 ObjectQuery에서 현재 ObjectQuery에 액세스 할 수있는 방법이 없기 때문에 사용자가 어떤 속성을 확장하고 사용자 지정 IsLoaded 속성을 만들 수 있는지 알 수 있습니까?

+0

이를 위해 내장 어디에도 없습니다 만,이는 내가 같은 주소에 대한 AddressesIsLoaded 속성을 만들어 내게 예를 들어, 사람에의 IsLoaded 표시 속성을 만들 내 유형 T4 템플릿을 업데이트 작동하기 위해서는

주 당신은 직접 그것을 쓸 수 있습니다. –

답변

1

아쉽게도 ObjectMaterialized 이벤트에서 호출 된 HandleObjectMaterialized 메서드의 자체 추적 엔터티에 IsLoaded 속성을 채우려는 원래 계획이 이벤트 후 많은 수의 컬렉션에만 채워지기 때문에 원하는대로 작동하지 않았습니다. this 게시물). 그리고 추적하고있는 각 엔티티에 대한 컨텍스트에서 관계를 반복하고, IsLoaded 속성을 테스트하고 자체 추적 엔터티에 해당 IsLoaded 속성을 설정하려고했습니다.

그래서 대신에 나는이 같은 대한 반사를 사용하는 첫 번째()와 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; 
     } 

이 솔루션은 약간 I가 한 점에서 dissapointing한다 올바른 탐색 (예 : Person.Address 대신 Person.Addresses)을 얻으려면 봉인 된 속성 "NavigationProperty"에 액세스 한 다음 NavigationProperty.Identity에 액세스하십시오. 다행히 뭔가 더 우아한 뭔가가 미래에 나타날 것입니다.

<# 
    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

EF4에는 더 이상 IsLoaded가 없습니다. 모든 기본 코드는 암시 적 지연로드로 생성됩니다. 더 이상 .Load()를 호출 할 필요가 없습니다.

현재의 SelfTrackingEntities t4는 모든 종류의 지연로드를 지원하지 않습니다. 액세스하려는 경우로드 탐색 특성을 열망해야합니다. 게으른 로딩이 가능합니다. t4 템플릿을 수동으로 편집해야합니다.

+0

감사합니다 jfar, 컨텍스트에서 전체 개체 쿼리에 액세스하는 방법을 알고 계십니까 (예를 들어 사용자가 Person.Include ("Addresses")를 원할 경우 Person에 AddressesIsLoaded 속성을 설정하고 싶습니까? –

+0

당신이 이미 답변을 알고있는 것처럼 들리네. 내가하는 일이나 Person을 검색하는 DAL 메서드에서 설정하는 것. 나는 모든 것에 과부하를 두는 경향이있다. 그래프를 열심히로드하는 것 GetPerson (int id, bool eager) – jfar

+1

이 대답은 실제로 잘못된 것입니다 .EF 4에는 확실히 IsLoaded가 있습니다. lazy 로딩의 경우에도 유용합니다 * 옵션 *이 아닌 필수 옵션입니다. 자기 추적 엔티티는 코드를 작성하는 경우 게으른로드를 수행 할 수 있으며 자기 추적 엔티티의 요점은이 기능을 제어 할 수 있어야한다는 것입니다. 너 자신이야. –

관련 문제