Linq-2-SQL Left Outer Join in C# - c#

What would be the linq-2-sql syntax for this SQL Query:
SELECT emp.id, Name, Count(t.id) as CNT
FROM employee emp
LEFT JOIN taskAssignment t
on emp.id = t.FKEmployeeID GROUP BY emp.id, Name
tables are like this:

Here is the answer
var lst = from emp in Employeetables
join task in TaskAssignmentTables
on emp.EmployeeId equals task.FKEmployeeId into j
from result in j.DefaultIfEmpty()
group result by new { emp.EmployeeId, emp.Name } into groupResult
select new
{
EmployeeId = groupResult.Key.EmployeeId,
Name = groupResult.Key.Name,
Count = groupResult.Count(r => r.FKEmployeeId != null)
};
This returns the same answer as your SQL question related to this SQL Left outer join question. I developed this simply using LinqPad

Not very sure if this will work but it is definitely worth a try.
If it doesnt work as expected then please let me know what query does it fire on the database so that I can improve accordingly.
List<Employee> employee = new List<Employee>()
{
new Employee() { id = 1, Name = "Samar" },
new Employee() { id = 1, Name = "Samar" },
new Employee() { id = 1, Name = "Samar" },
new Employee() { id = 2, Name = "Sid" }
};
List<TaskAssignment> taskAssignment = new List<TaskAssignment>()
{
new TaskAssignment(){FKEmployeeID = 1},
new TaskAssignment(){FKEmployeeID = 1}
};
var cls = from e in employee
join emp in taskAssignment on e.id equals emp.FKEmployeeID into empout
group e by new { e.id, e.Name } into g
select new { g.Key.id, g.Key.Name, CNT = g.Count() };
Hope this helps.

Try this.
var employees = from emp in dbContext.Employees
join task in dbContext.TaskAssignmentTable
on emp.employeeID equals task.FKEmployeeID
into tEmpWithTask
from tEmp in tEmpWithTask.DefaultIfEmpty()
group tEmp by new { emp.EmployeeID, emp.Name } into grp
select new {
grp.Key.EmployeeID,
grp.Key.Name,
grp.Count(t=>t.TaskID != null)
};

Related

How can I get a list of objects related to a min from a Linq

