Nhibernate query for Any condition - linq

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);

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.

Get default value from a select in a query

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)

linq to entities group by sub-query

I have the following code:
var statements = db.statement
.OrderByDescending(d => d.id)
.Take(5)
.AsEnumerable()
.Select(d => new Statements
{
Accounts = d.statement_entry.AsEnumerable()
.GroupBy(b => b.currency)
.Select(b =>
new Account
{
In = b.Where(l => l.amount > 0).Sum(l => l.amount),
Out = b.Where(l => l.amount < 0).Sum(l => l.amount),
Balance = b.Sum(l => l.amount),
Currency = b.Key
}).OrderBy(b => b.Currency),
UploadedDate = d.uploaded_date,
Id = d.id
})
.ToList();
Is there a way that I could do it without the AsEnumerable()? From what I understand the AsEnumberable will cause a query to take place for each of the statements returned.
Or is there a better way to refactor the code?
You understand wrongly. AsEnumerable will make the query execute on the local (client) machine.
This
statements = db.statement
.OrderByDescending(d => d.id)
.Take(5)
will be executed on the (SQL) server,
the remaining part on the client
Why are you puttin the AsEnumerable? I think the query should work even without (and it would do everything server-side)
The only thing is that after the OrderBy(b => b.Currency) you should put a .ToList() so that the .Select(b => new Account is materialized and cached.

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)

Resources