Find duplicate values in Entity Framework [duplicate] - c#

How can I write a linq to entities query that includes a having clause?
For example:
SELECT State.Name, Count(*) FROM State
INNER JOIN StateOwner ON State.StateID = StateOwner.StateID
GROUP BY State.StateID
HAVING Count(*) > 1

Any reason not to just use a where clause on the result?
var query = from state in states
join stateowner in stateowners
on state.stateid equals stateowner.stateid
group state.Name by state.stateid into grouped
where grouped.Count() > 1
select new { Name = grouped.Key, grouped.Count() };

I believe you can use a GroupBy followed by a Where clause and it will translate it as a Having. Not entirely sure though.

If you want to compare a variable that is not in the group by (Ex: age), then it would be:
var duplicated = (
from q1 in db.table1
where (q1.age >= 10 )
group q1 by new { q1.firstName, q1.lastName } into grp
where (grp.Count() > 1 )
select new
{
firstName= grp.Key.firstName,
lastName = grp.Key.lastName,
}
);

Related

How to add less than or equal to condition in linq inner join

We have two objects, Dates and ActiveEvents. Want to perform inner join on these with less than or equal to condition in linq. Same as ref of below SQL where consider #Tables are C# objects
Select A. from #Activities A
Inner Join #Dates D ON A.ActivityDate <= D.ProcessDate
Tried with below but it's not giving correct results.
var filteredActivity = (from e in ActiveEvents
from p in dates
where e.ActivityDate <= p.Date
select new ActiveEvent
{
ActivityDate = p.Date,
EventId = e.EventId
}).ToList();
And
var filteredActivity = (from e in ActiveEvents
from p in dates.Where(r => e.ActivityDate <= r)
select new ActiveEvent
{
ActivityDate = p.Date,
EventId = e.EventId
}).ToList();
Can you please suggest any better way to do this?
You can try this way
var filteredActivity = (from e in ActiveEvents
join p in dates
where e.ActivityDate <= p.ProcessDate
select new ActiveEvent
{
ActivityDate = p.Date,
EventId = e.EventId
}).ToList();
P/s: Ideally, between 2 tables should contain the foreign key to join like this join p in dates on e.Key equals p.ForeignKey
Based on your example, the query is filtering on ProcessDate but your linq query is filtering on p.Date. Are those the same field? The first example you gave should be correct.

C# LINQ Query with group by, having and where clause invalid

I have the following Linq queries which are getting the error below. My question is how can I use the T_EquipmentCompetency.Competency in a where clause but not have it in the group by or select list. I am fairly new to LINQ queries. Is there something that I am missing here?
using (EntitiesModel dbContext = new EntitiesModel())
{
var competencyForMachine = (from eq in dbContext.T_Equipmentcompetencies
where eq.MachineId == machineId
select eq.CompetencyId);
var competencyForEmployees = (from sm in dbContext.T_OHS_Skillsmatrices
join em in dbContext.T_Employees on sm.EmployeeID equals em.EmployeeID
where competencyForMachine.Contains(sm.CompentencyID)
group sm by new {sm.EmployeeID,em.FirstNameSTR,em.LastNameSTR} into g
where g.Count() == competencyForMachine.Count()
select new {g.Key.EmployeeID, g.Key.FirstNameSTR,g.Key.LastNameSTR});
foreach(var employee in competencyForEmployees)
{
RadMenuItem employeeItem = new RadMenuItem { Text= employee.FirstNameSTR + " " + employee.LastNameSTR, Value = employee.EmployeeID.ToString()};
Item.Items.Add(employeeItem);
}
}
This is the error I am getting
Telerik.OpenAccess.RT.sql.SQLException: Column
'dbo.T_EquipmentCompetency.CompetencyId' is invalid in the select list
because it is not contained in either an aggregate function or the GROUP BY clause.
The sql I am trying to emulate works in SQL Server
declare #MachineId int = 1
select sm.EmployeeID,em.FirstNameSTR,em.LastNameSTR
from T_OHS_SkillsMatrix sm
inner join T_Employees em on sm.EmployeeID = em.employeeId
where sm.CompentencyID in ( select CompetencyID
from T_EquipmentCompetency
where MachineId = #machineId
)
group by sm.EmployeeID,em.FirstNameSTR,em.LastNameSTR
having count(*) = (select count(*) from T_EquipmentCompetency where MachineId = #MachineId)
you got it mispelled
select eq.CompetencyId --- different spelling
sm.CompentencyID
while in sql sql server
where sm.CompentencyID in ( select CompentencyID

How to convert Group By SQL to LINQ?

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.
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
};
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 };

left join in Linq query

