linq combine results from two tables to one select new statment? - linq

With the following query how to I change that I dont have two sets of fields in the select new I want the information going into one set of columns not having two and a type field to say if its a traineeevent or a cpd event ?
List<EmployeeCPDReportRecord> employeeCPDRecords = new List<EmployeeCPDReportRecord>();
string employeeName;
var q = from cpd in pamsEntities.EmployeeCPDs
from traineeEvent in pamsEntities.TrainingEventTrainees
join Employee e in pamsEntities.Employees on cpd.EmployeeID equals e.emp_no
join TrainingEventPart tEventPart in pamsEntities.TrainingEventParts on traineeEvent.TrainingEventPartId equals tEventPart.RecordId
where (cpd.EmployeeID == id) && (startDate >= cpd.StartDate && endDate <= cpd.EndDate) &&
(traineeEvent.EmployeeId == id)
&& (traineeEvent.TraineeStatus == 1 || traineeEvent.TraineeStatus == 2)
&& (tEventPart.CPDHours > 0 || tEventPart.CPDPoints > 0)
&& (cpd.CPDHours > 0 || cpd.CPDPoints > 0)
|| traineeEvent.StartDate >= startDate
|| traineeEvent.EndDate <= endDate
orderby cpd.StartDate
select new
{
surname = e.surname,
forname1 = e.forename1,
forname2 = e.forename2,
EmployeeID = cpd.EmployeeID,
StartDate = cpd.StartDate,
EndDate = cpd.EndDate,
CPDHours = cpd.CPDHours,
CPDPoints = cpd.CPDPoints,
Description = cpd.Description,
TrainingStartDate = tEventPart.StartDate,
TrainingEndDate = tEventPart.EndDate,
TrainingCPDHours = tEventPart.CPDHours,
TrainingCPDPoints = tEventPart.CPDPoints,
TrainingEventDescription = tEventPart.Description
};
if (q != null)
{
Array.ForEach(q.ToArray(), i =>
{
if (ContextBase.encryptionEnabled)
employeeName = ContextBase.Decrypt(i.surname) + ", " + ContextBase.Decrypt(i.forname1) + " " + ContextBase.Decrypt(i.forname2);
else
employeeName = i.surname + ", " + i.forname1 + " " + i.forname2;
if (i.TrainingStartDate != new DateTime(1900, 1, 1))
employeeCPDRecords.Add(new EmployeeCPDReportRecord(employeeName, Convert.ToDateTime(i.StartDate), Convert.ToDateTime(i.EndDate), Convert.ToDecimal(i.CPDHours), Convert.ToDecimal(i.CPDPoints), i.Description,i.t,i.EndDate,Convert.ToDecimal(i.CPDHours),Convert.ToDecimal(i.CPDPoints),i.Description,"L&D"));
else
employeeCPDRecords.Add(new EmployeeCPDReportRecord(employeeName, Convert.ToDateTime(i.StartDate), Convert.ToDateTime(i.EndDate), Convert.ToDecimal(i.CPDHours), Convert.ToDecimal(i.CPDPoints), i.Description, i.StartDate, i.EndDate, Convert.ToDecimal(i.CPDHours), Convert.ToDecimal(i.CPDPoints), i.Description, "Employee CPD"));
});
}

