2017-11-13 19 views
1

나는 Provider 클래스와 Article 1을가집니다. 기사에는 int ProviderId{get;set}public virtual Provider Provider {get;set;} 속성이 있습니다.Entity Framework 6에서 하위 엔터티를 동적으로로드하는 방법

나는 게으른 로딩에 대해 알고 내가 컨텍스트 외부에서 문서의 제공자 속성에 액세스 할 수는 없지만 내가 왜 이런 식으로 다음 T를 반환하는 일반적인 방법이 있습니다

public static T Next<T>(T currentElement) where T : class, IModel { 
    T data; 

    if (currentElement.Id >= GetLastId<T>()) 
     return currentElement; 

    using (DatabaseEntities context = new DatabaseEntities()) { 
     data = context.Set<T>().Single(el => el.Id == currentElement.Id + 1); 
    } 

    return data; 
} 

을하지만 그럴 수 없어 기사 클래스에서 공급자와 같은 자식 엔티티 검색 모든 엔티티를 포함하려면 어떻게해야합니까? 메소드를 업데이트하고 엔티티 당 하나를 만들어야합니까?

Eager loadingExplicit loading에 대해 읽었지 만 이러한 방법으로 어떻게 구현할 수 있는지 알 수 없습니다.

참고 :

모든 내 엔티티 엔티티 아이들이 내가 Previous<T>(), First<T>() 또는 예상 한 일을 Last<T>() 같은 많은 방법이있다.

+0

귀하의 질문에 대답하지,하지만 난 당신의 다음 요소를 얻기 위해 '아이디 + 1'을 사용하여 생각 위험 할 수 있습니다. 테이블의 행이 삭제되면 예외가 throw됩니다. – DavidG

+0

답변으로,이 방법에 포함 목록을 전달할 수 있습니까? – DavidG

+0

@DavidG 당신은 Id 문제로 옳습니다. 따라서 모든 레코드를 목록에 저장해야합니까 (아마도 3000)? 그러나 이번에는 행을 삭제할 수 없으며, 그렇습니다. 포함 할 수 있습니다. – legomolina

답변

1

가능한 포함 목록을 가져 오는 방법을 확장 할 수 있습니다. 예를 들면 :

public static T Next<T>(T currentElement, params Expression<Func<T, object>>[] includes) 
    where T : class, IModel 
{ 
    if (currentElement.Id >= GetLastId<T>()) 
     return currentElement; 

    using (DatabaseEntities context = new DatabaseEntities()) 
    { 
     IQueryable<T> query = context.Set<T>(); 

     //Deferred execution allows us to build up the query 
     foreach (var include in includes) 
     { 
      query = query.Include(include); 
     } 

     return query.Single(el => el.Id == currentElement.Id + 1); 
    } 
} 

그리고 다음과 같이 사용 :

var someEntity = ...; 

var nextEntity = Next(someEntity, 
    e => e.Childcollection1, 
    e => e.Childcollection2, 
    // 
    e => e.ChildcollectionN) 

추가 점으로, 다음 개체를 얻을, 당신은 예를 들어, ID 값이 순차적 인에 의존해서는 안, 그들은 항목이 삭제되면 순서가 벗어납니다. 대신,이 같은 고려 : 당신은 당신의 Next 방법의 과부하를 만들 수

return query.OrderBy(el => el.Id).First(el => el.Id > currentElement.Id); 
+0

고마워요, 집에 돌아올 때 한번 시도해 보겠습니다. 스 니펫이 다음 요소를 가져 주셔서 감사합니다.) – legomolina

+0

완벽하게 작동합니다! 고마워요 : D – legomolina

1

을 그 받아들이는 Expression<Func<T, object>> :

public static T Next<T>(T currentElement, Expression<Func<T, object>> navigationProperty) where T : class, IModel 
{ 
    T data; 

    if (currentElement.Id >= GetLastId<T>()) 
     return currentElement; 

    using (DatabaseEntities context = new DatabaseEntities()) 
    { 
     IQueryable<T> dbQuery = context.Set<T>(); 
     if (navigationProperty != null) 
      dbQuery = dbQuery.Include<T, object>(navigationProperty); 

     data = dbQuery.AsNoTracking().Single(el => el.Id == currentElement.Id + 1); 
    } 
    return data; 
} 

사용법 :

var entity = Next(instance, x => x.Provider); 

