How do I access specific rows in my LINQ model? - c#

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;

Related

How can I get build a query based on array of IDs using EF

I'm trying to build a query selecting all records containing IDs which are stored in the list using that code:
var assistsIds = _context.Assistances.Where(c => c.IdUser == user.IdUser)
.Select(x => x.Owner.IdOwner).ToList();
Then I'm going through all the list elements to get a query:
var query = _context.Accounts.Where(_ => _.IsDeleted != 1);
foreach(var assist in assistsIds)
{
query = query.Where(_ => _.IdOwner == assist);
}
The result is that I'm getting something like this:
SELECT * FROM Accounts WHERE IdOwner = 1 AND IdOwner = 2 ...etc
Instead of:
SELECT * FROM Accounts WHERE IdOwner = 1 OR IdOwner = 2 ... etc
Is there a way to apply OR operator, or maybe there is some other way to achieve that?
You could use Contains:
var query = _context.Accounts
.Where(_ => _.IsDeleted != 1 && assistsIds.Contains(_.IdOwner));
This will return all records which match an Id in the assistsIds list.

C# linq to sql have no translation for string.join in order by

I have a problem where I am string.join on a subselect which works but when I order by that column I get the error that it does not have a translation
It works is I use ToList before OrderBy but I need to still have it as a queryable
var result = v.Select(x => new v_class() {
IDX = x.idx,
ID = x.id,
unit = string.Join(",", (from g in crm.g
join gv in crm.gv on g.idx equals gv.gFkey
where (gv.vfkey ?? 0) == x.idx
select g.desc
).ToArray()),
}).ToList();
I would like to know if I can orderby unit without using to list

C# query only when textbox is edited

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

Select by ID from a list

I have a table of products and a table of categories, I can select by the ID of the Category like this:
var result = db.tblProducts.Where(p => p.tblCategories.Any(c => c.ID == 1));
However, I want to be able to select based on a list of Categories:
var catIDs = new List<int>() { 1,2,3 };
var results = db.tblProducts.Where(r => r.tblCategories.Any(t => catIDs.Contains(t.ID)));
I get the following error:
LINQ to Entities does not recognize the method 'Boolean Contains(Int32)' method, and this method cannot be translated into a store expression.
Presumably because I am using Contains to compare entities to local variables. Is there a way to do this?
Try create Expression from values. F.e.:
static Expression MakeOrExpression<T, P>(Expression<Func<T, P>> whatToCompare, IEnumerable<P> values)
{
Expression result = Expression.Constant(true);
foreach (var value in values)
{
var comparison = Expression.Equal(whatToCompare, Expression.Constant(value));
result = Expression.Or(result, comparison);
}
return result;
}
How to use:
var results = db.tblProducts.Where(r => r.tblCategories.Any(MakeOrExpression(t => t.ID, catIDs)));
The method MakeOrExpression will create an expression t.ID == 1 || t.ID == 2 || t.ID == 3 for list { 1, 2, 3 } dynamically, and then EF will translate it to SQL condition.
Maybe you can use this:
var catIDs = new List<int>() { 1,2,3 };
var results = db.tblCategories
.Where(t => catIDs.Contains(t.ID))
.SelectMany(t => t.tblProducts)
.Distinct();
Try this:
var query=from p in db.tblProducts
from c in p.tblCategories
where catIDs.Contains(c.ID)
select p;
If at least one of the categories of the product is in the catIDs list, then the product will be seleted.
Another option could be start by the categories (I'm guessing you have a many to many relationship between Product and Category and you have a collections of products in your Category entity):
var query=db.tblCategories.Where(c => catIDs.Contains(c.ID)).SelectMany(c=>c.tblProducts).Distinct();
Try this code :
var catIDs = new List<int>() { 1,2,3 };
var results = db.tblProducts.Where(r => catIDs.Any(c => c == r.tblCategories.Id));

How to filter entity framework result with multiple columns using a lambda expression

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.

Categories