Get default value from a select in a query - linq

Im kinda having troubles learning Linq, people say its not soo hard to learn who already know something about Sql, but im still having troubles, basicly i have a table where i have a expend or a earning, im having troubles when i search between 2 dates some values to do statistics i know that happen, cause sometimes when i search between 2 dates i just have a expense and not a earning and in the query he has no idea what he should do, so how can i put default values for all the atributes inside the select?
[HttpPost]
public ActionResult Index(string dataInicial, string dataFinal)
{
var userId = User.Identity.GetUserId();
var queryDefault = db.SaldoUtilizadores.Where(d => d.ApplicationUserId == userId)
.GroupBy(x => x.ApplicationUserId)
.Select(x => new
{
biggestValor = x.Max(y => y.valor),
lowestValor = x.Min(y => y.valor),
expenses = x.Where(y => y.valor < 0).Sum(y => y.valor),
earnings = x.Where(y => y.valor > 0).Sum(y => y.valor),
lowestDate = x.Where(y => y.valor == x.Min(z => z.valor)).Select(y => y.data).FirstOrDefault(),
biggestDate = x.Where(y => y.valor == x.Max(z => z.valor)).Select(y => y.data).FirstOrDefault()
}).FirstOrDefault();
i already searched a lot and didnt find a concret answer if you guys can help me i appreciate.
Ps: Sorry for my bad english

Instead of Where(condition).Sum(selector) which generates exception when the result of Where is an empty set, you can use one of the following constructs:
(A) Where(condition).Select(selector).DefaultIfEmpty().Sum():
expenses = x.Where(y => y.valor < 0).Select(y => y.valor).DefaultIfEmpty().Sum(),
earnings = x.Where(y => y.valor > 0).Select(y => y.valor).DefaultIfEmpty().Sum(),
(B) Where(condition).Select(({nullable type})selector).Sum() ?? 0:
expenses = x.Where(y => y.valor < 0).Sum(y => (decimal?)y.valor) ?? 0,
earnings = x.Where(y => y.valor > 0).Sum(y => (decimal?)y.valor) ?? 0,
(C) Sum(condition ? selector : 0):
expenses = x.Sum(y => y.valor < 0 ? y.valor : 0),
earnings = x.Sum(y => y.valor > 0 ? y.valor : 0),

from your problem what I perceived is that you are trying to group the values based on userid.
you can use x.DefaultIfEmpty() according your need.

expenses = ((x.Where(y => y.valor).Sum(y => y.valor))==null ||(x.Where(y =>y.valor).Sum(y => y.valor))<0)?0:x.Where(y => y.valor).Sum(y => y.valor)

Related

Linq most efficient top results

I'm wondered I have a table with IDs and a version and a remove field. I d like to return the the top 20 records grouped by ID and for ech ID take only the highest version unless remove is set then ignore removed records.
Then return a descending record set.
There are a few ways todo it with Linq but I wonder is there a most efficient way, are there patterns to avoid?.
...
.OrderByDescending(x=>x.id)
.GroupBy(x=>x.id)
.SelectMany(y=>y.Where(x=>x.Version == y.Max(y=>y.Version)))
.Where(x=>x.Remove=false)
.Take(20)
One of then possible workarounds when using EF Core. I'm calling it workaround because with SQL and Window functions we can create more effective query.
var itemsQuery = ctx.SomeTable
.Where(x => x.Remove = false);
var query =
from d in itemsQuery.Select(d => new { d.id }).Distinct()
from x in itemsQuery.Where(x => d.Id == x.Id)
.OrderByDescending(x => x.Version)
.Take(1)
select x;
query = query.Take(20);
Similar queries when using EF Core 6:
var query = ctx.SomeTable
.Where(x => x.Remove = false)
.GroupBy(x => x.Id)
.Take(20)
.SelectMany(g => g.OrderByDescending(x => x.Version).Take(1));
var query = ctx.SomeTable
.Where(x => x.Remove = false)
.GroupBy(x => x.Id)
.Select(g => g.OrderByDescending(x => x.Version).First());
.Take(20);

Using GroupBy and show different Sums based on conditions - LINQ Lambda Expressions

I have a table with 3 columns.
And I would like to present a table with this structure:
Can someone show me how to do this with Lambda expressions?
So far I've only gotten the result if I only wanted to show one column:
var sum_data = _context.HechosFinanza
.Where(x => x.Product.Sale_Type == "Cash Sale")
.GroupBy(x => x.Product.Product_Name)
.Select(x => Product { Tienda = x.Key, Total = x.Sum(s =>
s.sales_amount) });
I don't know if something like this may be possible (no idea really, just trying to figure it out):
var sum_data = _context.HechosFinanza
// I remove there where condition from here
.GroupBy(x => x.Product.Product_Name)
// And I add the where condition in each sum
.Select(x => Product { Tienda = x.Key,
TotalCash = x.Sum(s => s.sales_amount).Where(s => s.Product.Sale_Type == "Cash Sale"),
TotalCredit = x.Sum(s => s.sales_amount).Where(s.Product.Sale_Type == "Credit Sale")
});
Uhm, well. It turns out I was really close.
Just had to put the 'Where' statement before.
Answer:
var sum_data = _context.HechosFinanza
// I remove there where condition from here
.GroupBy(x => x.Product.Product_Name)
// And I add the where condition in each sum
.Select(x => Product { Tienda = x.Key,
TotalCash = x.Where(s => s.Product.Sale_Type == "Cash Sale").Sum(s => s.sales_amount),
TotalCredit = x.Where(s.Product.Sale_Type == "Credit Sale") .Sum(s => s.sales_amount)
});
And done.

Nhibernate query for Any condition

I have table structure like
Product {List<Cost> Costs}
Cost{List<Invoice> Invoices, Product product}
Invoice{bool isIncluded}
Need a query to get all Products which has any Cost for which none of invoice is included (isIncluded=false for all)
I tried something like:
Product pro= null;
Product p = null;
var costQuery = QueryOver.Of<Cost>()
.JoinAlias(c => c.Product, () => p)
.Where(() => p.Id == pro.Id)
.WhereNot(c=>c.Invoices.Any(i=>i.IsIncluded))
.Select(c => c.Id);
var query = CurrentSession.QueryOver<Product>(() => pro)
.WithSubquery.WhereExists(costQuery);
Use of 'Any' in query errors out:
Unrecognised method call: System.Linq.Enumerable:Boolean
Any[Invoice](System.Collections.Generic.IEnumerable1[Trigger.StageGate.Services‌​.BusinessEntities.Invoice],
System.Func2[Trigger.StageGate.Services.BusinessEntities.Invoice,System.Boolean‌​])
try:
var costQuery = QueryOver.Of<Cost>()
.JoinAlias(c => c.Product, () => p)
.Where(() => p.Id == pro.Id)
.JoinQueryOver<Invoice>(c => c.Invoices)
.WhereNot(i => i.IsIncluded)
.Select(c => c.Id);

Order by in Linq

how can i show null or empty fields in last by apply Orderby:
here is my code.
Var movies = _db.Movies.Orderby(c => c.Category).ThenBy(n => n.Name)
If I understand your question correctly:
Var movies = _db.Movies
.OrderBy(c => c.Category==null?1:0)
.Thenby(c => c.Category).ThenBy(n => n.Name)

LINQ Query with 3 levels

I have a business object structured like this:
Country has States, State has Cities
So Country[2].States[7].Cities[5].Name would be New York
Ok, I need to get a list of all the Country objects which have at least 1 City.IsNice == true
How do I get that?
var selectedCountries =
countries.Where(
co => co.States.Any(
s => s.Cities.Any(
ci => ci.IsNice)));
Another option :
var selectedCountries =
countries.Where(
co => co.States.SelectMany(s => s.Cities).Any(
ci => ci.IsNice));
var result = (from country in db.Countries
from state in country.States
from city in state.Cities
where city.IsNice
select county).Distinct();
I would do it in one of two ways:
var selectedCountries = from country in countries
from state in country.States
from city in state.Cities
where city.IsNice
select country;
or
var selectedCountries =
countries.Where(country =>
country.States.FirstOrDefault(state =>
state.Cities.FirstOrDefault(city =>
city.IsNice) != null) != null);
var result = Countries
.SelectMany(a => a.States)
.SelectMany(b => b.Cities)
.Where(b => b.IsNice == true)
.ToList();

Resources