Use this code
List<EmployeeCPDReportRecord> employeeCPDRecords = new List<EmployeeCPDReportRecord>();
var q = ( from cpd in pamsEntities.EmployeeCPDs
from traineeEvent in pamsEntities.TrainingEventTrainees
join Employee e in pamsEntities.Employees on cpd.EmployeeID equals e.emp_no
join TrainingEventPart tEventPart in pamsEntities.TrainingEventParts on traineeEvent.TrainingEventPartId equals tEventPart.RecordId
where (cpd.EmployeeID == id) && (startDate >= cpd.StartDate && endDate <= cpd.EndDate) &&
(traineeEvent.EmployeeId == id)
&& (traineeEvent.TraineeStatus == 1 || traineeEvent.TraineeStatus == 2)
&& (tEventPart.CPDHours > 0 || tEventPart.CPDPoints > 0)
&& (cpd.CPDHours > 0 || cpd.CPDPoints > 0)
|| traineeEvent.StartDate >= startDate
|| traineeEvent.EndDate <= endDate
orderby cpd.StartDate
select new EmployeeCPDReportRecord
{
YourEmployeColumnName=(ContextBase.encryptionEnabled==true?ContextBase.Decrypt(e.surname) + ", " + ContextBase.Decrypt(e.forname1) + " " + ContextBase.Decrypt(e.forname2):e.surname + ", " + e.forname1 + " " + e.forname2),
YourEmployeeCPDColumnName=(i.TrainingStartDate !=new DateTime(1900, 1, 1)?"L&D":"Employee CPD")
surname = e.surname,
forname1 = e.forename1,
forname2 = e.forename2,
EmployeeID = cpd.EmployeeID,
StartDate = cpd.StartDate,
EndDate = cpd.EndDate,
CPDHours = cpd.CPDHours,
CPDPoints = cpd.CPDPoints,
Description = cpd.Description,
TrainingStartDate = tEventPart.StartDate,
TrainingEndDate = tEventPart.EndDate,
TrainingCPDHours = tEventPart.CPDHours,
TrainingCPDPoints = tEventPart.CPDPoints,
TrainingEventDescription = tEventPart.Description
}).ToList<EmployeeCPDReportRecord>();

Related

How to optimize slow LINQ query?

I tried delete a statement that use contain() and use skip() take()
but it's still take a long time on execution
public JsonNetResult GetList(C.Lib.ListParam param, string type, DateTime? WorkDate, string MNo, string ANo, string AName, string Specifi, string PNo, string SName, string PType, string OrNo)
{
var idObj = (mis.Models.Security.CIdentity)Csla.ApplicationContext.User.Identity;
var c = new mis.Models.CEntities();
var targetList = (from obj in c.WorkOrders
join obj2 in c.Partners on obj.PartnerId equals obj2.PartnerId
join obj3 in c.Assets on obj.AssetsId equals obj3.AssetsId
join obj4 in c.WorkOrderItems on obj.WorkOrderId equals obj4.WorkOrderId
join obj5 in c.WorkItems on obj4.WorkId equals obj5.WorkId
join obj6 in c.Products on obj3.AssetsId equals obj6.AssetsId
where true && obj.TenantId == idObj.TenantId && obj2.Customer == true && obj.WorkOrderStatus <= 1
select new
{
WorkProgressId = obj.WorkOrderId,
OrderNo = obj.InOrderItem.OrderItem.Order.OrderNo,
ProductType = obj5.ProductType,
WorkOrderId = obj.WorkOrderId,
MakeQty = obj.MakeQty,//delete some column
PrepaidDate = obj.PrepaidDate,
CompleteDate = (from subobj in c.WorkOrderItems
where subobj.WorkOrderId == obj.WorkOrderId && subobj.CompleteDate != null
orderby subobj.CompleteDate descending, subobj.WorkItem.WorkNo descending
select subobj.CompleteDate).FirstOrDefault(),
WorkNoName = (from subobj in c.WorkOrderItems
where subobj.WorkOrderId == obj.WorkOrderId && subobj.CompleteDate != null
orderby subobj.WorkItem.WorkNo descending
select new { WorkNoName = subobj.WorkItem.WorkNo + " " + subobj.WorkItem.WorkName }).FirstOrDefault().WorkNoName,
});
targetList = targetList.GroupBy(x => x.MakeNo).Select(x => new
{
WorkProgressId = x.FirstOrDefault().WorkOrderId,
OrderNo = x.FirstOrDefault().OrderNo,
ProductType = x.FirstOrDefault().ProductType,
WorkOrderId = x.FirstOrDefault().WorkOrderId,
WorkOrderDate = x.FirstOrDefault().WorkOrderDate,
OrderQty = x.FirstOrDefault().OrderQty,
MakeQty = x.FirstOrDefault().MakeQty,
PrepaidDate = x.FirstOrDefault().PrepaidDate,//delete some column
CompleteDate = x.FirstOrDefault().CompleteDate,
WorkNoName = x.FirstOrDefault().WorkNoName
}).OrderByDescending(x => x.WorkOrderDate).ThenByDescending(x => x.WorkNoName);
param.SetCount(targetList);
targetList.OrderByDescending(x => x.WorkOrderDate).ThenByDescending(x=> x.WorkNoName);
var tk= targetList.Skip((param.Page - 1) * param.Rows).Take(param.Rows);
return JsonNetHelper.ReturnData(param,tk);
}
I'm wondering what is the best way to optimize it? Or would the query profiler do that for me?

