2011-02-15 4 views
4

MappedItem 클래스 목록을 생성하려고하면 오류가 발생합니다 (아래 참조). 간단히 말해서 아래의 코드 예제는 범주, 날짜 범위 및 SKU별로 제품을 찾으려고합니다. 내가 가진 요구 사항은 사용자가 쉼표로 구분 된 SKU 목록을 입력 할 수 있어야하며 검색은 사용자가 입력 한 SKU 중 하나로 시작하는 모든 제품을 찾는 것입니다. 코드를 실행하면 얻을 수 있습니다.LINQ to SQL 구현시 로컬 시퀀스를 사용할 수 없습니다.

로컬 시퀀스는 Contains() 연산자를 제외한 쿼리 연산자의 LINQ to SQL 구현에 사용할 수 없습니다.

문자열리스트로의 SKU 콤마 구분 된 문자열로 변환 :

축약 된 시퀀스는이된다.

string sku = TextSKU.Text; 
List<string> skuList = sku.Split(new char[] { ',' }).ToList(); 

검색 결과를 허용 할 클래스의 코드를 다른 곳에서 정의하십시오.

public class MappedItem 
{ 
    public string ItemDescription { get; set; } 
    public int ItemCount { get; set; } 

    public MappedItem() 
    { 

    } 

    public MappedItem(string itemDescription, int itemCount) 
    { 
     ItemDescription = itemDescription; 
     ItemCount = itemCount; 
    } 
} 

여기에 내가 범인은 내가 추출 아래에 표시 한 코드의 라인이라고 생각

List<MappedItem> widgetItems = (from c1 in db.CCRCodes 
           join pac in db.widgetAssignedCodes on c1.code_id equals pac.code_id 
           join ph in db.widgetHistories on pac.history_id equals ph.history_id 
           where ph.contact_dt.Value.Date >= startDate && ph.contact_dt.Value.Date <= endDate && 
            (string.IsNullOrEmpty(baanCatFam) || ph.baan_cat_family_code == baanCatFam) && 
            (string.IsNullOrEmpty(baanCat) || ph.baan_cat_code == baanCat) && 
            (string.IsNullOrEmpty(baanSubCat) || (ph.baan_sub_cat_code == baanSubCat)) && 
            (string.IsNullOrEmpty(sku) || skuList.All(sl => ph.product_mod.StartsWith(sl))) 
           group c1 by c1.code_desc into ct 
           select new MappedItem 
           { 
            ItemDescription = ct.Key.ToUpper(), 
            ItemCount = ct.Count() 
           }).OrderByDescending(m => m.ItemCount) 
           .ToList(); 

에서 내 결과를 생성하는 쿼리입니다.

skuList.All(sl => ph.product_mod.StartsWith(sl)) 

는 사용자 입력의 SKU 쉼표로 구분 목록에서 파생 skuList에서 요소로 시작하는 모든 SKU를 식별. 내 질문은이 오류의 원인과 코드 예제를 통해 해결할 수있는 일입니다.

답변

5

첫 번째 - 논리적으로 원하는 것은 모두가 아니라 전부입니다.

둘째로, 이것은 쿼리 필터를 작성하는 좋은 방법이 아닙니다. 이러한 작업은 모두 데이터베이스로 보내지 만 적용 할 필터를 결정하는 정보는 이미 로컬입니다. 명시 적 조인도 좋지 않습니다 (연결 속성을 대신 사용할 수 있음).

IQueryable<WidgetHistory> query = db.widgetHistories 
    .Where(ph => ph.contact_dt.Value.Date >= startDate 
    && ph.contact_dt.Value.Date <= endDate); 

if (!string.IsNullOrEmpty(baanCatFam)) 
{ 
    query = query.Where(ph => ph.baan_cat_family_code == baanCatFam); 
} 
if (!string.IsNullOrEmpty(baanCat)) 
{ 
    query = query.Where(ph => ph.baan_cat_code == baanCat); 
} 
if (!string.IsNullOrEmpty(baanSubCat)) 
{ 
    query = query.Where(ph => ph.baan_sub_cat_code == baanSubCat); 
} 

//TODO sku filtering here. 

List<MappedItem> widgetItems = 
    from ph in query 
    let c1 = ph.widgetAssignedCode.CCRCode 
    group c1 by c1.code_desc into g 
    select new MappedItem 
    { 
    ItemDescription = g.Key.ToUpper(), 
    ItemCount = g.Count() 
    }).OrderByDescending(m => m.ItemCount) 
    .ToList(); 

세 번째 : 질문에 대한 답변입니다.

LinqToSql의 쿼리 공급자가 SQL로 해당 지역의 수집을 변환 할 수 없습니다이 오류의 원인을

. ... .Where(ph => idList.Contains(ph.Id))은 idList에 int 당 1 매개 변수가있는 IN 절로 변환됩니다.

이 제한 사항을 해결하려면 로컬 컬렉션을 표현식으로 변환해야합니다. , @Ddavid을

if (skuFilters.Any()) //this part goes into where it says "TODO" 
{ 
    Expression<Func<WidgetHistory, bool>> theSkuFilter = skuFilters.OrTheseFiltersTogether() 
    query = query.Where(theSkuFilter); 
} 
+0

당신을 :

List<Expression<Func<WidgetHistory, bool>>> skuFilters = skuList.Select<string, Expression<Func<WidgetHistory, bool>>>(skuItem => ph => ph.ProductMod.StartsWith(skuItem) ).ToList(); 

다음, 헬퍼 방법 :

public static Expression<Func<T, bool>> OrTheseFiltersTogether<T>( this IEnumerable<Expression<Func<T, bool>>> filters) { Expression<Func<T, bool>> firstFilter = filters.FirstOrDefault(); if (firstFilter == null) { Expression<Func<T, bool>> alwaysTrue = x => true; return alwaysTrue; } var body = firstFilter.Body; var param = firstFilter.Parameters.ToArray(); foreach (var nextFilter in filters.Skip(1)) { var nextBody = Expression.Invoke(nextFilter, param); body = Expression.OrElse(body, nextBody); } Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(body, param); return result; } 

이제 모두 함께 넣어 필터링 식으로 컬렉션의 각 항목을 tranforming에 의해 시작 록! –