Left outer join of datatable with linq expression? - c#

I have two DataTables:
DataTable dtFields = new DataTable("tmpFieldTable");
dtFields.Columns.Add("FieldID");
dtFields.Columns.Add("CDGroupID");
dtFields.Columns.Add("CDCaption");
dtFields.Columns.Add("fldIndex");
and
DataTable dtCDGroup = new DataTable("tmpCDGroup");
dtCDGroup.Columns.Add("CDGroupID");
dtCDGroup.Columns.Add("Name");
dtCDGroup.Columns.Add("Priority");
I am using following LINQ expression to join these tables:
var resultList = dtFields.AsEnumerable()
.Join(dtCDGroup.AsEnumerable(),
fieldList => fieldList.Field<string>("CDGroupID"),
cd => cd.Field<string>("CDGroupID"),
(fieldList, cd) => new
{
FieldID = fieldList.Field<string>("FieldID"),
CdGroup = cd.Field<string>("Name"),
CDCaption = fieldList.Field<string>("CDCaption"),
Priority = (cd.Field<string>("Priority") ?? "99"),
fldIndex = fieldList.Field<string>("fldIndex").ToString()
})
.OrderBy(result => result.Priority)
.ThenBy(result => result.fldIndex);
How can I perform left outer join with these DataTables?

Left join are not natively offered using lambda expression. but you can achieve this using GroupJoin and SelectMany method.
var result = new string[] { "A", "B" }.GroupJoin(new string[] { "B" }, l => l, r => r, (l, r) => new { l, r }).ToList();
Console.WriteLine(result.Count());
this will result result[0].r.Count() = 0 and result[1].r.Count() = 1.
Hope this will help.
Regards.

Just add DefaultIfEmpty() to your table:
resultList = dtFields.AsEnumerable()
.Join(dtCDGroup.AsEnumerable().DefaultIfEmpty(),
fieldList => fieldList.Field<string>("CDGroupID"),
cd => cd.Field<string>("CDGroupID"),
(fieldList, cd) => new
{
FieldID = fieldList.Field<string>("FieldID"),
CdGroup = cd.Field<string>("Name"),
CDCaption = fieldList.Field<string>("CDCaption"),
Priority = (cd.Field<string>("Priority") ?? "99"),
fldIndex = fieldList.Field<string>("fldIndex").ToString()
})
.OrderBy(result => result.Priority)
.ThenBy(result => result.fldIndex);

Related

How to join a list on a list that uses groupby using lambda expression

I'm trying to join two list and return an object using a lambda expression.
The current query I'm trying to convert looks like:
var results = from w in unitsList
group w by new{ w.UnitNo, w.Proj, w.Cred, w.Yr } into wGroup
join m in minList
on new { wGroup.Key.UnitNo, wGroup.Key.Proj }
equals new { m.UnitNo, m.Proj } into nGroup
select new DailyUnit(){
UnitNo = wGroup.key.UnitNo,
Project = wGroup.key.Proj,
Creds = wGroup.Key.Cred,
Years = wGroup.Key.Yr,
Sites = nGroup.Sum(x => x.Value) }).ToList()};
How do I do the group by and join using a lambda expression?
I've tried:
var results = unitsList.ToList().GroupBy(w => new{ w.UnitNo, w.Proj, w.Cred, w.Yr })
.Join(minList, w => { w.Key.UnitNo, w.Key.Proj },
u => { u.Key.UnitNo, u.Key.Proj },
(w,u) => new DailyUnit()
{ UnitNo = w.key.UnitNo,
Project = w.key.Proj,
Creds = w.Key.Cred,
Years = w.Key.Yr,
Sites = u.Sum(x => x.Value)
}
).ToList()};

Execute query using LINQ or EF to fetch records from multiple tables

