I have a query that work on a great data table. The code for the query is:
var getExtInv = snd.external_invoices.OrderByDescending(x => x.date).ToList();
var query = (from c in getExtInv
join o in snd.invoices on c.idexternal_invoices equals o.id_external_invoice
select new {c.idexternal_invoices,
c.businessname,
o.number,
c.message,
c.price,
c.date,
c.tipologiaPagamento,
c.esitoPagamento,
c.iduser
}).ToList();
I need to filter this query with a number of textbox value that can be empty. An example for one search filter is:
if (txtIdUser.Text != "")
{
int idUserSel = Convert.ToInt32(txtIdUser.Text);
query = query.Where(x => x.iduser == idUserSel).ToList();
}
the problem is that with this approach initially load a very high number of data which then filter based on the presence or absence of textfield filled. In doing so the initial loading time is very long. How can I speed up the process?
Thanks to all
As mentioned, don't use .ToList, .ToArray, .Count, etc. before you are ready to use the results.
int i = 0;
var query = from c in snd.external_invoices.OrderByDescending(x => x.date)
join o in snd.invoices on c.idexternal_invoices equals o.id_external_invoice
select new {c.idexternal_invoices, c.businessname, o.number, c.message,
c.price, c.date, c.tipologiaPagamento, c.esitoPagamento, c.iduser };
if(int.TryParse(txtIdUser.Text, out i) // this will check if text is not empty and valid int
query = query.Where(x => x.iduser == i);
and at the end when you are ready to use the results:
var results = query.ToList();
Related
How would you write a linq query with the following SQL statement. I've tried several methods referenced on stackoverflow but they either don't work with the EF version I'm using (EF core 3.5.1) or the DBMS (SQL Server).
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp = (select max(DateTimeStamp) from Products where a.ProductID = ProductID)
For reference, a couple that I've tried (both get run-time errors).
var results = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.OrderByDescending(x => x.DateTimeStamp).FirstOrDefault());
var results = _context.Products
.GroupBy(x => new { x.ProductID, x.DateTimeStamp })
.SelectMany(y => y.OrderByDescending(z => z.DateTimeStamp).Take(1))
Thanks!
I understand you would like to have a list of the latest prices of each products?
First of all I prefer to use group by option even over 1st query
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp IN (select max(DateTimeStamp) from Products group by ProductID)
Later Linq:
var maxDateTimeStamps = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.Max(x => x.DateTimeStamp)).ToArray();
var results = _context.Products.Where(s=>maxDateTimeStamps.Contains(s.DateTimeStamp));
-- all assuming that max datetime stamps are unique
I've managed to do it with the following which replicates the correlated sub query in the original post (other than using TOP and order by instead of the Max aggregate), though I feel like there must be a more elegant way to do this.
var results = from x
in _context.Products
where x.DateTimeStamp == (from y
in _context.Products
where y.ProductID == x.ProductID
orderby y.DateTimeStamp descending
select y.DateTimeStamp
).FirstOrDefault()
select x;
I prefer to break up these queries into IQueryable parts, do you can debug each "step".
Something like this:
IQueryable<ProductOrmEntity> pocoPerParentMaxUpdateDates =
entityDbContext.Products
//.Where(itm => itm.x == 1)/*if you need where */
.GroupBy(i => i.ProductID)
.Select(g => new ProductOrmEntity
{
ProductID = g.Key,
DateTimeStamp = g.Max(row => row.DateTimeStamp)
});
//// next line for debugging..do not leave in for production code
var temppocoPerParentMaxUpdateDates = pocoPerParentMaxUpdateDates.ToListAsync(CancellationToken.None);
IQueryable<ProductOrmEntity> filteredChildren =
from itm
in entityDbContext.Products
join pocoMaxUpdateDatePerParent in pocoPerParentMaxUpdateDates
on new { a = itm.DateTimeStamp, b = itm.ProductID }
equals
new { a = pocoMaxUpdateDatePerParent.DateTimeStamp, b = pocoMaxUpdateDatePerParent.ProductID }
// where
;
IEnumerable<ProductOrmEntity> hereIsWhatIWantItems = filteredChildren.ToListAsync(CancellationToken.None);
That last step, I am putting in an anonymous object. You can put the data in a "new ProductOrmEntity() { ProductID = pocoMaxUpdateDatePerParent.ProductID }...or you can get the FULL ProductOrmEntity object. Your original code, I don't know if getting all columns of the Product object is what you want, or only some of the columns of the object.
I am having trouble doing multiple counts on a single table in a LINQ query. I am using NHibernate, LINQ to NHibernate and C#.
query is a populated list. I have a table that has a boolean called FullRef. I want to do a LINQ query to give a count of occurances of FullRef = false and FullRef = true on each TrackId. TrackId gets a new row for each time he gets a track.Source == "UserRef".
In the following query I get the correct number count (from the FullRefTrueCount) of FullRef = true, but it gives an unknown wrong number on the FullRefFalseCount.
var query2 = from track in query
where track.Source == "UserRef"
group track by new { TrackId = track.TrackId, FullRef = track.FullRef } into d
select new FullReferrer
{
Customer = d.Key.TrackId,
FullRefFalseCount = d.Where(x => x.FullRef == false).Count(),
FullRefTrueCount = d.Where(x => x.FullRef == true).Count()
};
Anyone have any idea on how to fix it? I am pretty certain the .Where() clause is ignored and the "group by" is screwing me over.
If I could somehow
group track by new { TrackId = track.TrackId, FullRefTrue = track.FullRef, FullRefFalse = !track.FullRef }"
it would work. Is there some way to do this?
you should group by trackId only, if you want results by trackId...
var query2 = query
.Where(m => m.Source == "UserRef")
.GroupBy(m => m.TrackId)
.Select(g => new FullReferrer {
Customer = g.Key,
FullRefFalseCount = g.Count(x => !x.FullRef),
FullRefTrueCount = g.Count(x => x.FullRef)
});
I have the following table:
And the following data:
How can i filter the result, so that i only get the latest row from each omraade_id (sorted descending by timestamp)?
Which in this case would be the rows with id: 1010 and 1005
--
From #lazyberezovsky's answer, i have created the following expression:
dbConnection = new ElecEntities();
var query = from data in dbConnection.Valgdata
orderby data.timestamp descending
group data by data.omraade_id into g
select g.FirstOrDefault();
return query.ToList();
It returns two rows with the ID 3 and 4, which are the first two rows in the database, and also the ones with the lowest timestamp. Any idea why?
var query = dbConnection.Valgdata
.GroupBy(x => x.omraade_id)
.Select(g => g
.OrderByDescending(x => x.timestamp)
.FirstOrDefault());
I have no experience with EF, so I'm unsure if only SQL-esque linq works here. A plain C#-ish:
var query = dbConnection.Valgdata.GroupBy(u => u.omraade_id)
.Select(x => x.FirstOrDefault(y => x.Max(p => p.timestamp) == y.timestamp));
You have put filter on every item. It should be applied on complete query result, not on every item.
Following is updated query.
var query = (from data in dbConnection.Valgdata
orderby data.timestamp descending
group data by data.omraade_id into g
select g).FirstOrDefault();
var query = from v in dbConnection.Valgdata
orderby v.timestamp descending
group v by v.omraade_id into g
select g.First();
This will return only record with max timestamp for each omraade_id.
UPDATE query above works fine to me (at least for MS SQL Linq provider). Also you don't need to do FirstOrDefault - if omraade_id is grouped, then it definitely has at least one row.
var query = from v in dbConnection.Valgdata
group v by v.omraade_id into g
select g.OrderByDesc(x => x.timestamp).First();
This is my solution so far:
var data = dbConnection.Valgdata.Where(x => x.godkendt == false).ToList();
var dataGrouped = data.GroupBy(x => x.omraade_id).ToList();
List<Valgdata> list = new List<Valgdata>();
foreach (var grpdata in dataGrouped)
{
var dataGroup = grpdata.OrderByDescending(x => x.timestamp).ToList();
list.Add(dataGroup.FirstOrDefault());
}
return list;
I dont know if it is the most effective, but it works.
I currently have a linq query to select 5 random rows from my products table. Once I have the collection in my model how do I access a specific row? I'm using First() to get at my first row but Im not sure what I would use if I wanted to get data from the 3rd row in that query.
Thanks!
var Model = (from r in DB.Products select r).OrderBy(r => Guid.NewGuid()).Take(5);
var ProductID1 = Model.First().ProductID;
var ProductID3 = Model.???
You should only run the query once and then iterate over the rows using foreach or just use the index property to select the appropriate product
var Model = (from r in DB.Products select r).OrderBy(r => Guid.NewGuid()).Take(5).ToList();
var ProductID1 = Model[0].ProductID;
var ProductID2 = Model[1].ProductID;
var Model = (from r in DB.Products select r)
.OrderBy(r => Guid.NewGuid())
.Take(5).ToArray();
var ProductID1 = Model.First().ProductID;
var ProductID3 = Model.Skip(2).First() <-- 3rd row
I added ToArray() to the initial query, based on Douglas' comment. Otherwise, the query will re-run every time you pull anything out (since linq's .Take(n) is deferred).
You could simply iterate over your result collection, and take the nth index that you want.
Product product = null;
int index = 0;
foreach (Product p in DB.Products)
{
if (index == 3)
{
product = p;
break;
}
index++;
}
If you process your query into a List, you can access each element directly by index:
var Model = (from r in DB.Products select r)
.OrderBy(r => Guid.NewGuid())
.Take(5)
.ToList(); //Process into a list
var ProductID1 = Model[0].ProductID;
var ProductID3 = Model[3].ProductID;
...
var ProductID100 = Model[100].ProductID;
I'm using LINQ on an IQueryable returned from NHibernate and I need to select the row with the maximum value(s) in a couple of fields.
I've simplified the bit that I'm sticking on. I need to select the one row from my table with the maximum value in one field.
var table = new Table { new Row(id: 1, status: 10), new Row(id: 2, status: 20) }
from u in table
group u by 1 into g
where u.Status == g.Max(u => u.Status)
select u
This is incorrect but I can't work out the right form.
BTW, what I'm actually trying to achieve is approximately this:
var clientAddress = this.repository.GetAll()
.GroupBy(a => a)
.SelectMany(
g =>
g.Where(
a =>
a.Reference == clientReference &&
a.Status == ClientStatus.Live &&
a.AddressReference == g.Max(x => x.AddressReference) &&
a.StartDate == g.Max(x => x.StartDate)))
.SingleOrDefault();
I started with the above lambda but I've been using LINQPad to try and work out the syntax for selecting the Max().
UPDATE
Removing the GroupBy was key.
var all = this.repository.GetAll();
var address = all
.Where(
a =>
a.Reference == clientReference &&
a.Status == ClientStatus.Live &&
a.StartDate == all.Max(x => x.StartDate) &&
a.AddressReference == all.Max(x => x.AddressReference))
.SingleOrDefault();
I don't see why you are grouping here.
Try this:
var maxValue = table.Max(x => x.Status)
var result = table.First(x => x.Status == maxValue);
An alternate approach that would iterate table only once would be this:
var result = table.OrderByDescending(x => x.Status).First();
This is helpful if table is an IEnumerable<T> that is not present in memory or that is calculated on the fly.
You can also do:
(from u in table
orderby u.Status descending
select u).Take(1);
You can group by status and select a row from the largest group:
table.GroupBy(r => r.Status).OrderByDescending(g => g.Key).First().First();
The first First() gets the first group (the set of rows with the largest status); the second First() gets the first row in that group.
If the status is always unqiue, you can replace the second First() with Single().
Addressing the first question, if you need to take several rows grouped by certain criteria with the other column with max value you can do something like this:
var query =
from u1 in table
join u2 in (
from u in table
group u by u.GroupId into g
select new { GroupId = g.Key, MaxStatus = g.Max(x => x.Status) }
) on new { u1.GroupId, u1.Status } equals new { u2.GroupId, Status = u2.MaxStatus}
select u1;
What about using Aggregate?
It's better than
Select max
Select by max value
since it only scans the array once.
var maxRow = table.Aggregate(
(a, b) => a.Status > b.Status ? a : b // whatever you need to compare
);
More one example:
Follow:
qryAux = (from q in qryAux where
q.OrdSeq == (from pp in Sessao.Query<NameTable>() where pp.FieldPk
== q.FieldPk select pp.OrdSeq).Max() select q);
Equals:
select t.* from nametable t where t.OrdSeq =
(select max(t2.OrdSeq) from nametable t2 where t2.FieldPk= t.FieldPk)
Simply in one line:
var result = table.First(x => x.Status == table.Max(y => y.Status));
Notice that there are two action.
the inner action is for finding the max value,
the outer action is for get the desired object.