4

嗨,Linq to Entity和Contains?

我有一個這樣的LINQ to SQL的問題:

tmpAdList1 = (from p in context.Ads 
          join h in context.AdCategories on p.CategoryId equals h.Id 
          join l in context.Location on p.UserLocationId equals l.Id 
          where 
          (adList.S == null || adList.S.Length < 1 || p.Title.Contains(adList.S) || p.Description.Contains(adList.S)) && 
          (categorylevelOrder.Length < 1 || h.LevelOrder.StartsWith(categorylevelOrder)) && 

          ((locationIdList != null && lList.Contains(l.Id)) || 
          (locationLevelOrder.Length < 1 || l.LevelOrder.StartsWith(locationLevelOrder))) && 

          ((adTypeO1 == AdType.Unknown && adTypeO2 == AdType.Unknown && adTypeO3 == AdType.Unknown && adTypeO4 == AdType.Unknown && adTypeO5 == AdType.Unknown) || 
          (p.TypeOfAd == (int)adTypeO1 || p.TypeOfAd == (int)adTypeO2 || p.TypeOfAd == (int)adTypeO3 || p.TypeOfAd == (int)adTypeO4 || p.TypeOfAd == (int)adTypeO5)) && //Check for default filters 
          ((AdListShowType)adList.ALS.ST == AdListShowType.Both || adList.ALS.ST == p.OwnerType) && 
          (p.PublishedDate.HasValue && p.PublishedDate.Value.CompareTo(fetchAdsTo) >= 1) && 
          ((adOwnerType1.HasValue && adOwnerType2.HasValue) || p.OwnerType == (int)adOwnerType1.Value) && 
          p.InactivatedDate == null 
          orderby p.CreatedDate descending 
          select p).ToList(); 

見EDIT1整個方法

後,這個問題是拼命地跑一些更多的過濾會做(在上下文中),但爲了儘可能快地做到這一點,我的目標是在第一個問題中儘可能從SQL服務器獲取儘可能少的記錄。

問題是我需要比較一個int []的locationIdList到實體。拋出的異常是:

無法比較類型爲'System.Int32 []'的元素。只支持原始類型(如Int32,String和Guid)和實體類型。

我有谷歌這個問題,這是一個已知的問題,我已經發現但像這樣的例子:

var list = new List<int> { 1, 2, 3, 5 }; 
var result = from s in DB.Something 
      where list.Contains(s.Id) 
      select s; 

但是,這將引發相同的異常?我也讀過一個存儲過程可以解決這個問題,但我還沒有找到這個工作?

有什麼建議嗎?

BestRegards

EDIT1:整個方法:

