문제

선택한 데이터 소스에서 데이터를 성공적으로 가져오는 Linq 공급자가 있지만 필터링된 결과 집합이 있으므로 지금 하고 싶은 작업은 Linq to Objects가 나머지 식 트리(조인, 프로젝션 등)

내 생각에는 내 IQueryProvider가 포함된 식 상수를 ExpressionVisitor를 통해 결과 집합 IEnumerable로 바꾼 다음 해당 새 식을 반환할 수 있다는 것이었습니다.또한 내 IQueryable에서 IEnumerable의 공급자를 반환합니다. 하지만 작동하지 않는 것 같습니다. :-(

어떤 아이디어가 있나요?

편집하다:여기에 좋은 답변이 있지만 형식이 주어지면 ...

var qry = from c in MyProv.Table<Customer>()
          Join o in MyProv.Table<Order>() on c.OrderID equals o.ID
          select new 
          {
            CustID = c.ID,
            OrderID = o.ID
          }

내 공급자에서는 고객 및 주문에서 2개의 결과 집합을 쉽게 가져올 수 있습니다. 데이터가 SQL 소스에서 나온 경우 SQL 조인 구문을 구성하고 전달하기만 하면 되지만 이 경우 데이터는 SQL 소스에서 가져온 것이 아니므로 코드에서 조인을 수행해야 합니다...하지만 제가 말했듯이 2개의 결과 세트가 있고 Linq to Objects는 조인을 수행할 수 있습니다...(나중에 프로젝션) 표현식 상수를 대체하는 것이 정말 좋을 것입니다. MyProv.Table<Customer> 그리고 MyProv.Table<Order> ~와 함께 List<Customer> 그리고 List<Order> 그리고 List<> 공급자가 표현식을 처리합니다... 그게 가능합니까?어떻게?

도움이 되었습니까?

해결책 2

내가 추구했던 것은 표현식 트리의 Queryable<> 상수를 구체적인 IEnumerable(또는 .AsQueryable()을 통한 IQueryable) 결과 집합으로 바꾸는 것이었습니다...이것은 아마도 Linq에만 의미가 있는 복잡한 주제입니다. 표현 트리 방문자 등에 무릎을 꿇은 제공자 작가

내가 추구하는 것과 비슷한 작업을 수행하는 msdn 연습에서 조각을 찾았습니다. 이것은 나에게 앞으로 나아갈 길을 제공합니다...

using System;
using System.Linq;
using System.Linq.Expressions;

namespace LinqToTerraServerProvider
{
    internal class ExpressionTreeModifier : ExpressionVisitor
    {
        private IQueryable<Place> queryablePlaces;

        internal ExpressionTreeModifier(IQueryable<Place> places)
        {
            this.queryablePlaces = places;
        }

        internal Expression CopyAndModify(Expression expression)
        {
            return this.Visit(expression);
        }

        protected override Expression VisitConstant(ConstantExpression c)
        {
            // Replace the constant QueryableTerraServerData arg with the queryable Place collection.
            if (c.Type == typeof(QueryableTerraServerData<Place>))
                return Expression.Constant(this.queryablePlaces);
            else
                return c;
        }
    }
}

다른 팁

이전 답변은 모두 작동하지만 asenumerable ()을 사용하여 ienumerable에 시전하면 다음과 같이 더 잘 읽습니다.

// Using Bob's code...
var result = datacontext.Table
   .Where(x => x.Prop == val)
   .OrderBy(x => x.Prop2)
   .AsEnumerable()  //  <---- anything after this is done by LINQ to Objects
   .Select(x => new { CoolProperty = x.Prop, OtherProperty = x.Prop2 });

편집하다:

// ... or MichaelGG's
var res = dc.Foos
           .Where(x => x.Bla > 0)  // uses IQueryable provider
           .AsEnumerable()
           .Where(y => y.Snag > 0); // IEnumerable, uses LINQ to Objects

리포지토리 패턴을 구현 한 경우 iqueryable 뒷면을 제공하고 테이블을 추상화하는 것만으로 도망 갈 수 있습니다.

예시:

var qry = from c in MyProv.Repository<Customer>()
          Join o in MyProv.Repository<Order>() on c.OrderID equals o.ID
          select new 
          {
            CustID = c.ID,
            OrderID = o.ID
          }

그런 다음 제공자를 구축하여 리포지토리 메소드에서 iqueryable 패턴을 모델링하십시오. 이 기사 설명합니다.

이렇게하면 필요한 모든 것에 사용하기 위해 모든 종류의 공급자를 작성할 수 있습니다. LINQ 2 SQL 제공 업체를 보유하거나 단위 테스트에 대한 메모리 제공 업체를 작성할 수 있습니다.

LINQ 2 SQL 제공 업체의 저장소 방법은 다음과 같은 것으로 보입니다.

public IQueryable<T> Repository<T>() where T : class
{
    ITable table = _context.GetTable(typeof(T));
    return table.Cast<T>();
}

내가 오해하지 않는 한, 나는 일반적으로 LINQ 제공 업체가 실행하려는 지점에서 LINQ 메소드 체인에 .toArray ()를 추가합니다.

예를 들어 (LINQ에서 SQL을 생각하십시오)

var result = datacontext.Table
   .Where(x => x.Prop == val)
   .OrderBy(x => x.Prop2)
   .ToArray()
   .Select(x => new {CoolProperty = x.Prop, OtherProperty = x.Prop2});

따라서 Orderby ()를 통해 SQL로 변환되지만 select ()는 Linq to Objects입니다.

Rob의 대답은 좋지만 완전한 열거를 강요합니다. 확장 방법 구문 및 게으른 평가를 유지하기 위해 캐스트 할 수 있습니다.

var res = ((IEnumerable<Foo>)dc.Foos
            .Where(x => x.Bla > 0))  // IQueryable
          .Where(y => y.Snag > 0)   // IEnumerable
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top