Simplify multiple nhibernate queryover - c#

I'm doing a query over two different tables.
In the first query, i get some Ids that I then have to check in another table.
Then I do the first query again with the result of the second query.
This can't be the best way to do this.
But I haven't found a good way to solve it. So some help would be appreciated.
IntOrderInvoiceCostOut y = null;
var list = session.QueryOver<IntOrderInvoiceCostOut>(() => y)
.Where(x => x.IntegrationHandleDate == null)
.Select(Projections.Distinct(Projections.Property(() => y.Externalid)))
.List<string>();
var nonPreliminaryOrders = session.QueryOver<RefImplOrderEntity>()
.WhereRestrictionOn(x => x.ExternalId).IsIn(list.ToList())
.Where(x => x.StatusTypeId != 95)
.Select(x => x.ExternalId)
.List<string>();
var finalList = session.QueryOver<IntOrderInvoiceCostOut>()
.WhereRestrictionOn(x => x.Externalid).IsIn(nonPreliminaryOrders.ToList())
.Where(x => x.IntegrationHandleDate == null)
.OrderBy(x => x.IntegrationCreateDate)
.Asc
.List();
The code works...but i't really ugly.

you could use detacheCriteria for this. I have omitted couple of conditions and you might have to twick a bit as per your requirement.
for example
IntOrderInvoiceCostOut y = null;
var list = QueryOver.Of<IntOrderInvoiceCostOut>(() => y)
.Where(x => x.IntegrationHandleDate == null)
.Select(Projections.Distinct(Projections.Property(() => y.Externalid)))
.DetachedCriteria;
var nonPreliminaryOrders = QueryOver.Of<RefImplOrderEntity>()
.Where(Subqueries.PropertyIn(nameof(RefImplOrderEntity.ExternalId), list));
.Select(x => x.ExternalId)
.DetachedCriteria
var finalList = session.QueryOver<IntOrderInvoiceCostOut>()
.Where(Subqueries.PropertyIn(nameof(IntOrderInvoiceCostOut.ExternalId), nonPreliminaryOrders));
.List();

Related

Way to DistinctBy will remove duplicates from a repeating id but if the value is null will leave the duplicates?

There is a way to prevent duplicates Id, but if id is null to let the list to be with duplicates null?
data = data
.OrderByDescending(x => x.DocVersionNumber)
.DistinctBy(x => x.RequireId)
.ToList();
in this way if I have few items with null on RequireId, only one will stay.
Thanks
you can do it like this
var temp = data.Where(x => x.RequireId == null).ToList();
data = data.Where(x => x.RequireId != null)
.OrderByDescending(x => x.DocVersionNumber)
.DistinctBy(x => x.RequireId)
.ToList();
data.AddRange(temp);
data = data
.Where(i => i.RequireId != null)
.OrderByDescending(x => x.DocVersionNumber)
.DistinctBy(x => x.RequireId)
.ToList();

How to select a list of distinct values based on some values using linq or entity

I want to get all the Pre_Number where all Reconcile_Status related to that Pre_Number=null. In this case there should not be any item in list.If there would be some other Pre_number for eg. 7/2018 and it has two records and Reconcile_Status for those records is NULL then i should get one item in list that is 7/2018.
I tried
var NoNReconciled = context.tbl_prerelease_invoice
.Where(x => x.Reconcile_Status==null)
.Select(y => new { y.Pre_number }).Distinct().ToList();
But i got 6/2018
Well, your current attempt only checks that there is at least one record where Reconcile_Status is null, but it doesn't check that there are no records with the same Pre_number where Reconcile_Status is not null.
This should do the trick:
var NoNReconciled = context.tbl_prerelease_invoice
.Where(x => x.Reconcile_Status == null &&
!context.tbl_prerelease_invoice
.Any(y => y.Pre_number == x.Pre_number && y.Reconcile_Status != null)
).Select(y => new { y.Pre_number })
.Distinct().ToList();
No need to create anonymous object for Pre_Number. Try below code
var NoNReconciled = context.tbl_prerelease_invoice
.Where(x => x.Reconcile_Status==null)
.Select(y => y.Pre_number).Distinct().ToList();
Try this-
context.tbl_prerelease_invoice.GroupBy(r => r.Pre_number).Where(kv => kv.All(r => r.Reconcile_Status==null)).Select(kv => kv.Key).ToList();

Replacing Distinct() with GroupBy(...) in Linq

