Extension Method to assign value to a field in every item? - c#

I could have sworn that there was an extension method already built for the Queryable class that I just can't find, but maybe I'm thinking of something different.
I'm looking for something along the lines of:
IQueryable<Entity> en = from e in IDB.Entities select e;
en.ForEach(foo => foo.Status = "Complete");
en.Foreach() would essential perform:
foreach(Entity foo in en){
foo.Status = "Complete";
}
Is this already written? If not, is it possible to write said Extension Method, preferably allowing for any LINQ Table and any Field on that table. Where is a good place to start?

There's nothing in the base class library. Many, many developers have this in their own common library, however, and we have it in MoreLINQ too.
It sort of goes against the spirit of LINQ, in that it's all about side-effects - but it's really useful, so I think pragmatism trumps dogma here.
One thing to note - there's really no point in using a query expression in your example. (It's not entirely redundant, but if you're not exposing the value it doesn't matter.) The select isn't doing anything useful here. You can just do:
IDB.Entities.ForEach(foo => foo.status = "Complete");
Even if you want to do a single "where" or "select" I'd normally use dot notation:
IDB.Entities.Where(foo => foo.Name == "fred")
.ForEach(foo => foo.status = "Complete");
Only use query expressions where they actually make the code simpler :)

public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action)
{
foreach (var item in sequence)
{
action(item);
}
}

There is a foreach on a List<>. Roughly something along these lines:
IQueryable<Entity> en = from e in IDB.Entities select e;
en.ToList().ForEach(foo => foo.status = "Complete");

Related

What is the "=>" sign in LINQ queries?

It's amazing how little information there is on this. I found tons of tutorials explaining LINQ, but they don't explain this particular operator:
var Results = UserFavoritesContext.UserFavorites.Select(color => color.FavoriteColor);
"x => x.y"
Can someone please explain how this works? I get the general syntax and am able to use it to make queries, but it's like doing something without knowing what you're doing.
Suppose you have a list of people, and you want to iterate over them. You would write something like:
foreach(var person in people)
{
//do something to person
}
Note how you yourself chose the name person. It could've been any word, but you basically said "process every single item of the list as my person variable".
Now look at this LINQ query:
filteredPeopleList = people.Where(person => person.Name == "John");
Again, you basically chose person as a placeholder name for every object in the original list (one at a time). The above Linq query is equivalent to
foreach(var person in people)
{
if(person.Name == "John")
{
filteredPeopleList.Add(person);
}
}
To me, x => x.y is basically saying "for every variable we process (let's call it x), please perform the following operation on it (x.y, get the y property)"
I hope that explains it.
Edit
As a commenter who now deleted his comment mentioned, this isn't exclusively used in LINQ. A lambda expression doesn't have to iterate over an IEnumerable, it can be used to process a single item.
However, LINQ is by far the most common place to encounter lambdas, and I find their use very similar to the foreach loop, which is why I picked this example.
The => operator is used in lambda expressions.
The best way to think of this is a type of syntax for writing a function, where the left side of the operator is the parameters for the function and the right side is the body of the function e.g. this is a valid use of a lambda expression where its being used like a function:
Func<int, int> incrementFunction = i => i + 1;
int incrementedNumber = incrementFunction(1);
The name i in this case is an arbitrary variable name e.g. just like you would name a functions input parameter. Notice I didnt need to declare the input parameters type because the compiler will infer it. Also notice I dont need to include the "return" keyword or enclose the function body in a code block. It doesn't necessarily need any parameters either e.g.
Action myAction = () => Console.Write("something");
myAction();
When you use it in a linq expression, think of it as though the lambda function is being called on every element in the collection (which I believe is exactly what happens with linq to objects).
It's the syntax of a Lambda expression. If it helps you to remember... in a nutshell, the argument to pass (the parameter) is on the left of the => and the method(s) that use it are on the right hand side of it.
I hope this short summary explains it enough :)
That is a lambda expression, and it can be used as a selector from an object
You can conditionally select (or another operation orderby, count, etc) when the expression is true. For example:
Say you had a list of people and their details: ID, Name, City and Profession.
You could select a single person by using lambda to search for their specific ID:
public Person GetByID(int id)
{
Person selectedPerson = people.SingleOrDefault(person => person.ID == id);
return selectedPerson;
}
Same could be applied for a select on a city, this would be:
public List<Person> GetByCity(string city)
{
List<Person> selectedPeople = people.where(person => person.City == city);
return selectedPeople;
}
The lamda expression is where you place your operation variable, so in these cases the condition upon which you select the data. You can use it as a orderby variable much in the same way, in the next example I use two lamdas to perform two seperate functions
public List<Person> GetByCity(string city)
{
List<Person> selectedPeople = people.where(person => person.city == city)
.OrderByDescending(person => person.Name);
return selectedpeople;
}
I hope this helps at all
x => x.y is Lambda Expression introduced with C# 3.0. The general syntax is
parameter => executioncode
The Lambda Expression has 3 parts:
x on left hand side is the parameter.This can be a variable,delegate or an anonymous function.
=> read as "goes to", which acts as separator
x.y is an Expression to be evaluated.
For example, the lambda expression x => x * x specifies a parameter that’s named x and returns the value of x squared (source: MSDN).
Hope this would help you.
They're called Lamda expression:
https://msdn.microsoft.com/en-us/library/bb397687.aspx
var Results = UserFavoritesContext.UserFavorites.Select(color => color.FavoriteColor);
is similar to:
List<UserFavorite> Results = new List<UserFavorite>();
foreach(var item in UserFavorites)
{
Results.Add(item.FavoriteColor);
}
This is not specific to Linq.
It is the way you write a lambda expression.
The arrow => is the delimiter between your lambda parameters and its body.

