2009-03-30 5 views
7

나는 선택한 데이터 소스에서 데이터를 성공적으로 가져오고 가져 오는 Linq 공급자가 있지만, 필자는 필터링 된 결과 집합을 허용하고 싶습니다. 허용하고 있습니다. Linq가 나머지 Expression Tree를 처리합니다 (조인, 프로젝션 등)IQueryable 쿼리의 일부를 수행하고 나머지를 Linq에 객체에 대해 연기합니다.

내 IQueryProvider를 포함하는 표현식 상수를 ExpressionVisitor를 통해 결과 집합 IEnumerable로 바꿀 수 있다고 생각했습니다. 새 표현식을 반환하십시오. 또한 내 된 IQueryable에서는 IEnumerable의 제공을 반환 ...하지만이

어떤 생각의

편집 :-(작동하지 않습니다? ... 형태로 주어진 여기 좋은 답변,하지만

내 공급자의 경우 고객 및 주문에서 2 개의 결과 집합을 쉽게 얻을 수 있습니다. 데이터가 SQL 원본에서 나온 것이라면 SQL 결합 구문을 작성하여 전달하지만이 경우 데이터는 SQL 소스 그래서 코드에서 조인 할 필요가 ...하지만 내가 말했듯이 2 결과 집합 및 Linq 개체 조인 할 수 있습니다 ... (나중에 projection) 표현식 상수 MyProv.Table<Customer>MyProv.Table<Order>List<Customer>List<Order>으로 대체하고 List<> 제공자가 표현식을 처리하도록하면 정말 좋을 것입니다 ... 가능합니까? 방법?

답변

3

난 후 Queryable에서 <를 교체 하였다 물건의 종류> 식 트리에서 상수 콘크리트를 IEnumerable (또는 된 IQueryable을 통해와 .AsQueryable()) result set ... 이것은 표현 트리 방문객 등 깊은 Linq Provider 작가에게만 의미있는 복잡한 주제입니다.

뭔가를하는 msdn 연습에 스 니펫을 발견했습니다. 방금 멀리 뒤로 추상적 인 테이블을 IQueryable을 제공 멀리 얻을 수있는 저장소 패턴을 구현하는 경우 I 후 나는 무엇처럼이 나에게 기대하는 방법 ...

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; 
     } 
    } 
} 
+0

내 무릎에서 감사 - 깊은 식 트리의 방문자에. :) 이것은 정확하게 내가 필요로 한 것입니다 – Rik

1

오해가 아니라면 일반적으로 linq 공급자를 실행하려는 지점에서 .ToArray()를 linq 메서드 체인에 추가합니다.

예를 들어) 그래서있는 OrderBy 통해

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

을 ((SQL Linq에 생각) SQL로 번역됩니다 만, 선택은() 객체에 LINQ이다.

0

롭의 대답은 좋지만 전체 열거 형이어야합니다. 당신이 AsEnumerable를 사용하는 경우()는 IEnumerable로 된 IQueryable을 캐스팅 이전 답변 모두 작동

var res = ((IEnumerable<Foo>)dc.Foos 
      .Where(x => x.Bla > 0)) // IQueryable 
      .Where(y => y.Snag > 0) // IEnumerable 
5

하지만 더 읽습니다 :

// 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 
1

을 제공합니다.

예 :

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 
      } 

하고 그냥 this article이 보여처럼 저장소 방법으로 된 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>(); 
} 
+0

매우 흥미 롭습니다. 저는 이번 주말에이 문제를 해결할 것입니다. –