Searching for a range of dates in LINQ

I'm trying to do a search through a table via LINQ and Entity Framework CORE. I've got 2 text boxes startdate and enddate and a radio button set of 3 options created, modified and both.
This is the code I've produced based on Google searches and tutorials
switch(radCreatedModifiedBoth) {
case "b":
if (!String.IsNullOrEmpty(startDate)) {
if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(startDate + " 00:00:00") &&
ps.CreatedDate <= Convert.ToDateTime(endDate + " 23:59:59")
) || (
ps.ModifiedDate >= Convert.ToDateTime(startDate + " 00:00:00") &&
ps.ModifiedDate <= Convert.ToDateTime(endDate + " 23:59:59")
)
);
} else {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(startDate + " 00:00:00")
||
ps.ModifiedDate >= Convert.ToDateTime(startDate + " 00:00:00")
)
);
}
} else if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(endDate + " 23:59:59")
||
ps.ModifiedDate >= Convert.ToDateTime(endDate + " 23:59:59")
)
);
}
break;
case "c":
if (!String.IsNullOrEmpty(startDate)) {
if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(startDate + " 00:00:00") &&
ps.CreatedDate <= Convert.ToDateTime(endDate + " 23:59:59")
)
);
} else {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(startDate + " 00:00:00")
)
);
}
} else if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps <= (
ps.CreatedDate >= Convert.ToDateTime(endDate + " 23:59:59")
)
);
}
break;
case "m":
if (!String.IsNullOrEmpty(startDate)) {
if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps => (
ps.ModifiedDate >= Convert.ToDateTime(startDate + " 00:00:00") &&
ps.ModifiedDate <= Convert.ToDateTime(endDate + " 23:59:59")
)
);
} else {
persons = persons.Where(ps => (
ps.ModifiedDate >= Convert.ToDateTime(startDate + " 00:00:00")
)
);
}
} else if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps <= (
ps.ModifiedDate >= Convert.ToDateTime(endDate + " 23:59:59")
)
);
}
break;
}
This code works but seems massively inefficient, not to mention adding the start and end time into the date as a string like this
startDate + " 00:00:00"
endDate + " 23:59:59"
just seems wrong. Is this the prescribed method or can anyone suggest a more efficient method preferably getting rid of the " 00:00:00"/" 23:59:59"
Thanks
You can simplify by pushing the tests to SQL - the conditional operator will be translated to SQL CASE WHEN since they aren't simple constants. Note that I assumed you have the endDate tests backwards in your code sample. Also you have a lot of repeated sub-expressions I consolidated to variables. Since you are using EF Core, there isn't a better way to handle date only comparisons then what you are using. In EF you can use a DbFunction, but it still isn't as good as converting your dates to the appropriate date+time so that indices can be used.
var hasStartDate = !String.IsNullOrEmpty(startDate);
var dtStartDate = hasStartDate ? Convert.ToDateTime(startDate + " 00:00:00") : DateTime.MinValue;
var hasEndDate = !String.IsNullOrEmpty(endDate);
var dtEndDate = hasEndDate ? Convert.ToDateTime(endDate + " 23:59:59") : DateTime.MinValue;
var chkCreatedDate = (radCreatedModifiedBoth == "b" || radCreatedModifiedBoth == "c");
var chkModifiedDate = (radCreatedModifiedBoth == "b" || radCreatedModifiedBoth == "m");
persons = persons.Where(ps => (chkCreatedDate ? (hasStartDate ? ps.CreatedDate >= dtStartDate : true) && (hasEndDate ? ps.CreatedDate <= dtEndDate : true) : true)
||
(chkModifiedDate ? (hasEndDate ? ps.ModifiedDate >= dtStartDate : true) && (hasEndDate ? ps.ModifiedDate <= dtEndDate : true) : true)
);

Linq query dynamic

