I'm using this piece of code to get a desired list of rows from a table:
_userObjectSet = EntityFrameWorkContext.CreateObjectSet<User>();
List<int> selectedUserIDs = Method(); //Returns a specific set of int user IDs...
var results = _userObjectSet.Where(c => selectedUserIDs.Contains(c.ID)).ToList();
This does work as 'results' will only contain records whose ID field matches an element in the selectedUserIDs list.
The problem is that, if I look at Windows Task Manager, LINQ seems to load ALL of the table's row THEN filter them out. There is a huge number of rows in this table, and pretty soon the process weights over 1GB, which I don't really like.
I can also tell that it's doing this because of the time it takes to complete.
Is there any way to tell LINQ to generate a query that would look like:
SELECT * FROM Users WHERE ID IN (34,55,66,77, etc.)
which would only return the exact rows I'm looking for and use less memory ?
Thanks!
Try join.. I think u can find a difference...
List<int> selectedUserIDs = Method(); //Returns a specific set of int user IDs...
var results = (from u in _userObjectSet
join id in selectedUserIDs on u.Id equals id
select u);
You're going to need something like LinqKit for this.Specifically, have a look at the PredicateBuilder that comes with the kit, as I think you need that to solve your problem.
Related
I have a database table called Customers. I run the following sql to get information about the first and second customer:
select FirstCustomerName, SecondCustomerName,
* from Customers where FirstCustomerName = SecondCustomerName
When I run this in sql it gives me what I want, so that one is ok. The problem is when I want to do the same thing in Linq in C#.
To achive the same thing with Linq I have tried this(still "doesn't work"):
InfoAboutBothCustomers = c.customers.FirstCustomerName == c.customers.SecondCustomerName.ToString()
Note: InfoAboutBothCustomers is an int in my ViewModel
So my question basically is how do the same thing in LINQ?
I am not sure what value you want in InfoAboutBothCustomers. Your SQL statement returns two values and you are saying that you want an int. c.customers.FirstCustomerName == c.customers.SecondCustomerName.ToString() will return a boolean to say if they are equal or not.
If you want the id or ids that match you criteria, try something like:
var ids = from cust in customers
where cust.FirstCustomerName == cust.SecondCustomerName
select cust.Id;
Alternatively you can use what is mentioned in the other answers, which is cleaner, but just be aware that FirstOrDefault will return the row of data. You can then specify the column that you want by doing something like this FirstOrDefault().Id;
Without sample it is difficult to provide any solution. But you can try this
InfoAboutBothCustomers = c.customers.Where(x=>x.FirstCustomerName == x.SecondCustomerName).FirstOrDefault()
In case of error /issue please share the sample.
Use .Where operation
InfoAboutBothCustomers = c.customers.Where(c => c.FirstCustomerName == c.SecondCustomerName).FirstOrDefault();
Ok, I didn't put the title right.
I'll explain.
I've got a table with some exercise results. Mostly you've got a UserID, an ExerciseID, the Result and when was the result taken. The table is accessed using EF and Linq.
I want to get all the results for a given ExerciseID and take only the last one of each User. Using LINQ of course.
How can this be accomplished?
My Code (that takes all results) is as follows:
from e in models.ExerciseUserResults
where e.ExerciseID == ExerciseId
select e
This snippet will get all results for all users.
EDIT: an example
Let's say I've got this table
{<UserID>,<Result>} - {1,100},{1,200},{2,150},{2,250} - using JSON notation and without all the fields.
If the query is right - I would get [{1, 200},{2,250}]
Thanks
The fact that you want one per user makes it pretty clear that you want to group the query by user. From there, you can project each group into just one item:
var query = from e in models.ExerciseUserResults
where e.ExerciseID == ExerciseId
group e by UserID into usersExercises
select usersExercises.Last();
In SQL, it'd be done as such:
SELECT * FROM Student
WHERE SchoolId IN
(SELECT id FROM School WHERE Name LIKE '%elementary%')
How do I implement this with LINQ? I've tried the following:
var list = context.Students.Where(x => context.Schools.Where(r => r.Name.Contains("elementary").Select(r => r.Id).Contains(x.SchoolId))
but it's not giving me what I want, unfortunately...
I know it's possible to retrieve all the Ids from the School table first, but I think it'd take a heavy toll on the performance. Preferably I'd like LINQ to SQL to handle everything; I can't do this using vanilla SQL because I need stuff to be dynamic and currently LINQ is the best solution for me.
The code above is all for illustration purposes; what I'm doing is a tad different (but more or less the same). I really do need some help on this; if you need any more information just feel free to ask.
EDIT: My bad, I missed out a field. It works, but the results didn't show up because I was missing that field... So sorry...
Try this:
var result = from st in context.Student
from sc in context.Schools
where sc.Name.Contains("elementary") && sc.SchoolId == st.SchoolId
select st;
I am a bit hazy on the syntax, pardon me. But this should point you to the right direction.
Something like this should work. The first use of Contains is on a string object to see if the string contains the substring "elementary". The second use of Contains is on a list and checks to see if the first result list contains SchoolId.
var sublist = from s in context.Schools
where s.Name.Contains("elementary")
select id;
var list = from s in context.Students
where sublist.Contains(s.SchoolId)
select s;
I'm trying to get a list of rows in DataTableA where the value in Column 1 is not in Column1 of DataTableB.
I'm using the following LinQ query
//Not in Database
var query = from i in dtImport.AsEnumerable()
where !dtProducts.AsEnumerable().Any(p => p[colP] == i[colI])
select i;
Such that I want a list of products in the import table that aren't already in the products table.
Which seems to skip past the line quickly when I'm debugging but then when I call anything relating to that query such as int rows = query.Count<DataRow>(); or DataTable dtResult = query.CopyToDataTable(); it seems to take a long time so I just stop the program.
So, What am I doing wrong?
Linq uses deferred execution. The query is executed when it is used (not when declared)
For better performance you can use a HashSet like the following;
var set = new HashSet<int>(dtProducts.AsEnumerable().Select(p => p.colP));
var result = dtImport.AsEnumerable().Where(i => !set.Contains(i[colI])).ToList();
The slowdown is expected: the query does not get evaluated until you enumerate the results, so you skip this line in the debugger pretty quickly: all it does is preparing to query the data source; the querying is done on enumerating the results.
As far as I can tell without profiling your code, the issue is probably related to a big out-of-db select that happens when you convert dtProducts and dtImport to IEnumerable: essentially, you bring the data from both tables into memory before doing your select. If your tables are of considerable size, this is probably where most of the time goes. But again, the only sure way to tell is profiling.
Your query is slow, because it has to enumerate the products for each record in dtImport. Put the products into a dictionary first, to speed up your query.
var prod = dtProducts.AsEnumerable().ToDictionary(p => p[colP]);
var query = from imp in dtImport.AsEnumerable()
where !prod.ContainsKey(imp[colI])
select imp;
I want to return a single row from the users table using domain account id as my primary and unique key
However when i use singleordefault and see its sql translation it performs entire select * from Users
my query is..
var user = base.SingleorDefault(t=>t.domainaccountid)
i want this to return just one row!
What is base ? Is it possible that you've coerced it to IEnumerable<T> at some point, rather than IQueryable<T>? that would cause this. Note that database composition is only possible when using IQueryable<T>, so if any of your methods have returned something other than this, composition will end.
You could try Where along with FirstOrDefault:
var user = base.Where(t => t.domainaccountid == 123).FirstOrDefault();
Try
var user = base.SingleorDefault(t=>t.domainaccountid==123);
SingleOrDefault looks for unique entries, it should be doing:
SELECT TOP 2 * FROM TABLE
It does this so that if it finds 2 results it will throw an exception as it is not unique.
If you don't care about finding it as a unique object, as you have other measure in place to prevent duplicates; or just don't care you can use FirstOrDefault in the following way:
array.FirstOrDefault(x => x.id == someOtherId);
This will perform the following:
SELECT TOP 1 * FROM TABLE
This will get your results quicker, especially in larger tables, because it will return as soon as the first result is found.