Reputation: 3739
I have the following SQL statement I'm trying to convert to Entity Framework.
SELECT S_NUMBER,A_NUMBER,FIRST_NAME,LAST_NAME
FROM EMPLOYEE WHERE S_NUMBER IN (
SELECT S_NUMBER
FROM EMPLOYEE
WHERE CO='ABC'
GROUP BY S_NUMBER
HAVING COUNT(*) > 1)
I've done some searching on using Group By in LINQ as well as sub-queries. I'm using LinqPad with a "C# Statement" and I came up with the following which based on some examples I found looks like it should work. However, I'm getting errors when trying to assign esn.S_NUMBER to sNumber in the anonymous object. The message says 'IGrouping' does not contain a definition for 'S_NUMBER'.
var result = from e in EMPLOYEE
where e.CO=="ABC"
group e by e.S_NUMBER into esn
select new
{
sNumber = esn.S_NUMBER
};
result.Dump();
I was under the impression that all the records would basically get put into a temp table called esn and I could be able to call the temptable.column name to assign it to my object that I will eventually return as a list.
Upvotes: 2
Views: 521
Reputation: 16584
Since you're using the results of one query to filter another we can do a fairly direct transliteration of the query like so:
var result =
from e in EMPLOYEE
join f in (
from fe in EMPLOYEE
where fe.CO == 'ABC'
group null by S_NUMBER into grp
where grp.Count() > 1
select grp.Key
)
on e.S_NUMBER equals f
select new { e.S_NUMBER, e.A_NUMBER, e.FIRST_NAME, e.LAST_NAME };
Not only does this look a lot more like the original query but it should perform a bit faster (on MS SQL at least, can't speak for others) than the other form that might be simpler in LINQ but is much more complex when converted to SQL... four selects and a cross join, in my test version, vs two selects and an inner join for this one.
Of course if you prefer you can pull the inner query out as a separate IQueryable
for clarity:
var filter =
from e in EMPLOYEE
where e.CO == 'ABC'
group null by S_NUMBER into grp
where grp.Count() > 1
select grp.Key;
var result =
from e in EMPLOYEE
join f in filter
on e.S_NUMBER equals f
select new { e.S_NUMBER, e.A_NUMBER, e.FIRST_NAME, e.LAST_NAME };
Upvotes: 1
Reputation: 21897
You want to use Key
instead of S_NUMBER
. When grouping, the results get put into a IEnumerable<IGrouping>>
. The grouping has a Key
property which holds the key for that group, which in this case it's your S_NUMBER
.
select new
{
sNumber = esn.Key
};
The following query should be a translation of the original SQL query. Instead of using a subquery, we're grouping and doing another from...in
to "flatten" the sequence, and also checking that each grouping has a count > 1
like the original query.
var result = from e in EMPLOYEE
where e.CO=="ABC"
group e by e.S_NUMBER into esn
from e2 in esn
where esn.Count() > 1
select new
{
e.S_NUMBER,
e.A_NUMBER,
e.FIRST_NAME,
e.LAST_NAME
};
Upvotes: 4