Question

First, let me say that I've researched this problem and read the following stack overflow articles, but none of them really address this situation.

Situation

I have two classes

public class Section{
    public string SchoolId{get;set;}
    public string CourseId{get;set;}
    public string SectionId{get;set;}
}

public class RelatedItem{
    public string SchoolId{get;set;}
    public string CourseId{get;set;}
    public string SectionId{get;set;}
    //..
}

I have an array of Section coming from one source and is an actual collection of Objects.

RelatedItem I'm getting via a LINQ to Entities call against a DbContext.

My goal is to get all of the RelatedItems based on the Sections I have from the other source.

I'm writing a query like this

Section[] mySections = GetSections();    //Third Party Source
IQueryable<RelatedItem> relatedItems = DbContext.RelatedItems
    .Where(r=>
        mySections.Any(s=> s.SchoolId == r.SchoolId &&
                           s.CourseId == r.CourseId &&
                           s.SectionId == r.SectionId)
    );

Problem

At runtime, I receive the following error

Unable to create a constant value of type 'ProjectNamespace.Section'. Only primitive types or enumeration types are supported in this context.

I found a work around, but it involves doing the following, but it doesn't take advantage of any of my table indexes.

var sectionIds = sections.Select(s=>string.Concat(s.SchoolId, "|",s.CourseId, "|",s.SectionId));
IQueryable<RelatedItem> relatedItems = DbContext.RelatedItems
        .Where(r=>
            sectionIds.Contains(string.Concat(r.SchoolId, "|",r.CourseId, "|",r.SectionId))
        );

This block of code works, and currently is pretty fast (but this is dev, and my record count is small). Aside from converting my related items to a collection in memory, does anyone have any other suggestions?

Était-ce utile?

La solution

Try using Contains instead:

Section[] mySections = GetSections();    //Third Party Source

IQueryable<RelatedItem> relatedItems = DbContext.RelatedItems.Where(r=>
    mySections.Select(s => s.SchoolId).Contains(r.SchoolId) &&
    mySections.Select(s => s.CourseId).Contains(r.CourseId) &&
    mySections.Select(s => s.SectionId).Contains(r.SectionId)
);

Contains should translate to WHERE IN clauses in SQL.

This won't work if using .NET 3.5 and LINQ to Entities, as it wasn't implemented in that version.

Autres conseils

Proper way to solve this is to implement IEquitable. Here is an example on how to do it Does LINQ to Entities support IEquatable in a 'where' clause predicate?
One tip when implementing Equals() and GetHashCode() do not call any .NET methods (like getType()) only compare primitives SchoolId, CourseId, SectionId, it should get converted to expression tree and work just fine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top