Entity Framework 6.0 Multilevel joins group - entity-framework-6

Environment: EF 6 SQL 2012
Lazy Loading Disabled
I have a Service Request table which is having 1 to many relationship with Phase table which in turn is having one to many relationship with Tasks table. I m fetching record from Service request table and in order to compute NextActionDate in Service request, i need to account for Task dates.
This is the query which i have written without the highlighted one, it returns one record as expected, but if i remove the highlighted line, i m getting many records.. In the specific case, a single Service request was having 6 Phases and each phase is having multiple Tasks.. Could some guide me on how to approach this?
var servRequest = (from srDet in SRDB.ServRequestDetails
from srCustReqRef in srDet.ServRequest.ServReqCustReqRefs
from srOpSys in srDet.ServRequest.ServReqOpSys
from srOpSysDet in srOpSys.ServReqOpSysDetails
//from srPh in srDet.ServRequest.ServReqPhases
//from srTask in srPh.ServReqTasks
where srDet!=null && srCustReqRef.CustRequestID == 1 && srDet.IsActiveRow == true
&& srCustReqRef.ServRequestID == 1 && srOpSysDet.IsActiveRow==true
select new ServReqDTO()
{
ServRequestID = srDet.ServRequestID,
Requestor = srDet.HRUser_Requestor.DisplayName,
RequestorID = srDet.RequestorID,
SubmittedDate = srDet.ServRequest.SubmitDateTime,
ServRequestTypeID = srDet.ServRequestTypeID,
ServRequestType = srDet.ServRequestType.ServRequestTypeVal,
TargetDate = srDet.TargetCompletionDate,
OS = srOpSysDet.OperatingSystem.OperatingSystemVal,
OSID = srOpSysDet.OperatingSystem.OperatingSystemID,
//TaskFollowupDates = srTask.ServReqTaskDetails.Where(i => i.IsActiveRow == true).Select(task => task.TaskFollowUpDate).ToList(),
//TaskEndDates = srTask.ServReqTaskDetails.Where(i => i.IsActiveRow == true).Select(task => task.TaskEndDate).ToList(),
//TaskStartDates = srTask.ServReqTaskDetails.Where(i => i.IsActiveRow == true).Select(task => task.TaskStartDate).ToList(),
NextActionDate = null,
ServReqStatus = srDet.ServReqStatusType.ServReqStatusTypeVal,
ServReqStatusTypeID = srDet.ServRequestTypeID
}).ToList();

Related

How do I check how many times a group of value has appeared under a certain date/weekday in Entity Framework