To get a performance gain, I am trying to replace the call to Distinct() below with GroupBy(...), however I am getting errors.
Any suggestions on how this query should be rewritten to use GroupBy(...)?
I am trying to use GroupBy() on the Description field itself.
var result=
GetResults()
.Select(x => new SelectList { Text = x.Description, Value = x.Description })
.Where(x => x.Text != null)
.Distinct()
.ToList();
You can't force the Entity Framework to use GroupBy instead of Distinct clause in generated SQL. Entity framework will determine the appropriate query and it will use that.
One thing that is apparent from your code is that you are only interested in List<string> based on unique Description values. I don't think you have to create a collection of SelectList.
You can do:
var result= GetResults()
.Where(x => x.Description != null)
.GroupBy(x => x.Description)
.Select(grp => grp.Key)
.ToList();
OR
var result= GetResults()
.Where(x => x.Description != null)
.Select(x => x.Description)
.Distinct()
.ToList();
Both of the above queries would produce a list of unique description values. Now what type of SQL will be generated against both of these depends on the Entity Framework.
Old Answer:
Use GroupBy to group on Description and then Select where Key is not null like:
var result= GetResults()
.Select(x => new SelectList { Text = x.Description, Value = x.Description })
.Where(x => x.Text != null)
.GroupBy(x => x.Value) //Here select Value for Description
.Select(grp => grp.Key)
.ToList();
This will not give you any performance gain, even if there is any, it would be negligible.
You can yry grouping by Description:
var result=GetResults()
.GroupBy(x => x.Description)
.Where(g => g.Key != null)
.Select(g => new SelectList { Text = g.Key, Value = g.Key })
.ToList();
But I'd be surprised if you got better performance that a Distinct.

Multiple Any() in one Where() clause LINQ

Is it possible to use several Any() in one where() clause ?
For example, If I need to get favourite beers, this query will do the job:
var favouriteDrinks = drinks
.Where(f => favouriteBeers
.Any(d => d.drinkID == f.drinkID));
But what if I need to get favourite Beers and favourite Wines ? I am looking for something like this:
var favouriteDrinks = drinks
.Where(f => favouriteBeers.Any(d => d.drinkID == f.drinkID) ||
f => favouriteWines.Any(d => drinkID == f.drinkID));
var favouriteDrinks = drinks
.Where(f => favouriteBeers.Any(d => d.drinkID == f.drinkID) ||
favouriteWines.Any(d => d.drinkID == f.drinkID));
why not do it like this:
var favouriteDrinks = drinks.Where(f =>
favouriteBeers.Any(d => d.drinkID == f.drinkID)) ||
favouriteWines.Any(d => d.drinkID == f.drinkID)));
also you can use Contains:
var favouriteDrinks = drinks.Where(f =>
favouriteBeers.Contains(f.drinkID) ||
favouriteWines.Contains(f.drinkID));
You can use .Union() and .Join()
var favouriteDrinks = favouriteBeers
.Union(favouriteWines)
.Join(drinks,
x => x.drinkID,
y => y.drinkID,
(x,y) => y
);
This will work as long as favouriteBeers, and favouriteWines are of the same type.
This fixes Tim.Tang's second example I believe. There are several approaches in here, but if it comes down to "contains" vs "any", I prefer contains as the intention is much more clear to me.
var favouriteDrinks = drinks.Where(d =>
favouriteBeers.Select(b => b.drinkId).Contains(d.drinkID) ||
favouriteWines.Select(w => w.drinkId).Contains(d.drinkID));
Similarly, with the correct IEquatable interfaces implemented on your "drink" classes, you can slightly simplify too
var favouriteDrinks = drinks.Where(d =>
favouriteBeers.Contains(d) || favouriteWines.Contains(d));

could not resolve property: PropertyName of: Class error in NHibernate

I'm using NHibernate first time and in this line it throws exception for me
var total = session
.QueryOver<Comment>().Where(p => p.Entry.Author == username)
.ToRowCountQuery()
.FutureValue<int>();
var results = session
.QueryOver<Comment>().Where(p => p.Entry.Author == username)
.Fetch(x => x.Entry).Eager()
.OrderBy(x => x.Posted).Desc()
.Skip(skip)
.Take(take)
.List();
The Exception is
could not resolve property: Entry.Author of: FunnelWeb.Model.Comment
I guess, the problem is that Entry object doesn't loaded here. How can I do that trick with Nhibernate?
QueryOver is just a strongly-typed wrapper for Criteria, and doesn't allow implicit deep references.
You'd have to use:
session.QueryOver<Comment>()
.JoinQueryOver(x => x.Entry)
.Where(x => x.Author == username)
Or you can use Query<> instead (LINQ) which will work with the syntax you've tried.
You'd need to JoinAlias or JoinQueryOver. I have an example below on how to use Future queries...
Entry entryAlias = null;
var q = session.QueryOver<Comment>()
.JoinAlias(x => x.Entry, () => entryAlias)
.Where(() => entryAlias.Author == username);
var totalFuture = q.ToRowCountQuery().FutureValue<int>(); //ToRowcountQuery clones the query, we can reuse it for results
var resultsFuture = q
//.Fetch(x => x.Entry).Eager() //already joined
.OrderBy(x => x.Posted).Desc()
.Skip(skip)
.Take(take)
.Future<Comment>();
var results = resultsFuture.ToList(); //both future queries are executed in the same batch
var total = totalFuture.Value;

Categories

Resources