How to join for the purpose of doing an action, but not for selecting anything

listOne
.Join(listTwo,
x => x.key,
y => y.key,
(x, y) =>
{
y.SomeProperty = x.SomeProperty;
return 0;
});
I need to copy a property from one list to another where the items match, and I can easily join the two lists as shown in the example above but I think another developer coming after me would think "what the heck?" because I'm not really using it the way it was intended. Does linq provide a more appropriate way to accomplish the same thing?
Or if I want my code to be readable, should I just stick with a loop instead of trying to one line it?
I personally prefer a more functional approach of returning a new list, but if you are set on this mutating the other list, then you could do the following which at least implies side effects (via the ForEach):
val keyMatchedList= from x in listOne
join y in listTwo on x.key == y.key
select new {x.key, y.SomeProperty};
listTwo.ForEach(
x=> x.SomeProperty = keyMatchedList.First(y=>y.Key == x.Key).SomeProperty);
But, do keep in mind that LINQ is an attempt to be side-effect free...
Note that ParallelEnumerable<T> and List<T> provide methods to perform an Action<T> against each result, but these are specific enumerable types that may not be appropriate for the situation (side note: consider parallel for this particular situation via .AsParallel())
However, the default implementation is to perform a loop rather than using the Func passed to a Join or Select as, as you said, it can be misleading and necessitates an unused return value. To phrase this as Justin Pihony did in his answer, this violates principles of being "side effect free."
This is the exact siutuation in which you should consider using an anonymous type, like so
foreach(var pair in listOne
.Join(listTwo,
x => x.key,
y => y.key,
(x, y) => new { first = x, second = y}))
{
pair.first.SomeProperty = pair.second.SomeProperty;
}
More verbose, but avoids misusing methods in a way that might make someone have to do a double take down the line.
Also note that while it's not done for you in Linq, you can write your own ForEach
public static void ForEach<T>(this IEnumerable<T> source, Action<T> act)
{
foreach(T t in source) act(t);
}
Using this same approach, it's also advisable to occasionally write your own extension methods for IEnumerables (I'm particularly fond of making an UpdateCollecitonTo to update items in an ObservableCollection without just replacing the reference...) For this, it may be helpful to browse the source coe for Join on the Reference Source

Using a params array of linq Expressions

In EF, when you want to include a navigation property in the result of a query, you use Include(). Since some queries require calling this more than once, I tried to create a generic wrapper around this concept:
public IQueryable<T> FindAll<P>(params Expression<Func<T, P>>[] predicates) where P : class {
var entities = AllEntities();
foreach (var p in predicates) entities = entities.Include(p);
return entities;
}
And call it as such:
var customers = FindAll(q => q.Orders, q => q.Invoices, q => q.Contacts);
Questions:
The function compiles, but when I call it: "The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly." What am I doing wrong?
If I get it to work, can I call Include() the first time: var customers = FindAll(q => q.Orders, q => q.Invoices); and then again later in a separate step: customers = customers.Include(p => p.Invoices); or will that result in poor performance such that I should do the includes in one go?
EDIT:
JonSkeet's answer is correct, of course, and yet there is this solution which seems to do what I want. Not sure why it works however. Is it because of the Aggregate() function?
Fundamentally, I think you've got a problem - assuming that q.Orders, q.Invoices and q.Contacts return different types, you can't express what you want to happen. You probably want something like:
entities.Include<Parent, Order>(p => p.Order);
entities.Include<Parent, Invoice>(p => p.Invoices);
entities.Include<Parent, Contact>(p => p.Contacts);
... so you want a different value for P for each predicate. But you're calling a single method, providing a single type argument for P.
It's not clear that this is really giving you much benefit anyway... couldn't you just write:
var customers = AllEntities().Include(q => q.Orders)
.Include(q => q.Invoices)
.Include(q => q.Contacts);
I'd say that's clearer and it gets round the "multiple type parameters" problem.