I've this linq query:
var query = (from l in _contexto.lineasencargos
join a in _contexto.articulos on l.IDARTICULO equals a.IDARTICULO
join af in _contexto.articulofamilia on a.IDARTICULO equals af.IDARTICULO
join f in _contexto.familias on af.IDFAMILIA equals f.IDFAMILIA
join e in _contexto.encargos on l.IDENCARGO equals e.IDENCARGO
where e.FECHAHORAENCARGOS >= _finder.FechaDe &&
e.FECHAHORAENCARGOS <= _finder.FechaA &&
e.FECHAHORARECOGERENCARGOS >= _finder.FechaRecogerDe &&
e.FECHAHORARECOGERENCARGOS <= _finder.FechaRecogerA &&
e.clientes.RAZONSOCIALCLIENTE.Contains(_finder.Cliente)
group l by new { l.IDARTICULO, l.CANTIDADLINEAENCARGO,a.DESCRIPCIONARTICULO,f.DESCRIPCION,f.IDFAMILIA }
into g
select new listaEncargosAgrupados
{
IdArticulo=(int)g.Key.IDARTICULO,
DescripcionArticulo=g.Key.DESCRIPCIONARTICULO,
IdFamilia=g.Key.IDFAMILIA,
DescripcionFamilia=g.Key.DESCRIPCION,
SumaCantidad = (decimal)g.Sum(x => x.CANTIDADLINEAENCARGO),
SumaPrecio = (decimal)g.Sum(x => x.PRECIOLINEAENCARGO),
Total = (decimal)((decimal)g.Sum(x => x.CANTIDADLINEAENCARGO) * g.Sum(x => x.PRECIOLINEAENCARGO))
});
and i need create a condition in Where, that filter dynamically:
if (_finder.IdTienda > 0)
{
query = query.Where(x=>x.IDTIENDA == _finder.IdTienda);
}
But this Where it is not correct because IDTIENDA is contained in _context.encargos and not in listaEncargosAgrupados
How i can revolve this problem?
Thanks
Add e into grouping statement and IDTIENDA list into the result:
var query = (from l in _contexto.lineasencargos
join a in _contexto.articulos on l.IDARTICULO equals a.IDARTICULO
join af in _contexto.articulofamilia on a.IDARTICULO equals af.IDARTICULO
join f in _contexto.familias on af.IDFAMILIA equals f.IDFAMILIA
join e in _contexto.encargos on l.IDENCARGO equals e.IDENCARGO
where e.FECHAHORAENCARGOS >= _finder.FechaDe &&
e.FECHAHORAENCARGOS <= _finder.FechaA &&
e.FECHAHORARECOGERENCARGOS >= _finder.FechaRecogerDe &&
e.FECHAHORARECOGERENCARGOS <= _finder.FechaRecogerA &&
e.clientes.RAZONSOCIALCLIENTE.Contains(_finder.Cliente)
group new { l, e} by new { l.IDARTICULO, l.CANTIDADLINEAENCARGO,a.DESCRIPCIONARTICULO,f.DESCRIPCION,f.IDFAMILIA }
into g
select new { Result = new listaEncargosAgrupados
{
IdArticulo=(int)g.Key.IDARTICULO,
DescripcionArticulo=g.Key.DESCRIPCIONARTICULO,
IdFamilia=g.Key.IDFAMILIA,
DescripcionFamilia=g.Key.DESCRIPCION,
SumaCantidad = (decimal)g.Sum(x => x.l.CANTIDADLINEAENCARGO),
SumaPrecio = (decimal)g.Sum(x => x.l.PRECIOLINEAENCARGO),
Total = (decimal)((decimal)g.Sum(x => x.l.CANTIDADLINEAENCARGO) * g.Sum(x => x.l.PRECIOLINEAENCARGO))
},
IDTIENDAs = new HashSet<int>(from x in g
let id = x.e.IDTIENDA
where id.HasValue
select (int)id.Value)
});
...
if (_finder.IdTienda > 0)
{
query = query.Where(x => x.IDTIENDAs.Contains (_finder.IdTienda));
}
var query1 = query.Select(x => x.Result);
Finally the solution to my problem was to employ executestorequery in the context of my EF, and creat a SQL query :
List<ListaEncargosAgrupados> lista;
string queryString = #"SELECT l.IDARTICULO,a.DESCRIPCIONARTICULO,f.DESCRIPCION descripcionFamilia,f.IDFAMILIA,sum(l.CANTIDADLINEAENCARGO) sumaCantidad,avg(l.PRECIOLINEAENCARGO)
sumaPrecio,sum(l.CANTIDADLINEAENCARGO)*avg(l.PRECIOLINEAENCARGO) Total " +
"FROM lineasencargos l,articulos a,articulofamilia af,familias f,encargos e " +
"where a.IDARTICULO=l.IDARTICULO and a.IDARTICULO=af.IDARTICULO " +
"and af.IDFAMILIA=f.IDFAMILIA and l.IDENCARGO=e.IDENCARGO ";
if (_finder.IdTienda > 0)
{
queryString = queryString + " and e.idtienda=" + _finder.IdTienda;
}
queryString = queryString + " group by l.IDARTICULO,a.DESCRIPCIONARTICULO,f.DESCRIPCION,f.IDFAMILIA order by a.DESCRIPCIONARTICULO ";
var salidaQuery = _contexto.ExecuteStoreQuery<ListaEncargosAgrupados>(queryString).AsQueryable().ToList();
lista = salidaQuery;

