Can anyone explain why in my program:
linqToSqlDataContext.Scores.Where(x => Predicate(x))
returns no objects at all while:
linqToSqlDataContext.Scores.ToList().Where(x => x.Predicate(x))
returns exactly the right objects?
Scores is a System.Data.Linq.Table<Score>
Linq uses (by default) a deferred execution model.
Your first code is just a query. It is not executed. Whenever you iterate through it via (foreach, for, .ToList(), .Count(), .Any() etc.) that's when it will materialized.
Your second code calls ToList(), so your query is executed, but your Where does not any affect.
The correct way would be: linqToSqlDataContext.Scores.Where(Predicate).ToList()
Related
I have a simple list of integers that represent days of week. I am trying to check if Date property of my entity is in the selected days of week. But if I try to pass it in query that targets database like this:
query.Where(e => selectedDaysOfWeek.Contains((int)e.Date.DayOfWeek));
I got the exception:
The LINQ expression ... could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
If I on the other hand, first execute query by calling ToList() (for example) and then add the same where condition on resulting list, it works:
var items = query.ToList();
items = items.Where(e => selectedDaysOfWeek.Contains((int)e.Date.DayOfWeek)).ToList();
Although in my case this is acceptable, I would like to fetch less items from the database. Is there a way to check DayOfWeek when querying db as was my initial intent?
You are accessing the DayOfWeek property from a DateTime reference in the query.
Entity Framework "doesn't know" how to translate that to SQL thus in the first piece of code you getting an exception.
And in the second piece it is working after you have fetch all of the data from database at the .ToList() call, and the .Where filtering is happening in the memory.
If you wish to implement that logic on the database side, you will have to write your own SQL statement.
Let's say I have 100 000 objects of type Person which have a date property with their birthday in them.
I place all the objects in a List<Person> (or an array) and also in a dictionary where I have the date as the key and every value is a array/list with persons that share the same birthday.
Then I do this:
DateTime date = new DateTime(); // Just some date
var personsFromList = personList.Where(person => person.Birthday == date);
var personsFromDictionary = dictionary[date];
If I run that 1000 times the Linq .Where lookup will be significantly faster in the end than the dictionary. Why is that? It does not seem logical to me. Is the results being cached (and used again) behind the scenes?
From Introduction to LINQ Queries (C#) (The Query)
... the important point is that in LINQ, the query variable itself takes no action and returns no data. It just stores the information that is required to produce the results when the query is executed at some later point.
This is known as deferred execution. (later down the same page):
As stated previously, the query variable itself only stores the query commands. The actual execution of the query is deferred until you iterate over the query variable in a foreach statement. This concept is referred to as deferred execution...
Some linq methods must iterate the IEnumerable and therefor will execute immediately - methods like Count, Max, Average etc' - all the aggregation methods.
Another way to force immediate execution is to use ToArray or ToList, which will execute the query and store it's results in an array or list.
I'm looking for a clean way to write this Linq query.
Basically I have a collection of objects with id's, then using nhibernate and Linq, I need to check if the nhibernate entity has a subclass collection where all id's in object collection exist in the nhibernate subclass collection.
If there was just one item this would work:
var objectImCheckingAgainst = ... //irrelevant
where Obj.SubObj.Any(a => a.id == objectImCheckingAgainst.Id)
Now I want to instead somehow pass a list of objectImCheckingAgainst and return true only if the Obj.SubObj collection contains all items in list of objectImCheckingAgainst based on Id.
I like to use GroupJoin for this.
return objectImCheckingAgainst.GroupJoin(Obj.SubObj,
a => a.Id,
b => b.id,
(a, b) => b.Any())
.All(c => c);
I believe this query should be more or less self-explanatory, but essentially, this joins the two collections using their respective ids as keys, then groups those results. Then for each of those groupings, it determines whether any matches exist. Finally, it ensures that all groupings had matches.
A useful alternative that I sometimes use is .Count() == 1 instead of the .Any(). Obviously, the difference there is whether you want to support multiple elements with the same id matching. From your description, it sounded like that either doesn't matter or is enforced by another means. But that's an easy swap, either way.
An important concept in GroupJoin that I know is relevant, but may or may not be obvious, is that the first enumerable (which is to say, the first argument to the extension method, or objectImCheckingAgainst in this example) will have all its elements included in the result, but the second one may or may not. It's not like Join, where the ordering is irrelevant. If you're used to SQL, these are the elementary beginnings of a LEFT OUTER JOIN.
Another way you could accomplish this, somewhat more simply but not as efficiently, would be to simply nest the queries:
return objectImCheckingAgainst.All(c => Obj.SubObj.Any(x => x.id == c.Id));
I say this because it's pretty similar to the example you provided.
I don't have any experience with NHibernate, but I know many ORMs (I believe EF included) will map this to SQL, so efficiency may or may not be a concern. But in general, I like to write LINQ as close to par as I can so it works as well in memory as against a database, so I'd go with the first one I mentioned.
I'm not well versed in LINQ-to-NHibernate but when using LINQ against any SQL backen it's always important to keep an eye on the generated SQL. I think this where clause...
where Obj.SubObj.All(a => idList.Contains(a.id))
...will produce the best SQL (having an IN statement).
idList is a list of Ids extracted from the list of objectImCheckingAgainst objects.
Below I have two queries that are working as expected. How does CodeIgniter know to not add 2 where clauses to the second query? Does it reset the query statements after $this->db->update?
//Make sure customers don't belong to tier anymore
$this->db->where('tier_id', $tier_id);
$this->db->update('customers', array('tier_id' => NULL));
$this->db->where('id', $tier_id);
return $this->db->delete('price_tiers');
If you look in the System/database/db_active_rec.php core file, you can see (for example) the update() function
The first thing it does is calls:
// Combine any cached components with the current statements
$this->_merge_cache();
This is how the CRUD statements collect any "partial" where, etc clauses.
The second to last thing it does is calls:
_reset_write();
This resets them all to empty. Then it calls the query() to send off the statement
I'm building a poll widget. I've 2 tables, call them Polls and PollsCompleted. I need to do a linq query to get all the Polls that do not exist for a given user in PollsCompleted.
I have the following sets:
For Polls
Where Active == True
For PollsCompleted
Where UserId == ThisUserId
Where PollId = Polls.Id
Now I need to get all Polls that do not exist in PollsCompleted. I need an example for this using either a single or multiple queries. I've tried to break it down into 2 queries.
Basically, I've 2 IQueryables of type T and T1. I want to take all T's where T.ID does not exist in T1.ParentId.
T.Where(x => ! T1.Select(y => y.ParentID).Contains(x.ID))
In Linq you often work from the bottom up. Here we first get a collection of all the parentIDs in T1 -- the T1.Select(...) part. Then we create a where clause that selects all of the Ts whose IDs are not contained in that set.
Note that the result is a query. To materialize it, use ToList() or similar on the statement above.
Use Except. That will work in this case.
For your reference Enumerable.Except Method