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