linq select clause syntax - linq

Linq Select method takes Func as input parameter. This means I can have multiple statements in selector for Select, such as
var myresult = sources.Select(s =>
{int x; if (s.val = high) {x=1} else if (s.val = med) {x=2} else {x=3}; return x;
}
)
How can I do this using Linq query syntax
var myresult = from s in sources
select ...
Here, the code in Func part (if ... else if .. else) is artificial. What I really want to know is the syntax of select clause, which may be described as
select select-expression
What is the syntax of
select-expression

I wouldn't want to see your first version in my code. If you need to have what is basically a full function in the lambda, I would rather see the lambda simply invoke a full function! In other words...
theQuery.Select(s => GetX(s)); // just define a GetX function
And that would also be a straightforward translation to query expression syntax
from s in sources
select GetX(s);
You would not be able to put your full code block into the query expression syntax. You could translate your given logic to something usable (yet messy), however I'm quite sure your snippet is just a general example. On the offhand change it isn't, you might try
select s.val == high ? 1 : (s.val == med ? 2 : 3); // totally messy

Instead of special-casing values, with the if/else equivalent of a switch statement, it is more Linq-friendly to group and filter your values:
var myResult = from s in sources
group by s.val into g
select new { Val = g.Key, Sources = g };
var groupHigh = myResult.Where(i => i.Val == high);
var groupMedium = myResult.Where(i => i.Val == medium);
var groupOther = myResult.Except(groupHigh.Concat(groupMedium));
Note that the code I've provided is just a starting place, and isn't the best way to achieve your specific goal. I'd address this in one of these ways:
Change how group by is used (use SomeFunction(s.Val) instead of directly using s.Val)
Change the code around this query to flow better with the natural groupings, so I didn't require the groups to be transformed

This is not possible.
If you really want to, you could create an Func<T> from an anonymous method and invoke it, but that would be horrible.

MSDN indicates select is a contextual keyword of C# 4.0. So I checked the C# Language Specififcation 4.0. Its Select clauses section (7.16.2.5) specifies that
A query expression of the form
from x in e select v
is translated into
( e ) . Select ( x => v )
except when v is the identifier x, the translation is simply
( e )
As the result, the syntax for
select select-expresion
select-expression should be anything that can be used as TResult in Select Method. So the functionality can be done using anonymous Func in Select method may not be able to achieved using select clause.
Conclusion is that you should stick with Method syntax as this is how the code really runs behind the scene.

Related

Why is the "Select" of a Method Syntax is in another parenthesis?