I'm trying to do a left join, not an inner join in a linq query. I have found answers related to using DefaultIfEmpty() however I can't seem to make it work. The following is the linq query:
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id
where a.Table1_id == id
orderby a.sort descending
group e by new
{
a.Field1,
a.Field2
} into ga
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects = (from g in ga select new SubObject{
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
The query only gives me the rows from table 1 that have a corresponding record in table 2. I would like every record in table 1 populated into MyObject and a list of 0-n corresponding records listed in manySubObjects for each MyObject.
UPDATE:
I tried the answer to the question that is a "possible duplicate", mentioned below. I now have the following code that does give me one record for each item in Table1 even if there is no Table2 record.
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id into j1
from j2 in j1.DefaultIfEmpty()
where a.Table1_id == id
orderby a.sort descending
group j2 by new
{
a.Field1,
a.Field2
} into ga
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects = (from g in ga select new SubObject{
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
However, with this code, when there is no record in table2 I get "manySubObject" as a list with one "SubObject" in it with all null values for the properties of "SubObject". What I really want is "manySubObjects" to be null if there is no values in table2.
In reply to your update, to create the null listing, you can do a ternary in your assignment of manySubObjects.
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects =
(from g in ga select g).FirstOrDefaut() == null ? null :
(from g in ga select new SubObject {
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
Here is a dotnetfiddle that tries to do what you're attempting. https://dotnetfiddle.net/kGJVjE
Here is a subsequent dotnetfiddle based on your comments. https://dotnetfiddle.net/h2xd9O
In reply to your comments, the above works with Linq to Objects but NOT with Linq to SQL. Linq to SQL will complain that it, "Could not translate expression ... into SQL and could not treat as a local expression." That's because Linq cannot translate the custom new SubObject constructor into SQL. To do that, you have to write more code to support translation into SQL. See Custom Method in LINQ to SQL query and this article.
I think we've sufficiently answered your original question about left joins. Consider asking a new question about using custom methods/constructors in Linq to SQL queries.
I think the desired Result that you want can be given by using GroupJoin()
The code Below will produce a structure like so
Field1, Field2, List < SubObject > null if empty
Sample code
var query = dc.Table1.Where(x => Table1_id == id).OrderBy(x => x.sort)
.GroupJoin(dc.Table2, (table1 => table1.Table1_id), (table2 => table2.Table2_id),
(table1, table2) => new MyObject
{
field1 = table1.Field1,
field2 = table1.Field2,
manySubObjects = (table2.Count() > 0)
? (from t in table2 select new SubObject { fielda = t.fielda, fieldb = t.fieldb}).ToList()
: null
}).ToList();
Dotnetfiddle link
UPDATE
From your comment I saw this
ga.Select(g = > new SubObject(){fielda = g.fielda, fieldb = g.fieldb})
I think it should be (depends on how "ga" is built)
ga.Select(g => new SubObject {fielda = g.fielda, fieldb = g.fieldb})
Please update your question with the whole query, it will help solve the issue.
** UPDATE BIS **
sentEmails = //ga.Count() < 1 ? null :
//(from g in ga select g).FirstOrDefault() == null ? null :
(from g in ga select new Email{
email_to = g.email_to,
email_from = g.email_from,
email_cc = g.email_cc,
email_bcc = g.email_bcc,
email_subject = g.email_subject,
email_body = g.email_body }).ToList()
Should be:
sentEmails = //ga.Count() < 1 ? null :
((from g in ga select g).FirstOrDefault() == null) ? null :
(from g in ga select new Email{
email_to = g.email_to,
email_from = g.email_from,
email_cc = g.email_cc,
email_bcc = g.email_bcc,
email_subject = g.email_subject,
email_body = g.email_body }).ToList()
Checks if the group has a First, if it doesn't the group doesn't have any records so the Action.Name for a Time Stamp has no emails to send. If the First isn't null the loop throw the group elements and create a list of Email,
var results =
(
// Use from, from like so for the left join:
from a in dc.Table1
from e in dc.Table2
// Join condition goes here
.Where(a.Id == e.Id)
// This is for the left join
.DefaultIfEmpty()
// Non-join conditions here
where a.Id == id
// Then group
group by new
{
a.Field1,
a.Field2
}
).Select(g =>
// Sort items within groups
g.OrderBy(item => item.sortField)
// Project required data only from each item
.Select(item => new
{
item.FieldA,
item.FieldB
}))
// Bring into memory
.ToList();
Then project in-memory to your non-EF-model type.

LINQ aggregate across more than one table

I want to replicate this query in LINQ to SQL but am too unfamiliar with how to do it.
SELECT A.Recruiter, SUM(O.SaleAmount * I.Commission) --This sum from fields in two different tables is what I don't know how to replicate
FROM Orders AS O
INNER JOIN Affiliate A ON O.AffiliateID = A.AffiliateID
INNER JOIN Items AS I ON O.ItemID = I.ItemID
GROUP BY A.Recruiter
I've got this far:
from order in ctx.Orders
join item in ctx.Items on order.ItemI == item.ItemID
join affiliate in ctx.Affiliates on order.AffiliateID == affiliate.AffiliateID
group order //can I only group one table here?
by affiliate.Recruiter into mygroup
select new { Recruiter = mygroup.Key, Commission = mygroup.Sum(record => record.SaleAmount * ?????) };
group new {order, item} by affiliate.Recruiter into mygroup
select new {
Recruiter = mygroup.Key,
Commission = mygroup
.Sum(x => x.order.SaleAmount * x.item.Commission)
};
And an alternative way of writing the query:
from aff in ctx.Affiliates
where aff.orders.Any(order => order.Items.Any())
select new {
Recruiter = aff.Recruiter,
Commission = (
from order in aff.orders
from item in order.Items
select item.Commission * order.SaleAmount
).Sum()
};
try linqpad, just Google, amazing tool!

Categories