How to optimize speed of query EF - asp.net-mvc

i've a query as well as:
var query = unitOfWork.Ticket_Repository
.FindByQueryAsNoTracking(e => e.BusinessPageId == bpid && e.Status != p2 && e.Status != p3)
.Where(e => e.TicketParaphs
.Where(x => x.ParaphRole == p1)
.OrderByDescending(x => x.CreateDate)
.FirstOrDefault()
.ReceiveId == User.ID);
this query isn't optimize because the query executing in low speed.
How to optimize this query?
thanks.

Related

Entity Framework : better way to do many to many query?

Environment: EF6 code first
I have two tables e.g user and activity which have a many-to-many relation.
I want to know whether any user's activity has a given key, using Entity Framework in an asp.net mvc application.
is the following query performance wise?
is there any other way to write this query?
Query:
var userEntity = _dbcontext.Users.Find(userId);
var isAvailable = _dbcontext.Entry(userEntity)
.Collection(e => e.Activities)
.Query().Any(e => e.Name== "givenname");
updated:
i ran those queries and here are the time to run:
1
var userEntity = _dbcontext.Users.Find(userId);
var isAvailable = userEntity.Activities.Any(a => a.Name == "givenname");
time: 5.39s + time to fetch user
2
var isAvailable =_dbcontext.Users.Include(e => e.Activities)
.Any( u => u.UserId == userId
&& u.Activities.Any(a => a.Name == "givenname")
);
time: 5.73s
3
var userEntity = _dbcontext.Users.Find(userId);
var isAvailable = _dbcontext.Entry(userEntity)
.Collection(e => e.Activities)
.Query().Any(e => e.Name== "givenname");
time: 5.95s + time to fetch user
so it seems that choosing the second form of query be reasonable.
You can also try this:
var isAvailable =_dbcontext.Users.Include(e => e.Activities)
.Any( u => u.UserId == userId
&& u.Activities.Any(a => a.Name == "givenname")
);
If you haven't disabled lazy loading, then you don't need to call the Include extension method.
I would simplify this to:
var userEntity = _dbcontext.Users.Find(userId);
var isAvailable = userEntity.Activities.Any(a => a.Name == "givenname");
or maybe (I'm not quite clear what you're trying to achieve, from your question) - this doesn't take the userId into account, it just searches for any users that has any activity with that givenname:
var isAvailable = _dbcontext.Users.Any(u => u.Activities.Any(a => a.Name == "givenname"));
Single trip to the DB:
var result = _dbcontext.Users.Where( u => u.UserId == userId )
.Select( u => new {
User = u, // optional
IsAvailable = u.Activities.Any( a => a.Name == "givenname" )
} )
.SingleOrDefault();

Order results by two differents fields in entity framework

I have advertisement table, i want to order it first by special, then order by last added, but special ads has end date, so i want to order special ads that its date is still
This is my code
List<S_Advertisements> moduleItems = db.S_Advertisements
.Include(x => x.S_AdvertisementsImages)
.Where(x => x.CatId == pureId && x.IsActive == true)
.OrderByDescending(x => x.IsSpecial)
.ThenByDescending(x => x.AdId).ToList();
I want to know if Entity Framework will let me do something like that :
List<S_Advertisements> moduleItems = db.S_Advertisements
.Include(x => x.S_AdvertisementsImages)
.Where(x => x.CatId == pureId && x.IsActive == true)
.OrderByDescending(x => x.IsSpecial.Where(x => x.DateSpecialEnd > DateTime.Now))
.ThenByDescending(x => x.AdId).ToList();
may be :
DateTime dtn = Datetime.Now;
var moduleItems = db.S_Advertisements
.Include(x => x.S_AdvertisementsImages)
.Where(x => x.CatId == pureId && x.IsActive == true)
.Select( x => new {
o = x,
c = x.DateSpecialEnd > dtn ? 0 : 1 // not a boolean but an order info
})
.OrderByDescending(z => z.c)
.ThenByDescending(z => z.o.AdId).ToList();
same as in sql: view for calculating the field, then order the view.
The placement of the where clause doesn't affect ordering. Whether you order by IsSpecial or by IsSpecial.Where(...) the order would be the same, regardless. That's pretty much why what you're looking for doesn't exist: there's no need for it to.

linq: how to get sorted records from last ID

