EF CORE 3.0 Cannot use multiple DbContext instances within a single query execution - ef-core-2.0

After upgrading from .Net Core 2.2 to 3.0, the apps is throwing this err message.
Cannot use multiple DbContext instances within a single query execution
What is the workaround?
IQueryable<ApplicationUser> query;
var queryJoin = from ci in _courseInstructorRepository.Table
join uc in _userCourseRepository.Table on ci.CourseId equals uc.CourseId
select new { ci, uc };
if (userId > 0)
queryJoin = queryJoin.Where(x => x.ci.UserId == userId);
if (courseId > 0)
queryJoin = queryJoin.Where(x => x.uc.CourseId == courseId);
if (classId > 0)
queryJoin = queryJoin.Where(x => x.uc.CourseClassId == classId);
query = queryJoin.Select(x => x.uc.User).Distinct();
if (!string.IsNullOrEmpty(studentFirstChar))
query = query.Where(x => x.FirstName.StartsWith(studentFirstChar));
if (schoolId > 0)
query = query.Where(x => x.SchoolId == schoolId);
query = query.OrderBy(x => x.UserName);
return new PagedList<ApplicationUser>(query, pageIndex, pageSize);

You have a couple of design flaws in your code that EF core 2 swept under the carpet.
Your repositories don't share one context instance. EF core 2 couldn't create one SQL query from your code either, but it silently switched to client-side evaluation. That is, it just executed two SQL queries and joined them in memory. This must have been highly inefficient. One of the best design decisions in EF core 3 was to abandon automatic client-side evaluation, so now you're getting this error.
You don't use navigation properties. Using an ORM like EF, using manual joins should hardly ever be necessary. The Instructor class should have a navigation property like Courses, and Course a navigation property like Instructor.
Don't use this redundant repository layer anyway. As you're already experiencing in this small piece of code, it usually makes things harder than necessary without any added value.

One of your variables was created using another instance of DBContext, so when you try to use it as part of another DBContext's query it throws. The work around is to close the first DBContext and invoke DBContext.Attach(model) on the second.

Related

Do sub-queries hit database multiple times if using Entity Framework

Might seem like a silly question but please read it... I am writing some services and there comes a situation where I have to use sub-query with Entity Framework. Now I have written a query with sub-query but the way I have written it, got me thinking that whether my query is hitting database two times?
Below is the pseudo code of actual query....
var data = databaseContext.FirstTable
.Where(x => x.Group_Id == (databaseContext.SecondTable
.Where(y => y.DomainName == "gmail.com")
.Select(x => x.Group_Id)
.FirstAndDefault()))
.ToList();
This query is giving my expected result but I think is hitting the database twice. Am I correct ?
Now I don't want a yes no answer but a short description and can I turn this query into a join one. And some tools or tips to check database hits in SQL Server like a tracer or something.
Yes it does. When you call first or default the Iqueryable will be send to the database. You can trick it by using transactions. Also it's recommended for what you are doing here to use transactions. Also for what you are trying to do i recommend using transitional properties of EF.
var data = databaseContext.FirstTable
.Include(x=>x.SecondTable)
.Where(x => x.SecondTable.DomainName == "gmail.com")
The SQL server profiler will show you all queries on the database. Not recommended to use it on anything else than local host of course.

LINQ custom function in .where

can I, and if I can, how, write LINQ statement like this:
public IQueryable<Advert> SearchSimilarAdverst(string query)
{
Levenshtein compute = new Levenshtein();
return _db.Adverts.Where(a => a.IsActive &&
(compute.FindSimilarity(a.Name, query) <= 2));
}
Thanks
EDIT
I've tired solution Jeffery suggested and it worked but when I've tried this line of code I got EntityCommandExecutionException, does anybody know why ?
adverts.Where(a => a.WhoAmILookingForTags.Any
(t => compute.FindSimilarity(t.Name,query) <= 2));
Tags and Adverts are connected with many to many relation, and WhoAmILookingForTags is list of tags
EF will not be able to translate compute.FindSimilarity(a.Name, query) to SQL, so you're going to have to take the performance hit and do the following.
public IEnumerable<Advert> SearchSimilarAdverst(string query)
{
Levenshtein compute = new Levenshtein();
var adverts = _db.Adverts.Where(a => a.IsActive).ToList();
return adverts.Where(a => compute.FindSimilarity(a.Name, query) <= 2));
}
Note the return type of the method also needed to be changed to reflect the return type
As commented below, the query should be forced to run before filtering using FindSimilarity because of delayed execution. query.ToList() is one of many options.
In short, no - because EF needs to be able to convert your Linq predicate into T-SQL (or whatever dialect of SQL your RDBMS uses). Only a subset of .NET BCL functions are supported (such as String.Contains and custom user code is right-out).
For complicated predicates I recommend writing your own SQL by hand - you'll also get considerably better performance, EF can be slow at generating SQL.
I hope I'm wrong on this, but I do not believe that you would be allowed to that in a Linq-to-Entities query. In those kinds of LINQ queries it has to translate everything in the Where function into a SQL statement to be run on the underlying database. Since your method is not something that is on the SQL side of things, it will cause an exception when you try this.
For a regular LINQ query (i.e. after everything has already been put into memory), there should be no problem with accomplishing this.
You could also try it and see if it does or does not work...

