linq where condition on subselect - linq

how can we add a where condition to a linq subselect query.
i.e.
List<CallLog> callLog = CallLog.SampleData();
List<Contacts> contacts = Contacts.SampleData();
var q = from call in callLog
where call.Incoming == true
group call by call.Number into g
select new contacts {
contact.FirstName = g.FirstName,
contact.LastName = g.LastName,
Count = g.Count(),
Avg = g.Average( c => c.Duration ) <--- WHERE c.Duration > 5,
Total = g.Sum( c => c.Duration ) <--- WHERE c.Duration >= 60
};
How can we add a "Where condition" to the LINQ statement as shown above?

Simply add a Where method with the clause you described!
Avg = g.Where(c => c.Duration > 5).Average(c => c.Duration),
Total = g.Where(c => c.Duration >= 60).Sum(c => c.Duration)

You almost had it:
var q = from call in callLog
where call.Incoming == true
group call by call.Number into g
select new contacts {
contact.FirstName = g.FirstName,
contact.LastName = g.LastName,
Count = g.Count(),
Avg = g.Where(c => c.Duration > 5).Average( c => c.Duration ),
Total = g.Where(c => c.Duration >= 60).Sum( c => c.Duration )
};

Related

How to get list of results in Linq

I'm taking a list of counts, averaging and returning all results according to the condition. Looks like my command is too erroneous. I don't know how to do it yet.
I have tables:
var qr = (from Product c in _context.Products
join o in _context.RatingProducts on c.ID equals o.IDProduct
where c.Status == true
orderby c.NumProduct
group o by c.ID into g
select new {
ProductId = g.Key,
CountID = g.Count(),
//SumID = g.Sum(s => s.StarRating).ToString(),
AveragedID = g.Count() > 0 ? g.Average(x => x.StarRating) : 0
}).ToList();
var getqr = _context.Products.Where(a => a.Status).ToList();
int count = 0;
double averaged = 0;
foreach (var item in getqr)
{
int key = item.ID;
var id = qr.Where(x => x.ProductId == key).FirstOrDefault();
if(id != null)
{
count = id.CountID;
averaged = Math.Round(id.AveragedID,1);
}
var productquery = item;
}
var query = from c in qr
join p in getqr on c.ProductId equals p.ID
select new ProductQuery
{
ID = p.ID,
IDProduct = p.IDProduct,
CategoryID = p.CategoryID,
NumProduct = p.NumProduct,
Name = p.Name,
Status = p.Status,
Price = p.Price,
PriceOld = p.PriceOld,
ContentsSmall = p.ContentsSmall,
Contents = p.Contents,
Images = p.Images,
CountID = count,
//SumID = c.SumID,
AveragedID = averaged,
};
return query.ToList();
However when I debug, it shows only one result with row ID = 1. I want to display list: count, average results of table 1. Tks.
As far as I understand you should make LEFT JOIN here, so need to add DefaultIfEmpty in the initial query, and slightly change average counting logic.
Something like this, should work:
var qr = (from Product c in _context.Products
join o in _context.RatingProducts on c.ID equals o.IDProduct into productRatings
from pr in productRatings.DefaultIfEmpty()
where c.Status == true
orderby c.NumProduct
group o by c.ID into g
select new {
ProductId = g.Key,
CountID = g.Count(),
AveragedID = g.Average(x => x == null ? 0 : x.StarRating)
}).ToList();

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?

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;

Finding bounds with LINQ

This code works ok, but I was wondering whether there isn't some way to write it in one LINQ expression so a single pass can be done by the database server instead of realising a result set and then looping through it, which is what my code will produce.
var logs = from AssetLog log in dc.AssetLogs
where log.AssetId == assetId && log.Recorded >= start && log.Recorded <= finish
select log;
return new GetInteractionBoundsResult()
{
N = logs.Max(log => log.Latitude),
S = logs.Min(log => log.Latitude),
W = logs.Min(log => log.Longitude),
E = logs.Max(log => log.Longitude)
};
So, LINQ gurus, how would you write the above so that it produces more or less this at the database:
SELECT MIN(Latitude) S, MAX(Latitude) N, MIN(Longitude) W, MAX(Longitude) E
FROM ASSETLOG WHERE etc etc
Sure, just trick your LINQ provider into thinking it's still working with a query until the very end:
var logs = from asset in dc.Assets
where asset.AssetId == assetId
let g = asset.AssetLogs
.Where(log => log.Recorded >= start && log.Recorded <= finish)
select new GetInteractionBoundsResult
{
N = g.Max(log => log.Latitude),
S = g.Min(log => log.Latitude),
W = g.Min(log => log.Longitude),
E = g.Max(log => log.Longitude)
};
return logs.Single();
A Group By may perform better than the join that the above query would produce:
var logs = from log in dc.AssetLogs
where log.AssetId == assetId &&
log.Recorded >= start && log.Recorded <= finish
group log by log.AssetId into g
select new GetInteractionBoundsResult
{
N = g.Max(log => log.Latitude),
S = g.Min(log => log.Latitude),
W = g.Min(log => log.Longitude),
E = g.Max(log => log.Longitude)
};
return logs.Single();
It would take a pretty sophisticated LINQ provider, but a subquery may work:
var res = from asset in dc.Assets
where log.AssetId == assetId
let logs = (from AssetLog log in asset.AssetLogs
where log.Recorded >= start && log.Recorded <= finish
select log)
select new GetInteractionBoundsResult()
{
N = logs.Max(log => log.Latitude),
S = logs.Min(log => log.Latitude),
W = logs.Min(log => log.Longitude),
E = logs.Max(log => log.Longitude)
};
return res.Single();

Linq PredicateBuilder multi criteria

List<Product> Prs = data.Products
.Where(x=> x.ProductColors
.Where(y=> y.Color=="blue")
.Select(z=> z.ProductID)
.Contains(x.ID) && x.ProductColors
.Where(y=> y.Color== "red")
.Select(z=> z.ProductID)
.Contains(x.ID))
.ToList();
How to PredicateBuilder multi-criteria?
Something like the following:
var inner = PredicateBuilder.False<Product>();
inner = inner.Or (p => p.Description.Contains ("foo"));
inner = inner.Or (p => p.Description.Contains ("far"));
var outer = PredicateBuilder.True<Product>();
outer = outer.And (p => p.Price > 100);
outer = outer.And (p => p.Price < 1000);
outer = outer.And (inner);
var results = data.Products.AsExpandable().Where(outer)
You can read more about PredicateBuilder here

Resources