받는 참조하십시오 더 많은 정보와 완전한 예를 들어 블로그 게시물을 따르십시오. 엔티티 프레임 워크를 사용하여 일반 데이터 액세스 레이어를 구현

는 : 그래서 https://blog.magnusmontin.net/2013/05/30/generic-dal-using-entity-framework/

0

당신은 ProviderArticle 사이에 일대 다 관계를 가지고 모든 Provider는 0 개 이상의 Articles을 가지고, 그리고 모든 Article 정확히을 속한 하나 Provider. 만약 엔티티 프레임 워크에서 올바르게 일대 다 관계를 구성한 경우

, 프로 바이더는 많은 Articles 참조를 가져야한다 : 또한

public virtual ICollection<Article> Articles{get; set;} 

는 입력 int로서 취하는 함수 Next을 가지고 클래스 T의 객체이며, IModel을 구현하는 클래스입니다. Next은 다음 요소에 대한 적절한 정의가 있다고 가정하고 Ts의 DbSet에서 다음 요소를 반환합니다.

분명히 다음 함수를 사용하려면이 함수를 사용하여 다음을 얻는 것 Provider 모두가 Articles이어야합니다.

보다 일반적인 : T가 올바르게 설계된 일대 다 관계가있는 유형이고 T 유형의 객체가있는 경우 첫 번째 ID가 현재 T의 ID보다 높은 T를 원한다. , 모든 ICollections 포함.

나는 단절 작은 함수로이 분할했습니다

  • 유형 주어진 T는 ICollection에
  • 주어진 DbSet가 DbSet의 모든 요소를 ​​반환하는 함수 구현하는 모든 속성을 반환하는 함수 포함하는 모든 사람들이 주어진 ICollections

OrderByFirstOrDefault 당신의 모든 기사와 현재의 공급자보다 큰 ID를 가진 최초의 공급자를 얻을 수있을 것 같은 기능을 수행합니다.

static class QueryableExtensions 
{ 
    // returns true if PropertyInfo implements ICollection<...> 
    public static bool ImplementsICollection(this PropertyInfo propertyInfo) 
    { 
     return propertyInfo.IsGenericType 
      && propertyInfo.GetGenericTypeDefinition() == typeof(ICollection<>); 
    } 

    // returns all readable & writable PropertyInfos of type T that implement ICollection<...> 
    public static IEnumerable<PropertyInfo> CollectionProperties<T>() 
    { 
     return typeof(T).GetProperties() 
      .Where(prop => prop.CanRead 
       && prop.CanWrite 
       && prop.PropertyType.ImplementICollection(); 
    } 

    // given an IQueryable<T>, adds the Include of all ICollection<...> T has 
    public static IQueryable<T> IncludeICollection<T>(IQueryable<T> query) 
    { 
     var iCollectionProperties = CollectionProperties<T>(); 
     foreach (var collectionProperty in collectionProperties) 
     { 
       query = query.Include(prop.Name); 
     } 
     return query; 
    } 

    // given a IQueryable<T> and a T return the first T in the query with Id higher than T 
    // for this we need to be sure every T has an IComparable property Id 
    // so T should implement interface IId (see below) 
    public T Next<T>(this IQueryable<T> query, T currentItem) 
     where T : IId // makes sure every T has aproperty Id 
    { 
     T nextElement = query 
      // keep only those DbSet items that have larger Ids: 
      .Where(item => currentItem.Id < item.Id) 
      // sort in ascending Id: 
      .OrderBy(item => item.Id 
      // keep only the first element of this sorted collection: 
      .FirstOrDefault(); 
     return T 
    } 
} 

내가 그렇지 않으면 다음 ID를 가져올 수 없습니다, 모든 T는 ID를 가지고 있는지 확인해야합니다. 같은 이러한 기능을 한 후 쿼리가 될 것입니다

public Interface IId 
{ 
    public int Id {get;} 
} 

: 아마 당신은 당신의 IModel 해당 인터페이스이이

public static T Next<T>(T currentElement) where T : class, IModel, IId 
{ 
    T data; 
    if (currentElement.Id >= GetLastId<T>()) 
     return currentElement; 

    using (DatabaseEntities context = new DatabaseEntities()) 
    { 
     return context.Set<T>().Next(currentElement); 
    } 
} 
+0

이것은 내가 원하는 반대입니다. 내 목표는 내가 기사를 얻을 때 공급자를 얻을 수 있지만 내가 반대를 해야하는지 한번 살펴 보겠습니다. 감사 – legomolina