I have the following table,
ItemTable,
Col1 : ItemID(int)
Col2 : MRP(Decimal)
To one of the application I needed to pass selected number of items at a time, They will send me the lastId which I passed to them, the initial requirement was to pass the newest items, which I was able to get it using following query,
var itemList = itemRepository.AsQueryable()
.Where(r => r.ProductID == productID && r.IsActive == true && r.ItemID< lastId)
.OrderByDescending(r => r.ItemID)
.Take(numberOfItems)
.ToList();
However now there is a sort option added to it, which is the MRP column, though again i have only the last Id with me, how could I will able to get this? I tried with the following query, no luck.
var itemList = itemRepository.AsQueryable()
.Where(r => r.ProductID == productID && r.IsActive == true && r.ItemID< lastId)
.OrderByDescending(r => r.ItemID)
.OrderBy(r => r.MRP)
.Take(numberOfItems)
.ToList();
UPDATE : Working Code
As per CamperWill's suggesstion I updated my code and works great with skip.
var itemList = itemRepository.AsQueryable()
.Where(r => r.ProductID == productID && r.IsActive == true)
.OrderBy(r => r.MRP)
.Skip(pageNumber * numberOfItems)
.Take(numberOfItems)
.ToList();
LastID will not help you with paging if you are sorting by a different field (MRP). Also, as indicated in the comments above, the first ordering is effectively ignored by adding the second.
You could consider tracking the page number that is requested and use the Skip() extension.
// input parameter 'page'
var itemList = itemRepository.AsQueryable()
.Where(r => r.ProductID == productID && r.IsActive == true)
.OrderBy(r => r.MRP)
.Skip( (page-1)*numberOfItems )
.Take(numberOfItems)
.ToList();

How to get distinct value from the list

I have a List generated from Linq to Entities query. In which, I need to get a unique records based on BibId. I have tried changing the query but no help to get the unique records based on BibId.
Query
aa.NewBibContentsModel = (from x in db.BibContents
where (x.TagNo == "245" && x.NormValue == aa.CurrentTitle) || (x.TagNo == "020" && x.NormValue == aa.CurrentISBN) || (x.TagNo == "022" && x.NormValue == aa.CurrentISBN)
select new
{
BibId = x.BibId,
Title = (from a in db.BibContents where a.BibId == x.BibId && a.TagNo == "245" orderby a.Id ascending select a.NormValue),
//Tit = (from a in db.BibContents where a.BibId == line.BibId && a.TagNo == "245" && a.Sfld == "a" select a.NormValue).FirstOrDefault(),
Author = (from a in db.BibContents where a.BibId == x.BibId && splitted.Contains(a.TagNo) && a.NormValue != null select a.TagNo).FirstOrDefault(),
ISBN = (from a in db.BibContents where a.BibId == x.BibId && a.NormValue != null && (a.TagNo == "020" || a.TagNo == "022") orderby a.Id ascending select a.NormValue)
}).AsEnumerable().Select(x => new BibContentsModel
{
BibId = x.BibId,
Title = string.Join(" ", x.Title),
Author = string.Join(" ", (from a in db.BibContents where a.BibId == x.BibId && a.TagNo == x.Author orderby a.Id select a.NormValue)),
ISBN = string.Join(" ", x.ISBN)
}).ToList();
Any help to this problem will be appreciated.
Thanks
What you're trying to achieve is know as Distinct By. MoreLinq has a function for it. The syntax would look like:
(from x in db.BibContentsNo == "022")
... // your query
}).AsEnumerable()
.DistinctBy(x => x.BibId) // <= MoreLinq
What is does is group the records by BibId and take the first element of each group.
You can download MoreLinq as a NuGet package.

Speeding up a linq query

I am trying to replicate the following SQL query with linq. On SQL Server it takes a fraction of a second to run:
select g.reference, count(*)
from isis.dbo.[group] as g inner join
isis.dbo.enrolment as e on g.groupid = e.groupid inner join
isis.dbo.student as s on e.studentid = s.studentid inner join
isis.dbo.progression as p on s.studentid = p.studentid
where p.academicyear = '12/13' and g.istutorgroup = 1
group by reference
In my MVC application I am passing a listing of "TutorGroups" to the view. For each tutor group in the view I need to display various information about them, one item being the number of "Progression" interviews they have had.
I have tried a couple of methods but they both take upwards of 30 secs to run in my MVC application:
<%TTMrequired = tg.Enrolments
.SelectMany(e => e.Student.Progressions
.Where(p => p.TTMChecked == false &&
p.TTMInterview == true &&
p.AcademicYear == year))
.Count(); %>
and
<%TTMrequired = tg.Enrolments
.Where(e => e.Student.Progressions
.Any(p => p.TTMChecked == false &&
p.TTMInterview == true &&
p.AcademicYear == year))
.Count(); %>
Anyone got any suggestions on how I can speed this up? I suspect the problem is me trying to do it a stupid way - it usually is!
You could try doing a Sum of counts instead of a SelectMany:
tg.Enrolments.Sum(e => e.Student.Progressions
.Count(p => p.TTMChecked == false &&
p.TTMInterview == true &&
p.AcademicYear == year)
);
Should be written using this syntax:
var TTMRequired = (from g in tg.Groups
join e in tg.Enrolment on g.groupid equals e.groupid
join s in tg.Students on e.studentid equals s.studentid
join p in tg.Progressions on s.studentid = p.studentid
where p.academicyear.Equals("12/13") && g.istutorgroup.Equals(1)
group g by g.reference into grp
select new {
grpRef = grp.Key,
grpCount = grp.Count()
});
Note: if g.istutorgroup is of type BIT instead of INT, consider using .Equals(true).

Resources