public List<Ad> GetAds(AdList adList, DateTime fetchAdsTo, out int totalAds) 
{ 
    AdType adTypeO1 = AdType.Unknown; 
    AdType adTypeO2 = AdType.Unknown; 
    AdType adTypeO3 = AdType.Unknown; 
    AdType adTypeO4 = AdType.Unknown; 
    AdType adTypeO5 = AdType.Unknown; 

    int? adOwnerType1 = null; 
    int? adOwnerType2 = null; 

    FilterModel filterModel = new FilterModel(); 

    List<AdCategoryFilter> adCategoryFilterList; 
    AdsFilterValues adsFilterValues; 
    List<AdsFilterValueWrapper> seartchFilterValueList; 
    AdsFilterValueWrapper seartchFilterValue = null; 
    List<Ad> tmpAdList1; 
    List<Ad> tmpAdList2 = new List<Ad>(); 

    int locationId = -1; 
    int[] locationIdList = null; 
    string locationLevelOrder = string.Empty; 

    int categoryId = -1; 
    string categorylevelOrder = string.Empty; 

    AdCategoryFilter adCategoryFilter; 

    AdListCompare adListCompare; 

    Boolean firstDropDownMatch = false; 
    Boolean secondDropDownMatch = false; 

    totalAds = 0; 

    int machedFilterCount; 

    categoryId = AdHandler.Instance.ExtractCategoryId(adList.CS); 

    //If there is multiple choises 
    //This is the last level, that means that we can check against the ID dircly 
    if (adList.LS.L3.Count > 0) 
     locationIdList = adList.LS.L3.ToArray(); 
    else 
     locationId = AdHandler.Instance.ExtractLocationId(adList.LS); 


    switch ((AdOwnerType)adList.ALS.ST) 
    { 
     case AdOwnerType.Both: 
      adOwnerType1 = (int)AdOwnerType.Private; 
      adOwnerType2 = (int)AdOwnerType.Company; 
      break; 
     case AdOwnerType.Company: 
      adOwnerType1 = (int)AdOwnerType.Company; 
      break; 
     case AdOwnerType.Private: 
      adOwnerType1 = (int)AdOwnerType.Private; 
      break; 
    } 

    #region GetFilters 
    adCategoryFilterList = filterModel.GetCategoryFilterByCategory(categoryId); 
    seartchFilterValueList = FilterHandler.Instance.ConvertAdFilterToModel(adList.F, adCategoryFilterList, FilterType.Display); 
    #endregion 

    #region Set Default filters (Buy, Let, Sell, Swap, WishRent) 
    foreach (AdsFilterValueWrapper filterWrapper in seartchFilterValueList) 
    { 
     if ((adCategoryFilter = adCategoryFilterList.Where(c => c.Id == filterWrapper.FilterId).FirstOrDefault()) != null) 
     { 
      switch ((PublicAdFilterKey)adCategoryFilter.PublicAdFilterKey) 
      { 
       case PublicAdFilterKey.Buy: 
        { 
         if (filterWrapper.AdsFilterValues1.ValueNumber > 0) 
          adTypeO1 = AdType.Buy; 
         break; 
        } 
       case PublicAdFilterKey.Let: 
        { 
         if (filterWrapper.AdsFilterValues1.ValueNumber > 0) 
          adTypeO2 = AdType.Let; 
         break; 
        } 
       case PublicAdFilterKey.Sell: 
        { 
         if (filterWrapper.AdsFilterValues1.ValueNumber > 0) 
          adTypeO3 = AdType.Sell; 
         break; 
        } 
       case PublicAdFilterKey.Swap: 
        { 
         if (filterWrapper.AdsFilterValues1.ValueNumber > 0) 
          adTypeO4 = AdType.Swap; 
         break; 
        } 
       case PublicAdFilterKey.WishRent: 
        { 
         if (filterWrapper.AdsFilterValues1.ValueNumber > 0) 
          adTypeO5 = AdType.WishRent; 
         break; 
        } 
      } 
     } 
    } 

    #region Remove default filters fom filterList 
    adCategoryFilterList = adCategoryFilterList.Where(c => ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.Buy && 
            ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.Let && 
            ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.Sell && 
            ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.Swap && 
            ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.WishRent).ToList(); 
    #endregion 
    #endregion 

    var lList = adList.LS.L3.ToList<int>(); //new List<int> { 1, 2, 3, 5 }; 


    using (BissEntities context = new BissEntities()) 
    { 
     if (categoryId > 0) 
      categorylevelOrder = context.AdCategories.Where(c => c.Id.Equals(categoryId)).FirstOrDefault().LevelOrder.Trim(); 
     if (locationId > 0) 
      locationLevelOrder = context.Location.Where(c => c.Id.Equals(locationId)).FirstOrDefault().LevelOrder.Trim(); 

     tmpAdList1 = (from p in context.Ads 
         join h in context.AdCategories on p.CategoryId equals h.Id 
         join l in context.Location on p.UserLocationId equals l.Id 
         where 
         (adList.S == null || adList.S.Length < 1 || p.Title.Contains(adList.S) || p.Description.Contains(adList.S)) && 
         (categorylevelOrder.Length < 1 || h.LevelOrder.StartsWith(categorylevelOrder)) && 

         ((locationIdList != null && lList.Contains(l.Id)) || 
         (locationLevelOrder.Length < 1 || l.LevelOrder.StartsWith(locationLevelOrder))) && 

         ((adTypeO1 == AdType.Unknown && adTypeO2 == AdType.Unknown && adTypeO3 == AdType.Unknown && adTypeO4 == AdType.Unknown && adTypeO5 == AdType.Unknown) || 
         (p.TypeOfAd == (int)adTypeO1 || p.TypeOfAd == (int)adTypeO2 || p.TypeOfAd == (int)adTypeO3 || p.TypeOfAd == (int)adTypeO4 || p.TypeOfAd == (int)adTypeO5)) && //Check for default filters 
         ((AdListShowType)adList.ALS.ST == AdListShowType.Both || adList.ALS.ST == p.OwnerType) && 
         (p.PublishedDate.HasValue && p.PublishedDate.Value.CompareTo(fetchAdsTo) >= 1) && 
         ((adOwnerType1.HasValue && adOwnerType2.HasValue) || p.OwnerType == (int)adOwnerType1.Value) && 
         p.InactivatedDate == null 
         orderby p.CreatedDate descending 
         select p).ToList(); 

     #region Filter collection 
     foreach (Ad ad in tmpAdList1) 
     { 
      machedFilterCount = 0; 
      adListCompare = AdListCompare.NotCompered; 

      if (adCategoryFilterList.Count > 0) 
      {      
       //Loop the filters that belongs to the choosen category 
       foreach (AdCategoryFilter existingFilter in adCategoryFilterList) 
       { 
        //Se if the ad has the proper filter If not return it 
        if ((adsFilterValues = ad.AdsFilterValues.Where(c => c.CategoryFilterId == existingFilter.Id).FirstOrDefault()) != null || existingFilter.PublicAdFilterKey > 0) 
        { 

         //If the filter is not a regular value filter but a filter pointed to a property on the ad 
         //Then extract the correct value and use it 
         if (existingFilter.PublicAdFilterKey > 0) 
         { 
          adsFilterValues = new AdsFilterValues(); 
          adsFilterValues.CategoryFilterId = existingFilter.Id; 

          switch ((PublicAdFilterKey)existingFilter.PublicAdFilterKey) 
          { 
           case PublicAdFilterKey.Price: 
            { 
             adsFilterValues.ValueNumber = ad.Price; 
             break; 
            } 
          } 

         } 

         if ((seartchFilterValue = seartchFilterValueList.Where(c => c.AdsFilterValues1.CategoryFilterId == adsFilterValues.CategoryFilterId).FirstOrDefault()) != null) 
         { 
          firstDropDownMatch = false; 
          secondDropDownMatch = false; 
          adListCompare = AdListCompare.Compared; 

          switch ((FilterControlType)existingFilter.DisplayFilterControlType) 
          { 
           case FilterControlType.TwoDropDown: 

            //Check so the first dropdown value compare 
            //If the index is the first then any value will do 
            if (seartchFilterValue.FilterIndexPosition1 == FilterIndexPosition.First) 
             firstDropDownMatch = true; 
            else 
            { 
             if (adsFilterValues.ValueNumber.Value >= seartchFilterValue.AdsFilterValues1.ValueNumber.Value) 
              firstDropDownMatch = true; 
            } 

            if (firstDropDownMatch) 
            { 
             //Check so the second dropdown value compare 
             //If the index is the last then any value will do 
             if (seartchFilterValue.FilterIndexPosition2 == FilterIndexPosition.Last) 
              secondDropDownMatch = true; 
             else 
             { 
              if (adsFilterValues.ValueNumber.Value <= seartchFilterValue.AdsFilterValues2.ValueNumber.Value) 
               secondDropDownMatch = true; 
             } 

             if (secondDropDownMatch) 
              adListCompare = AdListCompare.Approved; 
            } 

            break; 
           case FilterControlType.DropDown: 

            //Check so the first dropdown value compare 
            //If the index is the first then any value will do 
            if (seartchFilterValue.FilterIndexPosition1 == FilterIndexPosition.First) 
            { 
             if (adsFilterValues.ValueNumber.Value <= seartchFilterValue.AdsFilterValues1.ValueNumber.Value) 
              firstDropDownMatch = true; 
            } 
            if (seartchFilterValue.FilterIndexPosition1 == FilterIndexPosition.Last) 
            { 
             if (adsFilterValues.ValueNumber.Value >= seartchFilterValue.AdsFilterValues1.ValueNumber.Value) 
              firstDropDownMatch = true; 
            } 
            else 
            { 
             if (adsFilterValues.ValueNumber.Value == seartchFilterValue.AdsFilterValues1.ValueNumber.Value) 
              firstDropDownMatch = true; 
            } 

            if (firstDropDownMatch) 
             adListCompare = AdListCompare.Approved; 

            break; 
           case FilterControlType.TextBox: 
            if (adsFilterValues.ValueString.Equals(seartchFilterValue.AdsFilterValues1.ValueString)) 
             adListCompare = AdListCompare.Approved; 
            break; 
           case FilterControlType.CheckBox: 
            if (adsFilterValues.ValueNumber != null && adsFilterValues.ValueNumber.Value == seartchFilterValue.AdsFilterValues1.ValueNumber.Value) 
             adListCompare = AdListCompare.Approved; 
            break; 
           default: 
            adListCompare = AdListCompare.NotCompered; 
            break; 
          } 

          //If no value is set, then break; 
          if (adListCompare != AdListCompare.Approved) 
           break; 

          machedFilterCount++; 
         } 
        } 
        else 
        { 
         //If the ad is missing the filter then return it anyway, it might as well be correct 
         adListCompare = AdListCompare.Approved; 
         machedFilterCount = adCategoryFilterList.Count(); 
        } 
       } 
      } 
      else 
      { 
       adListCompare = AdListCompare.Approved; 
       machedFilterCount = adCategoryFilterList.Count(); 
      } 


      if (adListCompare == AdListCompare.Approved && machedFilterCount == adCategoryFilterList.Count()) 
       tmpAdList2.Add(ad); 
     } 
     #endregion 

     if (adList.ALS.OB == (int)AdListOrderBy.Price) 
      tmpAdList2 = tmpAdList2.OrderBy(c => c.Price).ToList(); 


     totalAds = tmpAdList2.Count(); 

     return tmpAdList2.Skip((adList.ALS.P - 1) * adList.ALS.CP).Take(adList.ALS.CP).ToList(); 
    } 
} 