I've been searching for a while now. But all the solutions seems to be different than what I expect.
So this is my query in SQL:-
Select * from
(
select Name,Description Descr from CourseTbl
union all
select MainDesc Name,MainDesc Descr from CoursedescTbl
union all
select SubHeading Name,SubDesc Descr from CourseSubDesc
union all
select Name,Descr as Descr from InternTbl
)A where A.Name like '%D%' or A.Descr like '%D%'
I want to execute the above query using LINQ or EF. and return the list in Json format. So I tried many failed attempts and this is one of them:-
public JsonResult SearchDetail()
{
string SearchKey = Request.Form["SearchName"].ToString();
IEnumerable<SearchList> QueryResult;
using (EBContext db = new EBContext())
{
try
{
QueryResult =
(from x in db.Courses
select new { A = x.Name, B = x.Description })
.Concat(from y in db.CourseDesc
select new { A = y.MainHeading, B = y.MainDesc })
.Concat(from z in db.CourseSubDesc
select new { A = z.SubDesc, B = z.SubHeading })
.Concat(from w in db.Interns
select new { A = w.Name, B = w.Descr })
.ToList();
}
catch (Exception ex)
{
return new JsonResult
{
Data = ex.Message,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
return new JsonResult
{
Data = QueryResult,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
And my SearchList Class is like this:-
public class SearchList
{
public string Name { get; set; }
public string Descr { get; set; }
}
I'm not able to put the where clause in linq query which will search in all table.
I'm getting error when I assign queryresult to my ef query. It says cannot cast to Innumerable.
Thanks in Advance.
Could you explain more on the error you are getting?
Also, have you tried using .Union() in linq?
QueryResult = db.Courses.Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
.ToList(); //this isn't necessary
Edit: There are two ways to input where clause, either with each search, or at the end:
QueryResult = db.Courses.Where(x=>x.Name == "Name").Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Where(y=>y.MainHeading == "Name").Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
.ToList();
Or:
QueryResult = db.Courses.Where(x=>x.Name == "Name").Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Where(y=>y.MainHeading == "Name").Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
//Where can go either before or after .ToList
.Where(item=>item.A == "Name")
.ToList();
You did not say what error/exception you are getting. But your QueryResult is of type IEnumerable<SearchList> and you appear to be assigning it an enumerable of anonymous type { A, B }.
Try this:
QueryResult = (from x in db.Courses
select new SearchList { Name = x.Name, Descr = x.Description })
.Concat(...)
.ToList();
Or
QueryResult = db.Courses.Select(x => new SearchList
{ Name = x.Name, Descr = x.Description})
.Concat(...)
.ToList();
UPDATE
Your #2 issue will be fixed if you changed your select to new up a SearchList as I did above, instead of new-ing an anonymous type.
As for your issue #1, you should insert the Where() before your Select():
result1 = db.Courses
.Where(x => x.Name.Contains('D') || x.Description.Contains('D'))
.Select(x => new SearchList { Name = x.Name, Descr = x.Description});
result2 = db.CourseDesc
.Where(y => y.MainHeading.Contains('D') || y.MainDesc.Contains('D'))
.Select(y => new SearchList { Name = y.MainHeading, Descr = y.MainDesc});
result3 = db.CourseSubDesc
.Where(...)
.Select(...);
QueryResult = result1.Concat(result2).Concat(result3).ToList();
Doing Where() as part of the query on each table is important so you do not fetch all records from that table, unlike if you do the Where() after Concat(). Also note that Concat() may throw an ArgumentNullException.
Take the lists Separately and query and concat
check this example
List<string> a = new List<string>() { "a", "b", "c" };
List<string> b = new List<string>() { "ab", "bb", "cb" };
IEnumerable<SearchList> QueryResult =
a.Where(x => x.Contains("a")).Select(x => new SearchList() { Name = x, Descr = x })
.Concat(b.Where(x => x.Contains("a")).Select(x => new SearchList() { Name = x, Descr = x }));

SQL query to LINQ conversion with nested select statements

I want to convert the following query to LINQ:
SELECT LV.* FROM LowerVehicles LV
INNER JOIN (Select VSerial,MAX(updatedOn) MaxUpdatedOn from LowerVehicles group by vserial) LVG
ON LV.VSerial = LVG.VSerial AND LV.updatedOn = LVG.MaxUpdatedOn
Not knowing your entities classes, here is an approximation. You can use query syntax or fluent syntax. Sometimes one is preferable over the other, and in the case of joins and grouping I prefer to use query syntax.
QUERY SYNTAX
var query = from LV in LowerVehicles
join LVG in (
from r in LowerVehicles
group r by r.vserial into g
select new {VSerial = g.Key, MaxUpdatedOn = g.Max(t => t.updatedOn)})
on LV.VSerial equals LVG.Vserial
and LV.updatedOn equals LVG.MaxUpdatedOn
select LV;
FLUENT SYNTAX
var lvg = LowerVehicles.GroupBy(t => t.vserial)
.Select(g => new {
VSerial = g.Key,
MaxUpdatedOn = g.Max(t => t.updatedOn)
});
var query = LowerVehicles.Join(
lvg,
a => new { a.VSerial, a.updatedOn },
b => new { b.VSerial, b.MaxUpdatedOn },
(a, b) => new { LV = a, LVG = b}
)
.Select(t=> t.LV);
Something like this?
Something.LowerVehicles
.Join(something.LowerVehicles.Select(y => new { y.VSerial, updatedOn = y.updatedOn.Max() }).GroupBy(z => z.VSerial),
x => new { x.VSerial, x.updatedOn },
lvg => new { lvg.VSerial, lvg.updatedOn },
(x, y) => x)

Join and Group By using Lambda Expression

Query
var grpby4 = from u in dtEmp.AsEnumerable()
join v in dtDept.AsEnumerable() on u.Field<int>("DepartmentID") equals v.Field<int>("DepartmentID")
group u by v.Field<string>("DeptName") into g
select new { DeptName = g.Key, Records = g };
How write the same Query using Lambda Expression?
Using this handy webpage I get
dtEmp.AsEnumerable()
.Join(dtDept.AsEnumerable(),
u => u.Field<int>("DepartmentID"),
v => v.Field<int>("DepartmentID"),
(u, v) => new { u, v })
.GroupBy(τ0 => τ0.v.Field<string>("DeptName"), τ0 => τ0.u)
.Select(g => new { DeptName = g.Key, Records = g })

Convert LINQ in query syntax to lambda syntax

This is my LINQ query, Please help me in changing this LINQ query to query using Lambda expression:
var query = from d in db.customers
from s in db.tbl_states
where d.cust_state == s.state_id
select new
{
d.cust_name,
s.state_name
};
Try this:
var query =
db.customers.Join (
db.tbl_states,
d => d.cust_state,
s => s.state_id,
(d, s) => new { d.cust_name, s.state_name }
);
This should do it:
var query = db.customers.Join(db.tbl_states, d => d.cust_state, s => s.state_id, (d, s) => new { d.cust_name, s.state_name });
I guess your linq its should be like this
var query = from d in db.customers
join s in db.tbl_states on d.cust_state equals s.state_id
select new
{
d.cust_name,
s.state_name
};
for Lambda
var list = db.customers
.Join(db.tbl_states,
s => s.tbl_states,
d => d.state_id,
(s, d) => new
{
d.cust_name,
s.state_name
});

Categories