I want a way to check the max and the min times a ticket has been called at a certain weekday (eg: Monday: 5 tickets max; 2 min), the ticket has an ID that ranges between 0 and 4 so I want them all to be noticed.
This is what I currently have:
int S = 0;
var senhas = _db.SenhaSet.ToList();
double[] countersemana = new double[20];
foreach (var senha in senhas)
{
if (senha.Data.DayOfWeek == DayOfWeek.Monday && senha.IdTipoSenha >= 0)
{
S++;
break;
}
}
Your code is very inefficient as it relies on returning the entire SenhaSet table from the database and then looping round it. You want to apply the filter via Entity Framework on the database. Something like (I don't know your column names so am guessing):
var senhas = _db.SenhaSet
.Where(s => SqlFunctions.DatePart("dw", s.Data) == DayOfWeek.Monday && IdTipoSenha >= 0)
.GroupBy(s => DbFunctions.TruncateTime(s.Data))
.Select(s => new {
TicketDate= s.Key,
Count = s.Count(t => t.IdSenha)
})
.ToList();
int maxTickets = senhas.Max(s => s.Count);
int minTickets = senhas.Min(s => s.Count);
This assumes the database is SQL Server in order to use the System.Data.Objects.SqlClient.SqlFunctions.DatePart method.

A better way to combine two Linq Queries into one in MVC5 Controller

in my MVC Application using EntityFramework I have a self referencing table: customers with customerParentID. For children with no emails I want to be able to channel correspondence to parents Email. This is the solution I have that works but I am hitting database 3 times and I want to combine the last 2 into one.
Controller Linq Query
useParentEmail is a bool which is true for children with no Email
Id is obtained by a parameter
var b = db.Lists.SingleOrDefault(a => a.LatestTxnId == Id);
var customerWithNoEmail = db.Customers.SingleOrDefault(a => a.CustomerID == b.CustomerID && a.useParentEmail);
if (customerWithNoEmail != null)
{
var customerParent = db.Customers.SingleOrDefault(a => a.CustomerID == customerWithNoEmail.ParentCustomerID);
customerParentEmail = customerParent.Email;
}
This query hits database twice is there a better way I can do this to hit database once? Any help will be appreciated.
Assuming you are using Entity Framework with the correct navigation properties in the model so that joins work automagically, something like this could work (I've used LinqPad and linq to objects for ease of example). To be honest although I used to be a heavy user of Entity Framework I haven't used it for a few years so I could be a little rusty.
var customers = new[]
{
new { CustomerID = 1, useParentEmail = true, email = "", ParentCustomerID = (int?)2 },
new { CustomerID = 2, useParentEmail = false, email = "parent#example.org", ParentCustomerID = (int?)null },
new { CustomerID = 3, useParentEmail = false, email = "child#example.org", ParentCustomerID = (int?)null }
};
int id = 1;
var emails = (from c in customers
join p in customers on c.ParentCustomerID equals p.CustomerID into childrenParents
from cp in childrenParents.DefaultIfEmpty()
where c.CustomerID == id
select new
{
c.CustomerID,
email = c.useParentEmail == true ? cp.email : c.email
}).SingleOrDefault();
emails.Dump();

Mvc Telerik grid With large database

I am using telerik mvc grid in my mvc project , my table have around 1 Million records. My grid taking too much time to load.
This is my Query
//
var bib = (from a in db.Bibs
join inf in db.InfoTypes
on a.InfoTypeId equals inf.Id
where a.Status == "A"
select new BibViewModel
{
Id = a.Id,
Type = inf.Type,
InfoType = inf.Description,
Title = (from asd in db.BibContents where asd.BibId == a.Id && asd.TagNo == "245" && asd.Sfld == "a" select asd.Value).FirstOrDefault(),
Author = (from asd in db.BibContents where asd.BibId == a.Id && asd.TagNo == "100" && asd.Sfld == "a" select asd.Value).FirstOrDefault(),
CatalogueDate = a.CatalogDate,
Contents = "",
CreatedOn = a.CreatedOn,
ItemRelation = db.Items.Any(item => item.BibId == a.Id),
IssueRelation = db.Issues.Any(item => item.BibId == a.Id),
});
return View(new GridModel(bib.OrderByDescending(x => x.CreatedOn).Tolist()));
ToList() actually invokes the query, so if calling ToList() is taking too long, that means the issue is with the query.
In LINQ, you can use paging like in the following post; the idea is to use Skip and Take to skip X records, and only take Y records, as in:
var results = (from .. select ..).Skip(X).Take(Y)
With 1M records, I would highly suggest replacing it with a stored procedure, which will be much, much faster for what you are trying to do. Consider a custom pagination approach, which works very well for me with large result sets:
http://www.neiland.net/blog/article/dynamic-paging-in-sql-server-stored-procedures/
http://www.beansoftware.com/ASP.NET-Tutorials/Paging-Stored-Procedures.aspx
http://www.sqlpointers.com/2009/10/custom-sorting-and-paging-in-sql-server.html
T-SQL stored procedure with sorting and paging enabled not working properly
If you can't use stored procedures, reading this will help understand what needs to be accomplished with pagination. With LINQ, you'll want to examine the SQL being generated to see where you also can fine-tune the query, either using SQL profiler, or LINQPad.

Need help to build an EF query with LEFT JOIN

I can't find the correct way to build an EF (4.1) query that will return the same result as this SQL containing a LEFT JOIN:
SELECT
s.id_service,
s.description,
x.id_service as isDisponible
FROM
role.service_disponible s
LEFT JOIN
role.service_disponible_x_ue x
ON s.id_service = x.id_service AND x.id_ue = 1 and flg_actif = '1'
In fact I'm just trying to obtain the complete list of services disponible (ServiceDisponible) adding a field that tell me if service is disponible for a specific entity (filtered with the id_ue) which information come from a many to many related table (ServiceDisponibleXUe).
My model is:
Ideally, I would like this query to return this viewModel object what is basically my serviceDisponible domain with one more field indicating the disponibility of the service.
public ServiceDisponibleViewModel(ServiceDisponible ServiceDisponible, bool isDisponible)
{
this.serviceDisponible = serviceDisponible;
this.isDisponible = isDisponible;
}
What I have so far is this query but the syntax is invalid:
services = context.ServiceDisponible
.Select(a => new ServiceDisponibleViewModel
{
c => new ServiceDisponible
{
id_service = a.id_service,
description = a.description
},
isDisponible = a.ServiceDisponibleXUe
.Any(b => b.flg_actif && b.id_ue == idUe)
}).ToList();
Try this:
ServiceDisponibleViewModel services =
from sd in context.ServiceDisponible
from sdx in context.ServiceDisponibleXUe
.Where(x => x.id_ue == 1 && flg_actif == '1' && x.id_service == sd.id_service)
.DefaultIfEmpty()
select new ServiceDisponibleViewModel(
new ServiceDisponible
{
id_service = sd.id_service,
description = sd.description
},
sdx.id_service
);
Having SQL as example often makes one jump to a join in linq. But using navigation properties produces much more succinct syntax:
from sd in context.ServiceDisponible
from sdx in sd.ServiceDisponibleXUes.Where(x => x.id_ue == 1
&& x.flg_actif == "1")
.DefaultIfEmpty()
select new
{ sd.id_service,
sd.description,
isDisponible = sdx.id_service
};
(I couldn't help using the plural form of ServiceDisponibleXUe which imo is more clear).

load navigation properties with filter for Entity Framework 4.3

Few days back I put a question regarding mapping two classes Message and MessageStatusHistory using EF. The mapping is going fine but I am facing some problems with the navigation property StatusHistory in class Message that relates it to MessageStatusHistory objects. I am loading the messages for one user only and want to the statuses pertaining to that user only. Like I would want to show if the user has marked message as read/not-read and when. If I use default loading mechanism like following it loads all the history related to the message irrespective of the user:
IDbSet<Message> dbs = _repo.DbSet;
dbs.Include("StatusHistory").Where(x=>x.MessageIdentifier == msgIdentifier);
To filter history for one user only I tried following trick:
IDbSet<Message> dbs = _repo.DbSet;
var q = from m in dbs.Include("StatusHistory")
where m.MessageIdentifier == msgIdentifier
select new Message
{
MessageIdentifier = m.MessageIdentifier,
/*OTHER PROPERTIES*/
StatusHistory = m.StatusHistory
.Where(x => x.UserId == userId).ToList()
};
return q.ToList();//THROWING ERROR ON THIS LINE
I am getting the error:
The entity or complex type 'MyLib.Biz.Message' cannot be constructed in a LINQ
to Entities query.
I have tried by commenting StatusHistory = m.StatusHistory.Where(x => x.UserId == userId).ToList() also but it has not helped.
Please help me in getting Messages with filtered StatusHistory.
EDIT:- above is resolved with this code:
var q = from m in _repository.DBSet.Include("Histories")
where m.MessageIdentifier == id
select new {
m.Id,/*OTHER PROPERTIES*/
Histories = m.Histories.Where(x =>
x.SenderId == userId).ToList()
};
var lst = q.ToList();
return lst.Select(m => new Message{
Id = m.Id, MessageIdentifier = m.MessageIdentifier,
MessageText = m.MessageText, Replies = m.Replies,
ReplyTo = m.ReplyTo, Histories = m.Histories, SenderId =
m.SenderId, SenderName = m.SenderName, CreatedOn = m.CreatedOn
}).ToList();
But if I try to include replies to the message with:
from m in _repository.DBSet.Include("Replies").Include("Histories")
I am getting error on converting query to List with q.ToList() for Histories = m.Histories.Where(x=> x.SenderId == userId).ToList().
About your EDIT part: You cannot use ToList() in a projection, just leave it an IEnumerable<T> and convert to a List<T> when you construct the Message. You also don't need to create two list objects, you can switch from the LINQ to Entities query to LINQ to Objects (the second Select) by using AsEnumerable():
var list = (from m in _repository.DBSet
where m.MessageIdentifier == id
select new {
// ...
Histories = m.Histories.Where(x => x.SenderId == userId)
})
.AsEnumerable() // database query is executed here
.Select(m => new Message {
// ...
Histories = m.Histories.ToList(),
// ...
}).ToList();
return list;
Be aware that Include has no effect when you use a projection with select. You need to make the properties that you want to include part of the projection - as you already did with select new { Histories.....

Resources