編輯2:更新

GetAd出現主要方法

public List<Ad> GetAds(AdList adList, DateTime fetchAdsTo, out int totalAds) 
     { 
      LocationModel locationModel = new LocationModel(); 
      FilterModel filterModel = new FilterModel(); 

      List<AdCategoryFilter> adCategoryFilterList; 
      List<AdsFilterValueWrapper> seartchFilterValueList; 

      int categoryId = -1; 
      List<Ad> outputList; 

      totalAds = 0; 

      #region Fetch the first ads by location 
      outputList = GetAdsByLocations(locationModel.GetLocationOrderList(adList.GetLocationIds()), fetchAdsTo, false); 
      if(outputList.Count < 1) 
       return outputList; 
      #endregion 

      #region GetFilters 
      categoryId = AdHandler.Instance.ExtractCategoryId(adList.CS); 
      adCategoryFilterList = filterModel.GetCategoryFilterByCategory(categoryId); 
      seartchFilterValueList = FilterHandler.Instance.ConvertAdFilterToModel(adList.F, adCategoryFilterList, FilterType.Display); 
      #endregion 

      #region Filter Default filters (Buy, Let, Sell, Swap, WishRent) 
      FilterDefaultCustomFilters(outputList, adCategoryFilterList, seartchFilterValueList); 
      if (outputList.Count == 0) 
       return outputList; 
      else 
      { 
       #region Remove default filters fom filterList 
       adCategoryFilterList = adCategoryFilterList.Where(c => ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.Buy && 
               ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.Let && 
               ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.Sell && 
               ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.Swap && 
               ((PublicAdFilterKey)c.PublicAdFilterKey) != PublicAdFilterKey.WishRent).ToList(); 
       #endregion 
      } 
      #endregion 

      #region Filter Custom filters 
      this.FilterCustomFilters(outputList, adCategoryFilterList, seartchFilterValueList); 
      #endregion 

      #region Order 
      switch ((AdListOrderBy)adList.ALS.OB) 
      { 
       case AdListOrderBy.Price: 
        outputList = outputList.OrderBy(c => c.Price).ToList(); break; 
       case AdListOrderBy.Latest: 
        outputList = outputList.OrderByDescending(c => c.PublishedDate).ToList(); break; 
      } 
      #endregion 

      #region Total Ad Count 
      totalAds = outputList.Count(); 
      #endregion 

      #region Paging 
      outputList = outputList.Skip((adList.ALS.P - 1) * adList.ALS.CP).Take(adList.ALS.CP).ToList(); 
      #endregion 

      return outputList; 
     } 

