문제

LINQ에서 엔티티 엔티티에 대한 저장소를 생성하는 데 T4를 사용하고 있습니다.

저장소에는 페이징에 적합한 목록 방법이 포함됩니다. 문서 지원 및 지원되지 않는 방법 언급하지는 않지만 "전화 할 수 없습니다" Skip 정렬되지 않은 IQueryable. 다음과 같은 예외를 제기합니다.

System.NotSupportedException : 'Skip'방법은 LINQ에서 엔티티에 정렬 된 입력에 대해서만 지원됩니다. 'OrderBy'방법은 'skip'방법 전에 호출되어야합니다 ..

부분 메소드를 통해 기본 정렬을 정의하여 해결했습니다. 하지만 표현 트리에 실제로 포함되어 있는지 확인하는 데 문제가 있습니다. OrderBy.

문제를 가능한 한 적은 코드로 줄였습니다.

public partial class Repository
{
    partial void ProvideDefaultSorting(ref IQueryable<Category> currentQuery);

    public IQueryable<Category> List(int startIndex, int count)
    {
        IQueryable<Category> query = List();
        ProvideDefaultSorting(ref query);
        if (!IsSorted(query))
        {
            query = query.OrderBy(c => c.CategoryID);
        }
        return query.Skip(startIndex).Take(count);
    }
    public IQueryable<Category> List(string sortExpression, int startIndex, int count)
    {
           return List(sortExpression).Skip(startIndex).Take(count);
    }
    public IQueryable<Category> List(string sortExpression)
    {
        return AddSortingToTheExpressionTree(List(), sortExpression);
    }
    public IQueryable<Category> List()
    {
           NorthwindEntities ent = new NorthwindEntities();
           return ent.Categories;
    }

    private Boolean IsSorted(IQueryable<Category> query)
    {
        return query is IOrderedQueryable<Category>; 
    }
}

public partial class Repository
{
    partial void ProvideDefaultSorting(ref IQueryable<Category> currentQuery)
    {
        currentQuery = currentQuery.Where(c => c.CategoryName.Contains(" ")); // no sorting..
    }
}

이것은 나의 실제 구현이 아닙니다!

하지만 나의 의문 어떻게 구현할 수 있습니까? IsSorted 방법? 문제는 Linq to Entities Query 's가 항상 유형이라는 것입니다. ObjectQuery, 그것을 구현합니다 IOrderedQueryable.

그래서 어떻게 확인 해야하는지 OrderBy 표현식 트리에 방법이 있습니까? 나무를 구문 분석하는 유일한 옵션입니까?

업데이트
저장소에 정렬 지원을 추가하는 방법에 관한 것이 아니라 ProvideDefaultSorting 부분적 방법이 실제로 추가되었습니다 OrderBy 발현 트리에.

문제는 첫 번째 부분 클래스가 템플릿에 의해 생성되며 부분 클래스의 두 번째 부분의 구현은 다른 시간에 팀 구성원에 의해 이루어진다는 것입니다. .NET Entity Framework가 EntityContext를 생성하는 방식과 비교할 수 있으며 다른 개발자의 확장 지점이 허용됩니다. 그래서 나는 그것을 강력하게 만들고 싶고 ProvideDefaultSorting 올바르게 구현되지 않았습니다.

그래서 질문은 더 많을 것입니다. 어떻게 ProvideDefaultSorting 실제로 발현 트리에 정렬을 추가했습니다.

업데이트 2
새로운 질문이 답변되었고 받아 들여졌으며, 나는 질문에 더 일치하도록 제목을 변경해야한다고 생각합니다. 아니면이 솔루션에 동일한 문제가있는 사람들을 이끌어 내기 때문에 현재 제목을 남겨 두어야합니까?

도움이 되었습니까?

해결책

이를 제공하는 덕분에 반환 유형에서 해결할 수 있습니다. 이 코드는 다음과 같습니다.

    public IOrderedQueryable<int> GetOrderedQueryable()
    {
        IQueryable<int> myInts = new List<int>() { 3, 4, 1, 2 }.AsQueryable<int>();
        return myInts.Where(i => i == 2);
    }

이 코드는 구축되지만 교활하며 코더는 자격이있는 것을 얻습니다.

    public IOrderedQueryable<int> GetOrderedQueryable()
    {
        IQueryable<int> myInts = new List<int>() { 3, 4, 1, 2 }.AsQueryable<int>();
        return myInts.Where(i => i == 2) as IOrderedQueryable<int>;
    }

Ref와 같은 이야기 (이것은 빌드되지 않습니다) :

    public void GetOrderedQueryable(ref IOrderedQueryable<int> query)
    {
        query = query.Where(i => i == 2);
    }

다른 팁

페이징은 강한 방식으로 주문에 달려 있습니다. 왜 운영을 단단히 결합하지 않습니까? 다음과 같은 방법은 다음과 같습니다.

객체를 지원합니다

public interface IOrderByExpression<T>
{
  ApplyOrdering(ref IQueryable<T> query);
}

