LINQ, Unable to create a constant value of type XXX. Only primitive types or enumeration types are supported in this context

C#Entity FrameworkLinq

C# Problem Overview


In my application I have Lecturers and they have list of Courses they can teach and when I'm deleting a course I want to remove connection to lecturers. Here's the code:

public void RemoveCourse(int courseId)
{
    using (var db = new AcademicTimetableDbContext())
    {
        var courseFromDb = db.Courses.Find(courseId);
        
        var toRemove = db.Lecturers
                        .Where(l => l.Courses.Contains(courseFromDb)).ToList();
                        
        foreach (var lecturer in toRemove)
        {
            lecturer.Courses.Remove(courseFromDb);
        }

        db.SaveChanges();
    }
}

but it doesn't work. I get

> NotSupportedException: Unable to create a constant value of type Course. Only primitive types or enumeration types are supported in this context.

What am I doing wrong?

C# Solutions


Solution 1 - C#

You can't use Contains with non-primitive values. Do

Where(l => l.Courses.Select(c => c.CourseId).Contains(courseId)

(or the Id field you use).

Solution 2 - C#

If you are using a DbContext, you can query the .Local collection, and the == operator will work also with objects:

public void RemoveCourse(int courseId)
{
    using (var db = new AcademicTimetableDbContext())
    {
        var courseFromDb = db.Courses.Find(courseId);

        db.Lecturers.Load() //this is optional, it may take some time in the first load

        //Add .Local to this line
        var toRemove = db.Lecturers.Local 
                        .Where(l => l.Courses.Contains(courseFromDb)).ToList();

        foreach (var lecturer in toRemove)
        {
            lecturer.Courses.Remove(courseFromDb);
        }

        db.SaveChanges();
    }
}

The .Local is an ObservableCollection, so you can compare anything you like inside it (not limited to SQL queries which don't support object comparison). Just to make sure you get all your objects in the .Local collection you can call the db.Lecturers.Load() method before calling .Local, which brings all database entries into the Local collection.

Solution 3 - C#

The Courses collection of below line should be null or empty.

 var toRemove = db.Lecturers
                        .Where(l => l.Courses.Contains(courseFromDb)).ToList();

Solution 4 - C#

This can also happen when you pass a Func<T, bool> to Where() as a way to write a dynamic condition like here here For some reason the delegate can't be translated to SQL.

Solution 5 - C#

You cannot compare complex type, if you have not specified what you mean for equality.

As exception detail says, you need to check primitive values (like Integer in your case).

And better to use Any() method instead.

var toRemove = db.Lecturers
     .Where(l => l.Courses.Any(p=>p.Id == courseFromDb.Id)).ToList();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionpawel1708hpView Question on Stackoverflow
Solution 1 - C#Gert ArnoldView Answer on Stackoverflow
Solution 2 - C#HannishView Answer on Stackoverflow
Solution 3 - C#Chamath JeevanView Answer on Stackoverflow
Solution 4 - C#shrutyzetView Answer on Stackoverflow
Solution 5 - C#Aryan FirouzianView Answer on Stackoverflow