var sample = db.Database.OrderByDescending(x => x.RecordId).Select(y => y.RecordId).FirstOrDefault();
I don't know if my title is correct / right. Just want to ask why this query the select is in another ( )?. As for the example .Select(y => y.RecordId) unlike the query I use to be
var sample = (from s in db.Databse where s.RecordId == id select s) I know this is the same right?. Then what is the why it is in another parenthesis?. Anyone has an idea or can anyone explain it why?. Thanks a lot.
In your first example, you're using "regular" C# syntax to call a bunch of extension methods:
var sample = db.Database
.OrderByDescending(x => x.RecordId)
.Select(y => y.RecordId)
.FirstOrDefault();
(They happen to be extension methods here, but of course they don't have to be...)
You use lambda expressions to express how you want the ordering and projection to be performed, and the compiler converts those into expression trees (assuming this is EF or similar; it would be delegates for LINQ to Objects).
The second example is a query expression, although it doesn't actually match your first example. A query expression corresponding to your original query would be:
var sample = (from x in db.Database
orderby x.RecordId descending
select x.RecordId)
.FirstOrDefault();
Query expressions are very much syntactic sugar. The compiler effectively converts them into the first form, then compiles that. The range variable declared in the from clause (x in this case) is used as the parameter name for the lambda expression, so select x.RecordId becomes .Select(x => x.RecordId).
Things become a bit more complicated with joins and multiple from clauses, as then the compiler introduces transparent identifiers to allow you to work with all the range variables that are in scope, even though you've really only got a single parameter. For example, if you had:
var query = from person in people
from job in person.Jobs
order by person.Name
select new { Person = person, Job = job };
that would be translated into the equivalent of
var query = people.SelectMany(person => person.Jobs, (person, job) => new { person, job } )
.OrderBy(t => t.person.Name)
.Select(t => new { Person = t.person, Job = t.job });
Note how the compiler introduces an anonymous type to combine the person and job range variables into a single object, which is used later on.
Basically, query expression syntax makes LINQ easier to work with - but it's just a translation into other C# code, and is neatly wrapped up in a single section of the C# specification. (Section 7.16.2 of the C# 5 spec.)
See my Edulinq blog post on query expressions for more detail on the precise translation from query expressions to "regular" C#.

How can I merge two outputs of two Linq queries?

I'm trying to merge these two object but not totally sure how.. Can you help me merge these two result objects?
//
// Create Linq Query for all segments in "CognosSecurity"
//
var userListAuthoritative = (from c in ctx.CognosSecurities
where (c.SecurityType == 1 || c.SecurityType == 2)
select new {c.SecurityType, c.LoginName , c.SecurityName}).Distinct();
//
// Create Linq Query for all segments in "CognosSecurity"
//
var userListAuthoritative3 = (from c in ctx.CognosSecurities
where c.SecurityType == 3 || c.SecurityType == 0
select new {c.SecurityType , c.LoginName }).Distinct();
I think I see where to go with this... but to answer the question the types of the objects are int, string, string for SecurityType, LoginName , and SecurityName respectively
If you're wondering why I have them broken like this is because I want to ignore one column when doing a distinct. Here are the SQL queries that I'm converting to SQL.
select distinct SecurityType, LoginName, 'Segment'+'-'+SecurityName
FROM [NFPDW].[dbo].[CognosSecurity]
where SecurityType =1
select distinct SecurityType, LoginName, 'Business Line'+'-'+SecurityName
FROM [NFPDW].[dbo].[CognosSecurity]
where SecurityType =2
select distinct SecurityType, LoginName, SecurityName
FROM [NFPDW].[dbo].[CognosSecurity]
where SecurityType in (1,2)
You can't join these because the types are different (first has 3 properties in the resulting type, second has two).
If you can tolerate putting a null value in for the 3rd result of the second query this will help. I would then suggest you just do a userListAuthoritative.concat(userListAuthoritative3 ) BUT I think this will not work as the anonymous types generated by the linq will not be of the same class, even tho the structure is the same. To solve that you can either define a CustomType to encapsulate the tuple and do select new CustomType{ ... } in both queries or postprocess the results using select() in a similar fashion.
Acutally the latter select() approach will also allow you to solve the parameter count mismatch by implementing the select with a null in the post-process to CustomType.
EDIT: According to the comment below once the structures are the same the anonymous types will be the same.
I assume that you want to keep the results distinct:
var merged = userListAuthoritative.Concat(userListAuthoritative3).Distinct();
And, as Mike Q pointed out, you need to make sure that your types match, either by giving the anonymous types the same signature, or by creating your own POCO class specifically for this purpose.
Edit
If I understand your edit, you want your Distinct to ignore the SecurityName column. Is that correct?
var userListAuthoritative = from c in ctx.CognosSecurities
where new[]{0,1,2,3}.Contains(c.SecurityType)
group new {c.SecurityType, c.LoginName, c.SecurityName}
by new {c.SecurityType, c.LoginName}
select g.FirstOrDefault();
I'm not exactly sure what you mean by merge, since you're returning different (anonymous) types from each one. Is there a reason the following doesn't work for you?
var userListAuthoritative = (from c in ctx.CognosSecurities
where (c.SecurityType == 1 || c.SecurityType == 2 || c.SecurityType == 3 || c.SecurityType == 0)
select new {c.SecurityType, c.LoginName , c.SecurityName}).Distinct();
Edit: This assumed they were of the same type -- but they're not.
userListAuthoritative.Concat(userListAuthoritative3);
Try below code, you might need to implement IEqualityComparer<T> in your ctx type.
var merged = userListAuthoritative.Union(userListAuthoritative3);

Invoke an Expression in a Select statement - LINQ to Entity Framework

I'm trying to use an already existing Expression building class that I made when trying to do a select clause, but I'm not sure how to attach the expression to the expression tree for the Select, I tried doing the following:
var catalogs = matchingCatalogs.Select(c => new
{
c.CatalogID,
Name = EntitiesExpressionHelper.MakeTranslationExpression<Catalog>("Name", ApplicationContext.Instance.CurrentLanguageID).Compile().Invoke(c),
CategoryName = EntitiesExpressionHelper.MakeTranslationExpression<Category>("Name", ApplicationContext.Instance.CurrentLanguageID).Compile().Invoke(c.Category),
c.CategoryID,
c.StartDateUTC,
c.EndDateUTC
});
But I obviously get the error stating that the Entity Framework can't map Invoke to a SQL method. Is there a way to work around this?
FYI, EntitiesExpressionHelper.MakeTranslationExpression<T>(string name, int languageID) is equivalent to:
x => x.Translations.Count(t => t.LanguageID == languageID) == 0 ? x.Translations.Count() > 0 ? x.Translations.FirstOrDefault().Name : "" : x.Translations.FirstOrDefault(t => t.LanguageID == languageID).Name
EDIT: I realize that I need to use an ExpressionVisitor to accomplish this, but I'm not sure how to use an ExpressionVisitor to alter the MemberInitExpression, so if anyone knows how to accomplish this, let me know.
You need to capture the expressions in vars. You won't be able to use anonymous types. The general idea is that this works:
Expression<Func<Foo, Bar>> exp = GenExpression();
var q = matchingCatalogs.Select(exp);
But this will not:
var q = matchingCatalogs.Select(GenExpression());
The first happily passes the result of GenExpression to L2E. The second tries to pass GenExpression itself to L2E, rather than the result.
So you need a reference to a var of the same type as the expression. Those can't be implicitly typed, so you'll need a real type for your result type.

Can Distinct be expressed using so-called embedded query rather than a method call

given the following code:
string[] colors = {"red","green","blue","red","green","blue"};
var distinctColors = (from c in colors select c).Distinct();
distinctColors.Dump();
Is it possible to fold the call .Distinct() into the embedded query syntax?
something like int T-SQL
select distinct color from TableofColors
C#'s query expression syntax doesn't include "distinct". VB's does, however - for example, from the MSDN docs for VB's Distinct clause:
// VB
Dim customerOrders = From cust In customers, ord In orders _
Where cust.CustomerID = ord.CustomerID _
Select cust.CompanyName, ord.OrderDate _
Distinct
The C# equivalent would have to explicitly call Distinct() in dot notation.
However, your example can still be simplified:
string[] colors = {"red","green","blue","red","green","blue"};
var distinctColors = colors.Distinct();
distinctColors.Dump();
Don't think you have to use query expressions to use LINQ :)
There's no distinct embedded query syntax in C# as far as I'm aware. This is as close as it gets:
var distinctColors = (from color in colors
select color).Distinct()
Query comprehension syntax does not support the Distinct method.
In your case, you could simply write colors.Distinct(); you're not doing anything with the query expression.
You can try this
var dis = from c in colors
group c by c;
foreach (var cVal in dis)
{
string s = cVal.Key;
}

nhibernate.linq simple (read dumb) question

I'm trying to wrap my head around linq -> nhib
I have a simple bit of sql that i'm trying to get working in nhibernate.linq
select * from
ColModel where ColModel.DataIndex
not in ('CostElement1', 'CostElement2', 'CostElement3')
and ColModel.ReportId = 1
The list of excluded DataIndex values comes in in the form of a List<string> called excludeNames
Here is what I have tried but it seems that it's not really feeling the love:
var s = base._sessionManager.OpenSession();
var query = from col in s.Linq<ColModel>()
where col.Report.Id == reportid &&
!(from c in s.Linq<ColModel>() select c.DataIndex).Contains(excludeNames)
select col;
return query.ToList();
the error:
The type arguments for method 'System.Linq.Enumerable.Contains<TSource>(System.Collections.Generic.IEnumerable<TSource>, TSource)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
I'm pretty sure I'm borfing this from the offset so any pointers would be well appreciated :)
w://
Contains doesn't accept a list.
There are ways to work around this in LINQ, but I'm not sure which, if any, of those will work in NH Linq
I think you have your exclusion backwards.
s = base._sessionManager.OpenSession();
var query = from col in s.Linq<ColModel>()
where col.Report.Id == reportid &&
!excludeNames.Contains(col.DataIndex)
select col;
return query.ToList();
Collection.Contains(item) will produce the SQL item in (...collection...), adding the negation will get you what you want.

Resources