How to structure Entityframework DB Contexts

I haven't been able to find any answers online for this.
What are the advantages/disadvantages of using Multiple DB Contexts against using a single?
Is the below solution ok for setting related objects, (when saving to DB) (to make it more efficient, because I already have the ID, no need to fetch object)
I've heard its reccommened to use contexts like Using(MyContext c = MyContext) {}, at the moment I'm using the default MVC way, of having the context instantiated in the controller, is this ok?
Person P = new Person();
P.QuickSetCar(CarID);
db.People.Add(P);
db.saveChanges();
and
private void QuickSetCar(int CarID)
{
if(this.Car == null) {
Car C = new Car();
C.ID = ID;
this.Car = C;
}
}
Using multiple contexts is always a disadvantage unless you have no choice (e.g. your data is dispersed across multiple databases).
Almost, but you can simplify your new car initialization to:
private void QuickSetCar(int CarID) {
if(this.Car == null)
this.Car = new Car(){ ID = CarID };
}
That's fine. Just don't use more than one context for the duration of the web transaction (request/response) and don't keep it around for longer than that either.
Multiple contexts are normally only useful for very large models spread over multiple databases. If you are starting a project it is normally best to use a single context.
Your method for using IDs is fine.
Creating contexts within controllers is certainly workable but I would strongly suggest against it. This approach is often shown in demos and for basic scaffolding but in real world applications it is not a great idea. Large amounts of code will often be duplicated by instatiating and querying contexts in each controller. Also have a central repository will allow for much easier caching to improve performance.

EF4 - Self tracking entities and inheritance and eager loading

I know this has been asked before in several ways but none of the answers seem applicable to me - or correct - or current, so I'll try again.
I have a large model with several intstances of inherited entities. One example is a Timetable that contains a collection of TimetableEvents. There are several sub-types of TimetableEvent, such as an InterviewTimetableEvent, BreakTimetableEvent and an ExercisetimeTableEvent. ExerciseTimetableEvent has a relationship to an Exercise entity.
I need to use self-tracking entities as I'm using a WCF back end to serve up data to several WPF clients in a stateless fashion.
So, I need to eager load everything and I thought that self-tracking entities would automatically do this but it appears they dont.
So, to get a timetable I need to do something like this:
var tt = (from s in ESSDataContainer.Timetables
.Include("TimetableEvents")
where s.TimetableId == timetableid
select s).FirstOrDefault();
This will give me the TimetableEvents but not the Exercises that are related to the ExerciseTimetableEvents. Ive tried the following (and several other suggestions) without luck:
var tt = (from s in ESSDataContainer.Timetables
.Include("TimetableEvents")
.Include("ExerciseTimetableEvents.Exercise")
where s.TimetableId == timetableid
select s).FirstOrDefault();
Is there a solution to this?
If not I'll go back to normal context tracking and connect to the database from a local container rather than using WCF.
Cheers
It's a bit tricky, but possible:
var tt = (from s in ESSDataContainer.Timetables
where s.TimetableId == timetableid
select new
{
TimeTable = s,
Events = s.TimeTableEvents,
Exercise = s.TimeTableEvents.OfType<ExerciseTimetableEvents>()
.Select(ett => ett.Exercise)
}).Select(s => s.TimeTable)
.AsEnumerable()
.FirstOrDefault();
Clear as mud, but, hey: No magic strings! Also, it has the advantage that it actually works....
There is a Proposal for this issua at Microsoft Connect:. If you think this worthy you can vote for it.

MVC DataContext Ok to Share One Connection or Not

When is the "unit of work" no longer a "unit"? Which scenario is better on resources? THe first creates one connection wheras the second creates 4.
using (DataContext dc=new DataContext)
{
var orders= from o in dc.orders
select ( new Product { property a= from a in ..join... select x,
property b= from b in ..join... select y,
property c= from c in ..join... select z.}
)
}
OR
using (DataContext dc=new DataContext)
{
var orders= from o in dc.orders
select ( new Product { property a = GetPropertyA(),
property b = GetPropertyB(),
property c = GetPropertyC()}
)
}
When using LINQ if you add one entity to another and they use a different data context you are going to get an error. I would suggest keeping the same data context for each unit of work you are using. You can easily identify the unit of work you are processing by using the repository pattern to write your data access classes. If you're not clear on the repository pattern, check out this entry
Generally speaking the less round trips to your database the better. However, in high scale apps we often make our databases more and more 'dumb' so we end up not doing any joins so we don't tie up CPU and memory on the SQL database server. It really depends on which resources you find more scarce. If your SQL server has plenty of resources do the join there, otherwise pulling it back separately would be better. Have you looked at the results of this in the SQL profiler? Are you sure it's 4 connections, or just 4 separate calls?

Resources