GetAdByLocation

public List<Ad> GetAdsByLocations(string[] locationLevelOrderList, DateTime? fetchAdsTo, Boolean inactive) //, List<Ad> adList = null) 
{ 
    List<Ad> output; 

    using (BissEntities context = new BissEntities()) 
    { 
     if (fetchAdsTo.HasValue) 
     { 
      if (locationLevelOrderList.Count() == 0) 
      { 
       output = (from a in context.Ads 
          join l in context.Location on a.UserLocationId equals l.Id 
          where a.InactivatedDate.HasValue == inactive && 
          (a.PublishedDate.HasValue && a.PublishedDate.Value.CompareTo(fetchAdsTo.Value) >= 1) 
          select a).ToList(); 
      } 
      else 
      { 
       output = (from a in context.Ads 
          join l in context.Location on a.UserLocationId equals l.Id 
          where a.InactivatedDate.HasValue == inactive && 
          (a.PublishedDate.HasValue && a.PublishedDate.Value.CompareTo(fetchAdsTo.Value) >= 1) && 
          (locationLevelOrderList.Where(c => l.LevelOrder.StartsWith(c)).FirstOrDefault() != null) 
          select a).ToList(); 
      } 

     } 
     else 
     { 
      if (locationLevelOrderList.Count() == 0) 
      { 
       output = (from a in context.Ads 
          join l in context.Location on a.UserLocationId equals l.Id 
          where a.InactivatedDate.HasValue == inactive 
          select a).ToList(); 
      } 
      else 
      { 
       output = (from a in context.Ads 
          join l in context.Location on a.UserLocationId equals l.Id 
          where a.InactivatedDate.HasValue == inactive && 
          (locationLevelOrderList.Count() == 0 || locationLevelOrderList.Where(c => l.LevelOrder.StartsWith(c)).FirstOrDefault() != null) 
          select a).ToList(); 
      } 
     } 
    } 

    return output; 
} 

