A LINQ question: map query expression to c# code - c#

How do I translate the following query expression to corresponding C# code? Thanks.
var list1 = (from ol in orderedList
from er in ol.Er
from rd in er.Rd
where rd.ftr != ""
select ol).ToList<CRInfo>();

It would translate to something like this:
var list1 = orderedList.SelectMany(ol => ol.Er, (ol, er) => new { ol, er })
.SelectMany(z => z.er.Rd, (z, rd) => new { z, rd })
.Where(z2 => z2.rd.frt != "")
.Select(z2 => z2.z.ol)
.ToList<CRInfo>();
The "z" and "z2" bits are transparent identifiers, used by the C# compiler to propagate multiple range variables through the query.
You may want to download LINQPad, which I believe lets you translate query expressions like this very easily.

Well, aside from the obvious fact that your code is already C# code...
I assume you want to obtain the actual Enumerable method calls? If so, you could just compile it and throw it into Reflector.

Related

LINQ Intersect on inner collection

I have a list of Stores (of type ObservableCollection<Store>) and the Store object has a property called Features ( of type List<Feature> ). and the Feature object has a Name property (of type string).
To recap, a list of Stores that has a list of Features
I have a second collection of DesiredFeatures (of type List<string> ).
I need to use LINQ to give me results of only the stores that have all the DesiredFeatures. So far, I've only been able to come up with a query that gives me an OR result instead of AND.
Here's what that looks like:
var q = Stores.Where(s=> s.Features.Any(f=> DesiredFeatures.Contains(f.name)));
I know Intersect can help, and here's how I've used it:
var q = Stores.Where(s => s.Features.Intersect<Feature>(DesiredFeatures));
This is where I'm stuck, Intersect wants a Feature object, what I need to intersect is on the Feature.Name.
The goal is to end up with an ObservableCollection where each Store has all of the DesiredFeatures.
Thank you!
You've almost done what you need. A small refine would be to swap DesiredFeatures and s.Features.
var q = Stores.Where(s => DesiredFeatures.All(df => s.Features.Contains(df)));
It means take only those stores where desired features are all contained in features of the store.
I need to use LINQ to give me results of only the stores that have all the DesiredFeatures.
In other words, each desired feature must have a matching store feature.
I don't see how Intersect can help in this case. The direct translation of the above criteria to LINQ is like this:
var q = Stores.Where(s =>
DesiredFeatures.All(df => s.Features.Any(f => f.Name == df))
);
A more efficient way could be to use a GroupJoin for performing the match:
var q = Stores.Where(s =>
DesiredFeatures.GroupJoin(s.Features,
df => df, sf => sf.Name, (df, sf) => sf.Any()
).All(match => match)
);
or Except to check for unmatched items:
var q = Stores.Where(s =>
!DesiredFeatures.Except(s.Features.Select(sf => sf.Name)).Any()
);
Going on your intersect idea, the only way I thought of making this work was by using Select to get the Store.Features (List<Feature>) as a list of Feature Names (List<string>) and intersect that with DesiredFeatures.
Updated Answer:
var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures).Any());
or
var q = Stores.Where(s => DesiredFeatures.Intersect(s.Features.Select(f => f.Name)).Any());
Old Answer (if DesiredFeatures is a List<Feature>):
var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures.Select(df => df.Name)).Any());
Two things you want your code to perform.
var q = Stores.Where(s=> s.Features.All(f=> DesiredFeatures.Contains(f.name)) &&
s.Features.Count() == DesiredFeatures.Count()); // Incude Distinct in the comparison if Features list is not unique
Ensure that every Feature is DesiredFeature
Store contains all Desired features.
Code above assumes uniqueness in Features collection as well as DesiredFeatures, modify code as stated in comment line if this is not right

two foreach in linq?

...I've tried something but I got the "Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator." exception.
I'm talking about this:
Query = Query.Where(t => this.SysTextBox.Text.CSL2Array().All(ss => t.SysName.Contains(ss)));
I'm kind of new at this, but I kept trying to make it work. Thank you in advance!
You should be able to do the query after ToList:
Query = Query.ToList<TagsDeleted>()
.Where(t => this.SubSystemTextBox.Text.CSL2Array().All(ss => t.SubsystemName.Contains(ss)))
.AsQueryable<TagsDeleted>();
But that is not easy to read, I would refactor to the following to make it clear that "I create a list, and want to remove some items":
var words = this.SubSystemTextBox.Text.CSL2Array();
var list = Query.ToList<TagsDeleted>();
list.RemoveAll(t => !words.All(word => t.SubsystemName.Contains(word)));
Query = list.AsQueryable<TagsDeleted>();
var arr = this.SubSystemTextBox.Text.CSL2Array();
var notContained = Query.Where(td=>arr.Any(ss => !td.SubsystemName.Contains(ss)));
Query = Query.Except(notContained);
You can figure this out how to make it in one line, this was just to be clear.

equivalent lambda expression for this query expression