Entity Framework - Include in sub query? - Part 2

I'm not sure if this is the right thing to do, I'm sure someone will tell me if it's not.
I asked a question (Entity Framework - Include in sub query?) earlier this evening, which was answered very well and has solved my problem. But, I think there could be a better way, so I'm going to re-ask the question, but slightly differently.
Let's say I have 3 tables:
Restaurant 1.....M MenuCategory 1.....M MenuItem
I have a L2E query that looks something like this:
Restaurant = context.Restaurant
.Include(r => r.MenuCategory)
.FirstOrDefault(r => r.RestaurantId == resaurantId);
Which works to some extent, but it only pre-loads the menu categories.
What I really want to be able to do is something like:
Restaurant = context.Restaurant
.Include(r => r.MenuCategory)
.Include(r => r.MenuCategory.MenuItems)
.FirstOrDefault(r => r.RestaurantId == resaurantId);
But clearly this isn't available as r.MenuCategory is an enumerable
...the work around is to use the standard notation:
context.Restaurant.Include("MenuCategory.MenuItems");
...but this is not strongly typed. This question is about finding a strongly typed answer
This is the current extension method:
public static ObjectQuery<T> Include<T>(this ObjectQuery<T> query, Expression<Func<T, object>> path)
{
// Retrieve member path:
List<PropertyInfo> members = new List<PropertyInfo>();
EntityFrameworkHelper.CollectRelationalMembers(path, members);
// Build string path:
StringBuilder sb = new StringBuilder();
string separator = "";
foreach (MemberInfo member in members)
{
sb.Append(separator);
sb.Append(member.Name);
separator = ".";
}
// Apply Include:
return query.Include(sb.ToString());
}
How could this be adapted to allow a strongly typed form of:
context.Restaurant.Include("MenuCategory.MenuItems");
I have a Tip that allows exactly this: Tip 28 - How to implement an eager load strategy
Uses a nifty trick I think.
Alex
A far less elegant but much quicker to implement method might be as follows:
var list = dataContext.CartLists.Include(typeof(CartListItem).Name).Where(l => l.CustNum == customerNumber && l.ListTypeID == (int)ShoppingCartType.WebShoppingCart).Single();
. . . but you'll need to ensure that you haven't had the EF model generator pluralize your entity set names. This is kind of an ugly solution, but it should give you compile errors once you update your EF model if your table names ever change, as ours just did, and you won't have to actually execute your code to try to find places where your strings don't match actual entities.

Lambda Expression

Can I simplify this statement with a lambda expression?
var project = from a in accounts
from ap in a.AccountProjects
where ap.AccountProjectID == accountProjectId
select ap;
var project = accounts.SelectMany(a => a.AccountProjects)
.Where(x => x.AccountProjectID == accountProjectId);
Whether this is actually simpler is a matter of taste.
Honestly, it looks pretty clear to me. I think that a lambda in this case may be less readable, i.e., something like Brandon posted below.
(Stolen from Brandon's post)
var project = accounts.Select(a => a.AccountProjects)
.Where(x => x.AccountProjectID == accountProjectId);
As far as readability is concerned, I think that a couple of loops is preferable to the lambda solution, and I think that your solution is preferable to the loops.
I agree with Ed Swangren. This looks concise and readable enough.
Actually the answer to your question depends on 3 things:
What you want to achieve - better readability? better performance? etc.
The type of 'accounts'
How the resulting collection is going to be used.
If you want better performance, and in case 'accounts' is a List, and the resulting collection will be iterated or passed to another method for iterating soon enough after these lines of code, I would do something like that:
List<Account> filteredAccounts = new List<Account>();
accounts.ForEach(a => { if (a.AccountProjectID == accountProjectId) filteredAccounts.Add(a); });
Surely it's less readable then your LINQ statement, but I would use these 2 lines rather than accounts.Select.......
And surely it's much better optimized for performance, which is always important I believe.
accounts
.SelectMany (
a => AccountProjects,
(a, ct) =>
new
{
a = a,
ap = ap
}
)
.Where (t => (t.ap.AccountProjectID == t.a.accountProjectId))
.Select (t => t.ap)

Categories