public class OrderByExpression<T, U> : IOrderByExpression<T>
{
  public IQueryable<T> ApplyOrderBy(ref IQueryable<T> query)
  {
    query = query.OrderBy(exp);
  }
  //TODO OrderByDescending, ThenBy, ThenByDescending methods.

  private Expression<Func<T, U>> exp = null;

  //TODO bool descending?
  public OrderByExpression (Expression<Func<T, U>> myExpression)
  {
    exp = myExpression;
  }
}

논의중인 방법 :

public IQueryable<Category> List(int startIndex, int count, IOrderByExpression<Category> ordering)
{
    NorthwindEntities ent = new NorthwindEntities();
    IQueryable<Category> query = ent.Categories;
    if (ordering == null)
    {
      ordering = new OrderByExpression<Category, int>(c => c.CategoryID)
    }
    ordering.ApplyOrdering(ref query);

    return query.Skip(startIndex).Take(count);
}

얼마 후, 방법을 호출합니다.

var query = List(20, 20, new OrderByExpression<Category, string>(c => c.CategoryName));

나는 그것이 그것보다 조금 더 힘들다는 것을 두려워합니다. 알다시피, 엔티티 프레임 워크는 특정 상황에서 질서를 조용히 무시하십시오. 따라서 표현식 트리에서 Orderby를 찾는 것만으로는 충분하지 않습니다. 주문은 "오른쪽"장소에 있어야하며 "오른쪽"장소의 정의는 엔티티 프레임 워크의 구현 세부 사항입니다.

지금까지 추측 한 것처럼, 나는 당신과 같은 곳에 있습니다. 엔티티 리포지토리 패턴을 사용하고 프레젠테이션 레이어에서 테이크/스킵을하고 있습니다. 내가 사용한 솔루션은 아마도 이상적이지는 않지만 내가하고있는 일에 충분히 좋은 것은 마지막 순간까지 주문을하지 않는 것입니다. 따라서 (직접 또는 간접적으로) 테이크/스킵 (직접 또는 간접적으로)을 수행하는 모든 조치는 먼저 Orderby를 삽입합니다. 코드는 한 번만 발생할 수 있도록 구성되어 있습니다.

David B 덕분에 다음 솔루션이 있습니다. (부분적 방법이 실행되지 않았거나 방금 매개 변수를 반환하지 않은 상황에 대한 탐지를 추가해야했습니다).

public partial class Repository
{
    partial void ProvideDefaultSorting(ref IOrderedQueryable<Category> currentQuery);

    public IQueryable<Category> List(int startIndex, int count)
    {
        NorthwindEntities ent = new NorthwindEntities();
        IOrderedQueryable<Category> query = ent.CategorySet;
        var oldQuery = query;
        ProvideDefaultSorting(ref query);
        if (oldQuery.Equals(query)) // the partial method did nothing with the query, or just didn't exist
        {
            query = query.OrderBy(c => c.CategoryID);
        }
        return query.Skip(startIndex).Take(count);
    }
    // the rest..        
}

public partial class Repository
{
    partial void ProvideDefaultSorting(ref IOrderedQueryable<Category> currentQuery)
    {
        currentQuery = currentQuery.Where(c => c.CategoryName.Contains(" ")).OrderBy(c => c.CategoryName); // compile time forced sotring
    }
}

컴파일 시간에 부분 메소드가 구현되면 최소한 iorderdqueryable을 유지해야합니다.

부분 메소드가 구현되지 않았거나 매개 변수를 반환하면 쿼리가 변경되지 않으며 폴백 정렬을 사용합니다.

    ProvideDefaultSorting(ref query);
    if (!IsSorted(query))
    {
            query = query.OrderBy(c => c.CategoryID);
    }

로 변경:

    //apply a default ordering
    query = query.OrderBy(c => c.CategoryID);
    //add to the ordering
    ProvideDefaultSorting(ref query);

완벽한 솔루션이 아닙니다.

당신이 언급 한 "순서 함수의 필터"문제를 해결하지 못합니다. "주문을 구현하는 것을 잊어 버린"또는 "주문하지 않기로 선택합니다"를 해결합니다.

LinqToSQL 에서이 솔루션을 테스트했습니다.

    public void OrderManyTimes()
    {
        DataClasses1DataContext myDC = new DataClasses1DataContext();
        var query = myDC.Customers.OrderBy(c => c.Field3);
        query = query.OrderBy(c => c.Field2);
        query = query.OrderBy(c => c.Field1);

        Console.WriteLine(myDC.GetCommand(query).CommandText);

    }

생성 (순서의 역 순서 참고) :

SELECT Field1, Field2, Field3
FROM [dbo].[Customers] AS [t0]
ORDER BY [t0].[Field1], [t0].[Field2], [t0].[Field3]

기본 정렬 순서가 지정되지 않았기 때문에 기본 키로 모든 컬렉션을 정렬하는 솔루션을 구현했습니다. 아마도 그것은 당신에게 효과가있을 것입니다.

보다 http://johnkaster.wordpress.com/2011/05/19/a-bug-fix-for-system-linq-dynamic-and-a-solution-for-the-entity-framework-4-skip-problem/ 토론과 범용 코드. (동적 Linq에 대한 부수적 인 버그 수정).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top