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();
}
Related
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();
I am trying to join three lists but for some reason the second join is causing no data to be returned. I ultimately do want to "left" join this, but I'm trying to solve the problem of it not joining properly first.
My three lists:
var equipmentAliasList = new List<EquipmentAlias> {
new EquipmentAlias { Alias = "100-00001"},
new EquipmentAlias { Alias = "100-00005"},
new EquipmentAlias { Alias = "100-00004"},
new EquipmentAlias { Alias = "100-00003"},
new EquipmentAlias { Alias = "100-00002"},
}
var assets = new List<Asset> {
new Asset { AssetNum = "100-00001", LineAsset = "200-00001"},
new Asset { AssetNum = "100-00005", LineAsset = "200-00002"},
new Asset { AssetNum = "100-00004", LineAsset = ""},
new Asset { AssetNum = "100-00003", LineAsset = "200-00001"},
new Asset{ AssetNum = "100-00002", LineAsset = ""},
};
var lineAssets = new List<Asset> {
new Asset { AssetNum = " 200-00001", IsRunning = true },
new Asset { AssetNum = " 200-00002", IsRunning = false },
};
So, select all from equipmentAliasList join assets on assetNum and then join lineAssets on asset.LineAsset equals lineAsset.AssetNum.
Here's what I've come up with:
(from e in equipmentAliasList
join ma in assets on e.Alias equals ma.AssetNum
join la in lineAssets on ma.LineAsset equals la.AssetNum
select new EquipmentAlias
{
Alias = e.Alias,
IsPor = la.IsRunning,
}).ToList();
And the result should be:
Alias | IsPor
----------|-----------
100-00001 | true
100-00005 | false
100-00003 | true
However, the join from assets to lineAssets is causing the query to not return any results.
Well if you notice lineAssets, there are spaces in AssetNum field. Change " 200-00001" to "200-00001"
var lineAssets = new List<Asset> {
new Asset { AssetNum = "200-00001", IsRunning = true },
new Asset { AssetNum = "200-00002", IsRunning = true },
};
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)
};
what is the wrong with this LINQ statement:
(from deposit in DAOBase<CashBookDeposit, long>.GetIQueryableBusinessBase()
where deposit.Id == id
select new CashBookDeposit
{
Id = deposit.Id,
DepositeNumber = deposit.DepositeNumber,
DocumentTypeName = deposit.CashBookDepositDocumentType.EnglishName,
StatusName = deposit.CashBookDepositeStatus.EnglishName,
CashbookName = deposit.CashBook.EnglishName,
Collector = deposit.Collector,
Partner = deposit.Partner,
CashBookDepositDocumentType = deposit.CashBookDepositDocumentType,
CreationDate = deposit.CreationDate,
PaidAmount = deposit.TotalAmount,
Description = deposit.Description,
TempReceipts = (from receipt in deposit.TempReceipts
select new TempReceipt
{
Id = receipt.Id,
Code = receipt.Code,
ReceiptNo = receipt.ReceiptNo,
Amount = receipt.Amount,
BusinessPartnerName = receipt.Partner.ENName,
CollectorName = receipt.Collector.EnglishName,
StatusName = receipt.TempReceiptStatus.EnglishName,
CollectionDate = receipt.CollectionDate,
CreationDate = receipt.CreationDate,
Description = receipt.Description,
}).ToList()
}).SingleOrDefault();
i got this exception :
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
need help, thanks
You can change the query as follows:
(from deposit in DAOBase<CashBookDeposit, long>.GetIQueryableBusinessBase()
let receipts = (from tempReceipts in deposit.TempReceipts
select tempReceipts)
where deposit.Id == id
select new CashBookDeposit
{
Id = deposit.Id,
DepositeNumber = deposit.DepositeNumber,
DocumentTypeName = deposit.CashBookDepositDocumentType.EnglishName,
StatusName = deposit.CashBookDepositeStatus.EnglishName,
CashbookName = deposit.CashBook.EnglishName,
Collector = deposit.Collector,
Partner = deposit.Partner,
CashBookDepositDocumentType = deposit.CashBookDepositDocumentType,
CreationDate = deposit.CreationDate,
PaidAmount = deposit.TotalAmount,
Description = deposit.Description,
TempReceipts = (from receipt in receipts
select new TempReceipt
{
Id = receipt.Id,
Code = receipt.Code,
ReceiptNo = receipt.ReceiptNo,
Amount = receipt.Amount,
BusinessPartnerName = receipt.Partner.ENName,
CollectorName = receipt.Collector.EnglishName,
StatusName = receipt.TempReceiptStatus.EnglishName,
CollectionDate = receipt.CollectionDate,
CreationDate = receipt.CreationDate,
Description = receipt.Description,
}).ToList()
}).SingleOrDefault();
var setsA = new List<SetA> {
new SetA { SsnA = "3450734507", name = "setA"},
new SetA { SsnA = "6833467788", name = "setA"},
new SetA { SsnA = "5452347787", name = "setA"},
new SetA { SsnA = "9345345345", name = "setA"},
};
var setsB = new List<SetB> {
new SetB { SsnB = "5452347787" ,name = "setB"},
new SetB { SsnB = "9345345345", name = "setB"},
};
when i use this linq:
var Set =
from seta in setsA
join setb in setsB
on seta.SsnA
equals setb.SsnB
select new {
SSN = seta.SsnA,
NAME = setb.name
};
i get this value:
{ SSN = "5452347787", NAME = "setB" }
{ SSN = "9345345345", NAME = "setB" }
but i would want to have SET which combines these two and the result would be:
{ SSN = "3450734507", NAME = "setA" }
{ SSN = "6833467788", NAME = "setA" }
{ SSN = "5452347787", NAME = "setB" }
{ SSN = "9345345345", NAME = "setB" }
This would be a result set that would tell me with the name NAME property which set it was taken from, if SSN was found in SetA and SetB it would have property NAME = "setB"
could someone help me with this?
It seems you want an outer join - this is done using GroupJoin:
var set = setsA.GroupJoin(
setsB,
sa => sa.SsnA,
sb => sb.SsnB,
(a, bs) => new { SSN = a.SsnA, NAME = bs.Any() ? "setB" : "setA" });
The LINQ way described here:
http://msdn.microsoft.com/en-us/library/bb397895.aspx would look like this (functionally same to the lambda way):
var set = from a in setsA
join b in setsB on a.SsnA equals b.SsnB into g
from o in g.DefaultIfEmpty()
select new { SSN = a.SsnA, NAME = (o != null ? o.name : a.name)};