EF query taking too much time and result to timeout exception - entity-framework

I am using LINQ query to search string from table which result to timeout exception for some time. Please help me to simplify the query which is as below.
var lstEntityMasterdata1 = (from E in _contextRegister.Entities
join ba in _contextRegister.BusinessActivities on E.MainActivityId equals ba.Id into NewBA
from BA in NewBA.DefaultIfEmpty()
where (E.NameOfEstablishment.Contains(SearchKey) || E.LicenseNr.Contains(SearchKey))
&& (E.IsDeleted != true && E.Active != false)
select new { E, BA }).ToList();

Related

Efcore 2.2- where clause runs after selection and returns false results

I have this simple query:
Expression<Func<Tips, bool>> lastTipsPredicate = x => x.Status == (int)EnumGringo.LU_Status.active;
IQueryable<Tips> lastQueryBase(DbSet<Tips> t) => t.OrderByDescending(x => x.CreateDate).Take(6);
IEnumerable<Tips> latestTips = await base.GetAllByCondition(lastTipsPredicate, lastQueryBase);
This is my base repository:
public virtual async Task<IEnumerable<TEntity>> GetAllByCondition(Expression<Func<TEntity, bool>> predicate, Func<DbSet<TEntity>, IQueryable<TEntity>> baseQuery = null)
{
IQueryable<TEntity> q = context.Set<TEntity>();
if (baseQuery != null)
{
q = baseQuery(context.Set<TEntity>());
}
return await q.Where(predicate).ToListAsync();
}
This generate this sql query(From profiler):
exec sp_executesql N'SELECT [t].[ID], [t].[CreateDate], [t].[Description], [t].[InsertedByGringo], [t].[IsRecommended], [t].[IsSubscribe], [t].[LanguageType], [t].[SeoId], [t].[Slug], [t].[Status], [t].[Title], [t].[UserID], [t].[ViewCount]
FROM (
SELECT TOP(#__p_0) [x].[ID], [x].[CreateDate], [x].[Description], [x].[InsertedByGringo], [x].[IsRecommended], [x].[IsSubscribe], [x].[LanguageType], [x].[SeoId], [x].[Slug], [x].[Status], [x].[Title], [x].[UserID], [x].[ViewCount]
FROM [Tips] AS [x]
ORDER BY [x].[CreateDate] DESC
) AS [t]
WHERE [t].[Status] = 1',N'#__p_0 int',#__p_0=6
Which returns only 5 records and not 6 as I expected, 1 record is filtered out because it has status!=1.
While this query is the correct one and returns the last 6 records:
SELECT top 6 [t].[ID], [t].[CreateDate], [t].[Description], [t].[InsertedByGringo], [t].[IsRecommended], [t].[IsSubscribe], [t].[LanguageType], [t].[SeoId], [t].[Slug], [t].[Status], [t].[Title], [t].[UserID], [t].[ViewCount]
FROM Tips as [t]
WHERE [t].[Status] = 1
ORDER BY [t].CreateDate DESC
How can I generate the second query instead of the first one?
Efcore 2.2- where clause runs after selection and returns false results
It's neither EF Core nor LINQ problem, but the way your repository method builds the LINQ query.
If you want to apply filtering (Where) first and then optionally the rest, then you should change the baseQuery func input type from DbSet<TEntity> to IQueryable<TEntity>, and the implementation as follows:
public virtual async Task<IEnumerable<TEntity>> GetAllByCondition(
Expression<Func<TEntity, bool>> predicate,
Func<IQueryable<TEntity>, IQueryable<TEntity>> baseQuery = null)
{
var q = context.Set<TEntity>()
.Where(predicate); // <-- (1)
if (baseQuery != null)
q = baseQuery(q); // <-- (2)
return await q.ToListAsync();
}

Entity Framework check result null

I am using this query:
var result = from r in db.Registrations
join u in db.UserTypes on r.UserTypeId equals u.UserTypeId
where r.Email.ToLower()==model.LoginEmail.ToLower() && r.Password.ToLower() == model.Password.ToLower()
select new { r,u};
Here how can I check that if no record is found? If so, then
if(result == null)
// no record found
else
// record found
You can use Any or Count extension method:
if(!result.Any())
///norecord found
else
//record found
Using Count would be:
if(result.Count()==0)
///norecord found
else
//record found
First what you assign to a result is just IQueryable so it's query and you need to execute it first. So I suggest renaming it to query and then do it like this:
var query= from r in db.Registrations
join u in db.UserTypes on r.UserTypeId equals u.UserTypeId
where r.Email.ToLower()==model.LoginEmail.ToLower() && r.Password.ToLower() == model.Password.ToLower();
select new { r,u};
var result = query.FirstOrDefault(); // gives first result or null
if (result == null) {
// no record
} else {
// record found and is in result
}

EF DbContext. How to avoid caching?

Spent a lot of time, but still cann't understand how to avoid caching in DbContext.
I attached below entity model of some easy case to demonstrate what I mean.
The problem is that dbcontext caching results. For example, I have next code for querying data from my database:
using (TestContext ctx = new TestContext())
{
var res = (from b in ctx.Buildings.Where(x => x.ID == 1)
select new
{
b,
flats = from f in b.Flats
select new
{
f,
people = from p in f.People
where p.Archived == false
select p
}
}).AsEnumerable().Select(x => x.b).Single();
}
In this case, everything is fine: I got what I want (Only persons with Archived == false).
But if I add another query after it, for example, query for buildings that have people that have Archived flag set to true, I have next things, that I really cann't understand:
my previous result, that is res, will be added by data (there
will be added Persons with Archived == true too)
new result will contain absolutely all Person's, no matter what Archived equals
the code of this query is next:
using (TestContext ctx = new TestContext())
{
var res = (from b in ctx.Buildings.Where(x => x.ID == 1)
select new
{
b,
flats = from f in b.Flats
select new
{
f,
people = from p in f.People
where p.Archived == false
select p
}
}).AsEnumerable().Select(x => x.b).Single();
var newResult = (from b in ctx.Buildings.Where(x => x.ID == 1)
select new
{
b,
flats = from f in b.Flats
select new
{
f,
people = from p in f.People
where p.Archived == true
select p
}
}).AsEnumerable().Select(x => x.b).Single();
}
By the way, I set LazyLoadingEnabled to false in constructor of TestContext.
Does anybody know how to workaround this problem? How can I have in my query what I really write in my linq to entity?
P.S. #Ladislav may be you can help?
You can use the AsNoTracking method on your query.
var res = (from b in ctx.Buildings.Where(x => x.ID == 1)
select new
{
b,
flats = from f in b.Flats
select new
{
f,
people = from p in f.People
where p.Archived == false
select p
}
}).AsNoTracking().AsEnumerabe().Select(x => x.b).Single();
I also want to note that your AsEnumerable is probably doing more harm than good. If you remove it, the Select(x => x.b) will be translated to SQL. As is, you are selecting everything, then throwing away everything but x.b in memory.
have you tried something like:
ctx.Persons.Where(x => x.Flat.Building.Id == 1 && x.Archived == false);
===== EDIT =====
In this case I think you approach is, imho, really hazardous. Indeed you works on the data loaded by EF to interpret your query rather than on data resulting of the interpretation of your query. If one day EF changes is loading policy (for example with a predictive pre-loading) your approach will "send you in then wall".
For your goal, you will have to eager load the data you need to build your "filterd" entity. That is select the building, then foreach Flat select the non archived persons.
Another solution is to use too separate contexts in an "UnitOfWork" like design.

Linq to Entities: multiple criteria query for one table

using (WinFileContextContainer c = new WinFileContextContainer())
{
IQueryable<File> dbfiles = (from f in c.File
where //(f.Category.Any((category => category.name == categoryname)) &&
f.alive //&&
//f.description == "" &&
//f.Category.Count == 1)
select f);
// the rest....
}
The query works only as it is now - I left just one criteria (the rest is in comment sections). But I want the other criteria to be taken into account too. I tried with multiple "where"s :D or all the criteria in brackets with one "where", but still no success. I'm kinda new to LINQ so any help is appreciated. Thanks in advance !
Finally got it to work:
IQueryable<File> dbfiles =
c.File.Where(f => f.Category.Any(cat => cat.name == categoryname) &&
f.alive &&
f.description == null &&
f.Category.Count == 1);

EF 4.0 LINQ one to many / many to one

Just starting to use LINQ as well as EF.
I have a set of tables in the following configuration:
PublicUtility (UtilityCode) * ----> 1 (UtilityCode) Utility (UtilityCode) 1 -----> * (UtilityCode) UtilityDetail
I have a query in SQL. Based on some other business rules this query will either return 1 value or NULL.
SELECT
#UtilityCode = UtilityDetail.UtilityCode
FROM
UtilityDetail
INNER JOIN PublicUtility ON
PublicUtility.SubdivisionCode = #SubdivisionCode AND
PublicUtility.Year = #PublicUtilityYear AND
PublicUtility.UtilityCode = UtilityDetail.UtilityCode
WHERE
UtilityDetail.DebtPurposeCode = #DebtPurposeCode
How could I rewrite this using LINQ to entities?
using (YourObjectContext ctx = new YourObjectContext())
{
var code = (from ud in ctx.UtilityDetails
join pu in PublicUtility on ud.UtilityCode equals pu.UtilityCode
where ud.DeptPurposeCode == [code_value] && pu.SubdivisionCode == [subdivcode_value] && pu.Year == [year_value]
select new {ud.UtilityCode}).FirstOrDefault();
}