Dynamic linq not working

I have a problem. I want to build a dynamic LINQ query like this:
var result = from li in datacTx.LIs
where
(((StartDate != null) && (StartDate.Date != DateTime.MinValue)) ? li.Available <= StartDate.Date : true) &&
(((EndDate != null) && (EndDate.Date != DateTime.MinValue)) ? li.Expire <= EndDate.Date : true)
select new
{
A,
B,
C,
D
};
Before calling this query I am intializing the StartDate and EndDate with:
StartDate = DateTime.MinValue;
EndDate = DateTime.MinValue;
The problem is that the branch of "if" is always wrong I never can get the "true" branch if the StartDate and EndDate are having MinValue.
Try using a simpler condition:
where ((StartDate == DateTime.MinValue || li.Available <= StartDate.Date) &&
(EndDate == DateTime.MinValue || li.Expire <= EndDate))
However, if I were to implement something like this, I would actually create the query dynamically:
var query = datacTx.LIs;
if(StartDate != DateTime.MinValue)
query = query.Where(li => li.Available <= StartDate.Date);
if(EndDate != DateTime.MinValue)
query = query.Where(li => li.Expire <= EndDate .Date);
var result = query.Select(x => new { A, B, C, D });

Problems with Linq(join)

I am writting a query with linq(follow code bellow). I am looking for data from db.imovel and for each one bring a picture nested into db.fotoimovel. Keep in mind that I may have more than one picture for each db.imovel data.
The issue is when I run, it returns me all the pictures with the same db.imovel data in all of them.
It works for me if return the db.imovel data with just one(may be the first picture) from db.fotoimovel.
Code:
var retorno = (from c in db.fotoimovel
join p in db.imovel on c.idImovel equals p.idImovel
where p.MetragemImovel >= metragem1 && p.MetragemImovel <= metragem2 &&
p.StatusImovel == opcao &&
((String.IsNullOrEmpty(bairro)) || p.BairroImovel == bairro) &&
((imovel == null) || (p.TipoImovel == imovel)) &&
((carros == null) || (p.QtdVagaGaragemImovel == carros)) &&
((quartos == null) || (p.QtdQuartoImovel == quartos))
select new DadosImovel
{
Id = p.idImovel,
Titulo = p.TituloImovel,
Descricao = p.DescricaoImovel,
Foto = c.NomeFotoImovel,
TipoImovel = p.TipoImovel,
Endereco = p.EnderecoImovel,
Complemento = p.ComplementoImovel,
Bairro = p.BairroImovel,
Cidade = p.CidadeImovel,
Estado = p.EstadoImovel,
CEP = p.CEPImovel,
MetragemImovel = p.MetragemImovel,
QtdComodoImovel = p.QtdComodoImovel,
QtdQuartoImovel = p.QtdQuartoImovel,
QtdBanheiroImovel = p.QtdBanheiroImovel,
QtdVagaGaragemImovel = p.QtdVagaGaragemImovel,
QtdAndarImovel = p.QtdAndarImovel,
Status = p.StatusImovel,
Ativo = p.AtivoImovel
}).Distinct().ToList();

Resources