I have a Linq Query that is working as intended, but I need to add the code so that it will show me ONLY the people with the less cases assigned for an app that is been used to treat customers inquiries. The idea behind the query is so that it will let me automatically assign inquiries randomly between those agents which have less assigned issues to cover.
As a simple example, lets say I have 5 agents with just 1 case each, I need to randomly assign one of them to an Inquire which has currently no agent assigned. So all I'm looking for is a way to actually get all the agents with the smallest number of cases assigned.
So far this is the full proof of concept code:
var inquires = new List<Inquire>();
var agents = new List<Agent>();
LoadData();
var assignationsPerAgent = (from agent in agents
join inq in inquires on agent equals inq.AssignedAgent into agentsInInquires
select new {
o_agent = agent,
casesAssignedTo = agentsInInquires.Count()
}).ToList();
//This works but is NOT the kind of solution I'm looking for
var min = assignationsPerAgent.Min(c => c.casesAsignedTo);
var agentWithMin = assignationsPerAgent.Where(a => a.casesAsignedTo == min);
Console.WriteLine();
void LoadData()
{
agents = new(){
new Agent{ Id = Guid.Parse("317d3d26-25c2-49da-aa4b-b7e49a1b9015"), Name = "Robert" },
new Agent{ Id = Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"), Name = "Corina" },
new Agent{ Id = Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"), Name = "John" },
new Agent{ Id = Guid.Parse("34e091e4-cc7a-4222-9885-5de5bb5a0291"), Name = "Jack"},
new Agent{ Id = Guid.Parse("f22dcb4e-e927-4ddf-ae66-f37c0de6753d"), Name = "Samuel"}
};
inquires = new(){
new Inquire{ CustomerName = "Paula", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("317d3d26-25c2-49da-aa4b-b7e49a1b9015"))},
new Inquire{ CustomerName = "Barry", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"))},
new Inquire{ CustomerName = "Bertie", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"))},
new Inquire{ CustomerName = "Herman", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"))},
new Inquire{ CustomerName = "Ashley", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("317d3d26-25c2-49da-aa4b-b7e49a1b9015"))},
new Inquire{ CustomerName = "Tate", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"))},
new Inquire{ CustomerName = "Bonnie", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"))},
new Inquire{ CustomerName = "Tabitha", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"))},
new Inquire{ CustomerName = "Ashley", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("34e091e4-cc7a-4222-9885-5de5bb5a0291"))},
new Inquire{ CustomerName = "Josie", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"))},
new Inquire{ CustomerName = "Kelly", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"))},
new Inquire{ CustomerName = "Kelly", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("f22dcb4e-e927-4ddf-ae66-f37c0de6753d"))},
};
}
#nullable disable
class Inquire
{
private Guid _id;
public Guid Id
{
get
{
return _id;
}
private set
{
_id = Guid.NewGuid();
}
}
public string CustomerName { get; set; }
public Agent AsignedAgent { get; set; }
}
#nullable disable
class Agent
{
public Guid Id {get; set;}
public string Name { get; set; }
}
Please take in consideration that the assignationsPerAgent variable is simulating data coming from a query in the database (The actual query is below). If the "easy" way to do this comes from the SQL that it's also an acceptable solution.
SELECT u.Id, COUNT(g.Id) as QtyAsig
FROM Users as u
LEFT JOIN GeneralInquires AS g ON u.Id = g.UserId
GROUP BY u.Id
ORDER BY COUNT(g.Id)
What I'm getting from this Query is:
Id QtyAsig
8A21A6D2-0CEC-4F5C-2A6B-08DA60967E94 1
323C8D1A-2FAE-4ECC-D7A2-08DA6098F19A 1
BA485F3C-C44A-4FE5-9BFA-08DA64EF283A 1
8F0E856E-FA0B-4167-BBEF-08DA6451FA81 2
40952727-5C76-4902-9C4F-08DA638B3068 3
DD51085A-5BE3-4872-F4B5-08DA6E7828AA 4
What I need is:
Id QtyAsig
8A21A6D2-0CEC-4F5C-2A6B-08DA60967E94 1
323C8D1A-2FAE-4ECC-D7A2-08DA6098F19A 1
BA485F3C-C44A-4FE5-9BFA-08DA64EF283A 1
Thank you in advance!
check this
var assignationsPerAgent = (from agent in agents
join inq in inquires on agent equals inq.AsignedAgent into agentsInInquires
from inq in agentsInInquires.DefaultIfEmpty()
select new
{
o_agent = agent,
casesAssignedTo = agentsInInquires.Count()
}).GroupBy(x=>x.casesAssignedTo).OrderBy(x=>x.Key).FirstOrDefault();
Linq doesn't require one statement and splitting results has no impact on performance. Try following :
List<Inquire> sortedInquires = inquires.OrderBy(x => x.AsignedAgent.Id).ToList();
var results = (from a in agents
//join i in sortedInquires on a.Id equals i.Id
join i in sortedInquires on a.Id equals i.AssignedAgent
select new { agent = a, inquires = i}
).GroupBy(x => x.agent.Id)
.Select(x => x.First())
.ToList();

How can I use Linq to include a List<myDto> in selectTableDto?

I am currently using Linq to join two tables together, mainTable and selectTable, they are joined on mainTable.ID = selectTable.mtID. I am trying to include a third table, myTable, that is joined on selectTable.ID = myTable.selID. There will be many records in myTable for one ID from selectTable so I'm trying to get List<myTable>. This is what I have so far that works:
public async Task<List<mainTableDto>> listAll()
{
var db = _repository.DbContext;
var result = await ( from mt in db.mainTable
join sel in db.selectTable
on mt.ID equals sel.mtID
select new mainTableDto
{
ID = mt.ID,
createDate = mt.createDate,
selectTable = new selectTableDto
{
ID = sel.ID
name = sel.name
}
}
}).ToListAsync;
return result;
I've tested getting data from selectTableDto with List< myTableDto> and it works.
I'm a little stuck on how to include a List<myTableDto> into this nested call. I've tried:
join sel in db.selectTableInclude(x=>x.myTableDto)
But when I do this I don't get the info from myTableDto and just get null instead (I've put data in the DB so there should be something)
I've also tried:
join sel in db.selectTable
on mt.ID equals sel.mtID
join my in db.myTable
on sel.ID equals my.selID
selectTable = new selectTableDto
{
ID = sel.ID
name = sel.name
myTableDto = new List<myTableDto>
{
ID = my.ID
}
}
But when I do this it says "ID is not a member of myTableDTO".
Any advice on what I'm doing wrong?
I believe you want a groupjoin (method syntax) or into (query syntax)
This is query syntax:
from mt in db.mainTable
join sel in db.selectTable
on mt.ID equals sel.mtID
into mainTableSels
select new mainTableDto
{
ID = mt.ID,
createDate = mt.createDate,
selectTable = from mts in mainTableSels select new selectTableDto
{
ID = mts.ID
name = mts.name
}
}
Though I do personally prefer a hybrid query/method syntax:
from mt in db.mainTable
join sel in db.selectTable
on mt.ID equals sel.mtID
into mainTableSels
select new mainTableDto
{
ID = mt.ID,
createDate = mt.createDate,
selectTable = mainTableSels.Select(mts => new selectTableDto
{
ID = mts.ID
name = mts.name
})
}
I'm not clear on what type your mainTableDto.selectTable property is; if it's an array or list you'll need a ToArray/ToList. If it's IEnumerable then it should work without

Linq, Json, Select product from db

I have a 3 tables Dish, Wine, Suggestion.
Then the idea is use table suggestion table to put the dish and the wine making one of them suggestion each other.
I'm using LINQ, but when one product doesn't have a suggestion he does not add to the json.
var query = (from m in db.Dish
join t in db.TypeDish on m.idTypeDish equals t.idTypeDish
join i in db.ImageDish on m.idDish equals i.idDish into g
join s in db.Suggestion on m.idDish equals s.idDish
join si in db.ImageWine on s.idWine equals si.idWine into f
where m.idTypeDish == dish
select new DishModel()
{
Name = m.name,
CalorificValue = m.calorificValue,
Price = m.price,
ShortName = m.shortName,
Time = m.manufactureTime,
Description = m.description,
UrlImageList = g.Select(i => _url + i.Image.urlImage).ToList(),
BeveragesList = new List<BeverageModel>()
{
new BeverageModel()
{
Name = s.Wine.name,
ShortName = s.Wine.shortName,
Price = s.Wine.price,
Description = s.Wine.description,
AlcoholContent = s.Wine.alcoholContent,
WineEnum = WineEnum.WhiteWine,
Region = s.Wine.Region.name,
WineCaste = s.Wine.wineCaste,
UrlImageList = f.Select(i => _url+i.Image.urlImage).ToList(),
}
}
}).ToList();
return query;
Now I have 2 items on DB, and he sends only one because the other don't have a suggestion.
The error is on joins probably, but I'm a newbie in Linq.
Thanks.

LINQ Updating the selected object while doing a left outer join

In the below code, I have a collection of Employee object. I have to check whether the employee are InOrg or not. For that I do a left join with the InOrgCatalog table and return an anonymous object. I already have an InOrg property
in my Employee object, so instead of returning an anonymous object I want to return the Employee object with the InOrg property updated. What change I have to do in the query to achieve that?
List<Employee> employees = new List<Employee>
{
new Employee { EmployeeId = 1, EmployeeName = "Aaron" , Alias = "AWERAS", InOrg = false},
new Employee { EmployeeId = 2, EmployeeName = "asdfsdf" , Alias = "HJKHJK", InOrg = false},
new Employee { EmployeeId = 3, EmployeeName = "qwerwe" , Alias = "NMUIYUI", InOrg = false},
new Employee { EmployeeId = 4, EmployeeName = "zcvcx" , Alias = "PIOUKJ", InOrg = false},
};
using (var context = new MyDbContext())
{
var result = (from employee in employees
join catalog in context.InOrgCatalogs on new { Alias = employee.Alias, Active = true } equals
new { Alias = catalog.Alias, Active = catalog.Active }
into ps
from p in ps.DefaultIfEmpty()
select new { Employee = employee , InOrg = !(p == null)}).ToList();
}
it looks to me you need to select a new Employeee object rather than an anonymous object. Then you can update the properties as needed:
using (var context = new MyDbContext())
{
var result = (from Employee employee in employees
join catalog in context.InOrgCatalogs on new { Alias = employee.Alias, Active = true } equals
new { Alias = catalog.Alias, Active = catalog.Active }
into ps
from p in ps.DefaultIfEmpty()
select new Employee { EmployeeId = employee.EmployeeId,EmployeeName = employee.EmployeeName, Alias = employee.Alias, InOrg = !(p == null) }).ToList();
}
Also you can use trick with let keyword and double assigning:
using (var context = new MyDbContext())
{
var result = (from employee in employees
join catalog in context.InOrgCatalogs
on new { Alias = employee.Alias, Active = true } equals
new { Alias = catalog.Alias, Active = catalog.Active } into ps
from p in ps.DefaultIfEmpty()
let temp = employee.InOrg = (p != null)//it will do the work
select employee).ToList();
}

linq SQL statements for joining two id with single list

I want to join list of users with my records list, but records list has two columns where I should use value of user list, also one of those two columns is nullable. How to join it properly? I was trying to do something like this:
var results = (from r in records
join u in users on r.RegisteredBy equals u.Id
join u in users on r.ModifiedBy equals u.Id
select new CustomResult()
{
Id = r.Id,
Name = r.Name,
RegisteredByName = u.Name,
ModifiedByName = u.Name
}).ToList();
It didn't work as I expected, I remember that I have to set it to use default value if null.
For example I have list of users
var user1 = new User() { Id = 1, Name = "John" };
var user2 = new User() { Id = 2, Name = "Matt" }
var user3 = new User() { Id = 3, Name = "George" };
List<User> users = new List<User>(){ user1, user2, user3 };
And I have another List of my records, i.e
var record1 = new Record() { Id = 1, Name = "Record1", RegisteredBy = 1, ModifiedBy = 3};
var record2 = new Record() { Id = 2, Name = "Record2", RegisteredBy = 3, ModifiedBy = null };
var record3 = new Record() { Id = 3, Name = "Record3", RegisteredBy = 2, ModifiedBy = 1 };
List<Record> records = new List<Record>(){ record1, record2, record3 };
As a result of this join I want to make another list of class, having information that I need, i.e
var result1 = new CustomResult(){ Id = 1, Name = "Record1", RegisteredByName = "John", ModifiedByName = "George" };
var result2 = new CustomResult(){ Id = 2, Name = "Record2", RegisteredByName = "George", ModifiedByName = null };
var result3 = new CustomResult(){ Id = 1, Name = "Record3", RegisteredByName = "Matt", ModifiedByName = "John" };
Well, you need to perform left outer join for the optional (nullable) field (and then of course chech for null when accessing related object properties):
var results = (from r in records
join ru in users on r.RegisteredBy equals ru.Id
join mu in users on r.ModifiedBy equals mu.Id into modifiedBy
from mu in modifiedBy.DefaultIfEmpty()
select new CustomResult()
{
Id = r.Id,
Name = r.Name,
RegisteredByName = ru.Name,
ModifiedByName = mu != null ? mu.Name : string.Empty
}).ToList();

Categories