注:主GetAd出現,使用濾鏡的名稱開頭的方法將只與集合(沒有數據庫操作)

+1

這是一個不必要的複雜查詢。您應該對查詢外其他集合執行空檢查。我首先簡化它。這可能意味着將查詢分解爲多個部分並將它們組合成更大的查詢。這樣做可能會自動解決問題。 – 2011-04-02 09:08:54

+0

@Jeff M>謝謝,我現在已經添加了整個方法,您可以看到爲什麼它如此複雜。然而,我確實沒有跟隨你,你能否以更細節的方式解釋? – Banshee 2011-04-02 09:14:14

+0

這麼多代碼。您必須將您的問題本地化爲簡單的代碼片段,否則大多數人會簡單地跳過您的問題。 – 2011-04-02 09:42:00

回答

2

最後一個例子工作在實體工作框架4.如果您得到異常,您的應用程序最有可能構建爲.NET 3.5,並且第一個版本的實體框架不支持Contains

+0

哦!那麼EF4最終支持Contains?不知道!確實是個好消息!每天學些新東西。 +1 – 2011-04-02 09:31:09

+0

>目標框架設置爲4.0? – Banshee 2011-04-02 14:50:47

+0

@SnowJim:在SQL中編寫您的查詢,以便我們能夠理解您正在嘗試執行的操作。 – 2011-04-02 14:55:02

7

在您查詢,您比較:

... locationIdList != null ... 

看到,因爲locationIdListint[]類型,查詢無法翻譯,因爲它僅支持簡單的比較(因爲錯誤狀態)。

您應該在查詢之外執行這些檢查,而不是在這些檢查之內。但是,由於它們是在方法中初始化的,因此您應該確保它們已初始化,並省略檢查,因爲它是不必要的。


我強烈建議重構整個方法和查詢。這是非常漫長而難以遵循的。將代碼塊移動到單獨的方法中執行所需的一小部分,然後將它們放在一起。它會使你的代碼更易於維護和糾正這樣的錯誤,例如這更容易。

+0

M>謝謝,我會嘗試重構該方法。我首先想到的是製作一種只從屬於正確位置的數據庫獲取所有廣告的方法(GetAdsByLocation),然後我將制止所有其他方法中的檢查,並僅對從第一種方法獲得的集合執行此操作( GetAdsByLocation)。這意味着收藏中可能有很多廣告,但我不知道如何以其他方式做到這一點?請指教 – Banshee 2011-04-03 09:11:19

+0

@Jim:我想這是一個好的開始。此外,您應該將跨越15-20行的所有代碼塊移動到自己的方法中。您可能還想考慮重組最後一個模塊。將它移動到一個單獨的方法是不夠的。 – 2011-04-03 09:30:30

+0

M>謝謝,看看Edit2,這是同樣方法的新更新。這看起來更好嗎?還有什麼我應該重構嗎? – Banshee 2011-04-03 12:07:25