As per post Select element with given attribute using linq to xml what will be the equivalent lambda expression.
The below solution works fine
var artistsAndImage = from a in feed.Descendants("artist")
from img in a.Elements("image")
where img.Attribute("size").Value == "big"
select new { Name = a.Element("Name").Value
, Image = img.Value};
I tried the lambda expression but it's not working :-(
can somebody suggest the equivalent lambda expression.
Sure:
var artistsAndImage = feed.Descendants("artist")
.SelectMany(a => a.Elements("image"),
(a, img) => new { a, img })
.Where(z => z.img.Attribute("size").Value == "big")
.Select(z => new { Name = z.a.Element("Name").Value,
Image = z.img.Value });
(Untested, but I think it should work.)
The tricky bit here is that the second from clause calls SelectMany and introduces a transparent identifier which I've made somewhat less transparent by calling it z.
Any particular reason you want to avoid query expression syntax here though? It's simpler in this example - I just use whichever is simpler for the query I'm writing.

C#, Linq to Sql: Why can I not use an expression to filter SubEntities?

I have made myself an ExpressionBuilder class that helps me put together expressions that can be used as a predicate when doing Linq to Sql queries. It has worked great. However, I just discovered Expressions can only be used to filter on Tables, and not on EntitySets??Why on earth is this the case?
For example if I have Company and an Employee with a Salary. I could create these two expressions:
Expression<Func<Company, bool>> cp = x => x.Name.StartsWith("Micro");
Expression<Func<Employee, bool>> ep = x => x.Name.StartsWith("John");
I would then expect to be able to do the following, however it only partially works:
var companies = dataContext.Companies
.Where(cp) // Goes fine
.Select(x => new
{
x.Name,
SumOfSalaries = x.Employees
.Where(ep) // Causes compile-time error
.Sum(y => y.Salary),
}
.ToList();
Also, if I do a ep.Compile() it compiles, but then I get an error when running the query.
Why is this the case? Am I missing something? I don't find this logical. Can I fix this somehow? Or do you have a good workaround?
I know that I in this case could just use Where(x => x.Name.StartsWith("John")) instead, but the problem is that the expressions I need are not that trivial. They are longer strings of AndAlsos and OrElses.
If you are going to pass a lambda expression to a LINQ to SQL provider don't create it as an Expression<T> - let the provider do that for you.
The following works for me - note both are compiled:
var companies = dataContext.Companies.Where(cp.Compile())
.Select(x => new
{
x.Name,
SumOfSalaries = x.Employees
.Where( ep.Compile() )
.Sum(y => y.Salary),
}
).ToList();
The expression parser seems to be losing type information in there somewhere after the first where clause when you put in the second. To be honest, I'm not sure why yet.
Edit: To be clear, I do understand that EntitySet doesn't support passing an expression into the where clause. What I don't completely understand is why it fails when you add the Where(ep.Compile()).
My theory is that in compiling the first where (Where(cp.Compile()), Linq2Sql quits parsing the expression - that it can't parse the ep.Compile() against an entityset, and is unable to decide to break up the query into two until you compile the first where clause.
I think you need to rewrite your query. Another way to ask for the details you want, is: "Give me the sum of the salaries for the selected employees in the selected companies, organized by the company name".
So, with the employee salaries in focus, we can write:
//Expression<Func<Employee, bool>> ep = x => x.Name.StartsWith("John");
//Expression<Func<Company, bool>> cp = x => x.Name.StartsWith("Micro");
Expression<Func<Employee, bool>> ep = x => x.Name.StartsWith("John");
Expression<Func<Employee, bool>> cp = x => x.Company.Name.StartsWith("Micro");
var salaryByCompany = dataContext.Employees
.Where(ep)
.Where(cp)
.GroupBy(employee => employee.Company.Name)
.Select(companyEmployees => new
{
Name = companyEmployees.Key,
SumOfSalaries = companyEmployees.Sum(employee => employee.Salary)
});
var companies = salaryByCompany.ToList();

Lambda expression to grab all values inside a Dictionary

I have a LINQ query which returns all the values inside a Dictionary, conditional upon something:
var apps =
from entry in shape.Decorators
where entry.Value == DecoratorLayoutStyle.App
select entry.Key;
shape.Decorators is a
Dictionary<Shape, DecoratorLayoutStyle>
Is there something terser, and/or can I use a combination of lambdas or something?
var apps = shape.Decorators
.Where(x=>x.Value == DecoratorLayoutStyle.App)
.Select(x=>x.Key);
I think yours is just as fine.
That looks plenty terse to me, I guess you could use the extension functions instead of the from/select linq syntax, but that wouldn't be too different.
More imporantly, I'm not sure you want terser. The current format is very readable, and clearly documents exactly what you're trying to do.
var apps = shape.Decorators
.Where(e => e.Value == DecoratorLayoutStyle.App)
.Select(e => e.Key);
Do you think this is terser?
Personally I prefer the query syntax when I have more than one LINQ operator all the operators I use can be translated to it.
var apps = Shape.Decorators.Where(x => x.Value == DecoratorLayoutStyle.App)
.Select(x => x.Key);
Just to be different.
var apps = shape.Decorators.Keys
.Where(k => shape.Decorators[k] == DecoratorLayoutStyle.App);

Categories