I am trying to join two tables.
The TSQL would be:
SELECT *
FROM User u INNER JOIN Hierarchy h ON u.OrganisationId = h.OrganisationId
OR u.OrganisationId = h.OwnerOrganisationId
I have searched and no one has an answer for this with fluent. The closest I can think of is this:
var join1 = context.User.Join(context.Hierarchy, u => u.OrganisationId, h => h.OrganisationId, uh => new {u, h});
var join2 = context.User.Join(context.Hierarchy, u => u.OrganisationId, h => h.OwnerOrganisationId, uh => new {u, h});
var desiredResult = join1.Union(join2);
This seems like it could be highly inefficient though.
Fluent syntax
var orJoin = context.User.SelectMany(
u => context.Hierarchy.Where(h => u.OrganisationId == h.OrganisationId || u.OrganisationId == h.OwnerOrganisationId),
(u, h) => new { u, h }
);
Query syntax
var orJoin = from u in context.User
from h in context.Hierarchy
where u.OrganisationId == h.OrganisationId || u.OrganisationId == h.OwnerOrganisationId
select new { u, h };
Related
i'm trying rewrite query from native sql to linq lambda syntax (not linq query syntax)
LINQ (not work)
var result = _uow.Repository<TableA>().Get().AsNoTracking()
.GroupJoin(
_uow.Repository<TableB>().Get().AsNoTracking(),
a => new { a.TabNotesCodeId, a.TabLabelCodeId },
b => b.ElementNameId
(b, a) => new SubSection
{
SubSectionName = b.CustomValue ?? a.TabLabelCodeId,
SubSectionNote = b.CustomValue ?? a.TabLabelCodeId,
})
.Where(a => a.ResourceId == 1);
SQL
SELECT [SubSectionName] = ISNULL(B.CUSTOMVALUE,A.TABLABELCODEID),
[SubSectionNote] = ISNULL(B.CUSTOMVALUE,A.TABNOTESCODEID)
FROM TableA as A LEFT JOIN
(SELECT CUSTOMVALUE, ELEMENTNAMEID FROM TableB WHERE DISPLAYSETTINGID = 1) as B
ON B.ELEMENTNAMEID IN ( A.TABNOTESCODEID, A.TABLABELCODEID)
WHERE A.RESOURCEID = 1
Q How to rewrite sql ON B.ELEMENTNAMEID IN ( A.TABNOTESCODEID, A.TABLABELCODEID) to lambda syntax
...
a => new { a.TabNotesCodeId, a.TabLabelCodeId },
b => b.ElementNameId
....
(doesn't work)
Normally I would suggest following my SQL conversion rules, but this is sufficiently complex I don't think it would help.
To use query comprehension syntax on a non-equijoin that is a left join, it seems easiest to use lambda syntax to express the join conditions, so I just combined the sub-query with the join conditions:
var ans = from A in TableA
where A.ResourceID == 1
from B in TableB.Where(b => b.DisplaySettingID == 1).Where(b => b.ElementNameID == A.TabNotesCodeID || b.ElementNameID == A.TabLabelCodeID).DefaultIfEmpty()
select new {
SubSectionName = (B.CustomValue ?? A.TabLabelCodeID),
SubSectionNote = (B.CustomValue ?? A.TabNotesCodeID)
};
The lambda equivalent of multiple from clauses to generate a cross join is SelectMany, so converting into lambda syntax:
var ans2 = TableA.Where(a => a.ResourceID == 1)
.SelectMany(a => TableB.Where(b => b.DisplaySettingID == 1).Where(b => b.ElementNameID == a.TabNotesCodeID || b.ElementNameID == a.TabLabelCodeID)
.DefaultIfEmpty(),
(a, b) => new {
SubSectionName = (b.CustomValue ?? a.TabLabelCodeID),
SubSectionNote = (b.CustomValue ?? a.TabNotesCodeID)
}
);
After countless experiments i've found out solution:
_uow.Repository<TableA>().Get().AsNoTracking()
.GroupJoin(
_uow.Repository<TableB>().Get().AsNoTracking().Where(b => b.DisplaySettingId == 1),
a => new { note = a.TabNotesCodeId, label = a.TabLabelCodeId },
b => new { note = b.ElementNameId, label = b.ElementNameId },
(a, b) => new { a,b })
.Where(joinTables => joinTables.a.ResourceId == 1)
.SelectMany(
joinTables => joinTables.b.DefaultIfEmpty(),
(joinTables, b) => new SubSection()
{
LayoutTab = joinTables.a.LayoutTab,
SubSectionName = b.CustomValue ?? joinTables.a.TabLabelCodeId,
SubSectionNote = b.CustomValue ?? joinTables.a.TabNotesCodeId
});
Is it possible to join two from based on a local expression variable?
ex;
var query = from t in context.table1
from a in context.anothertable1.Where(x => t.id == a.id)
select new {a,t};
on line 2, the Where clause .Where(x => t.id == a.id) how would you move it into an expression?
I know i can do this;
Expression<Func<anothertable1, bool>> test = x => x.field1 == 1;
and It would work here;
var query = from t in context.table1
from a in context.anothertable1
.Where(x => t.id == a.id)
.Where(test)
select new {a,t};
and everything work and the sql query generated is as expected.
I can't figure out how to do the same with the other where.
EDIT
a more complex example, i anonymized it so it might not compile
var listOfMinMaxtable1 = (from n in context.table1.Where(table1Filter)
group n by n.table1_Number into grp
select new MinMaxtable1()
{
table1_Id_Max = grp.Max(x => x.table1_Id),
table1_Id_Min = grp.Min(x => x.table1_Id),
table1_Number = grp.Key
});
var listtable2 = (from t in context.table2
group t by t.table2_Id into grp
select new table2()
{
table2 = grp,
table2_Id = grp.Key
});
var query = from MinMax in listOfMinMaxtable1
//inner join **reference 1**
from table3 in context.table3
.Where(x => x.table_Number == MinMax.table_Number)
.Where(noticeMasterFilter) //a working expression<func<>>
//inner join **reference 2**
from Lasttable1 in context.table1
.Where(x => x.table_Id == MinMax.table_Id_Max)
//left join **reference 3**
from Firsttable1 in context.table1
.Where(x => x.table_Id == MinMax.table_Id_Min)
.Where(firstNoticeFilter) //a working expression<func<>>
.DefaultIfEmpty()
//left join **reference 4**
from Lasttable2 in listtable2
.Where(x => x.table_Id == MinMax.table_Id_Max)
.SelectMany(x => x.table2)
.Where(x => x.table2_Id == 123)
.OrderByDescending(x => x.table_Id)
.Take(1)
.DefaultIfEmpty()
if you find //left join reference 3 in the code above
that where clause; .Where(x => x.table_Id == MinMax.table_Id_Min)
might be sometime; .Where(x => x.table_Id == MinMax.table_Id_Max)
I could just copy/paste the whole from and change the where clause while adding noop pattern (an expression that return false and this make entity framework remove the whole thing so it doesn't affect the generated sql/result) with an expression on both from
for reference(this is noise to the question), the noop expression that i'm talking about is;
Expression<Func<table1, bool>> includeFrom= x => false;
and would be used like
//left join **reference 3**
from Firsttable1 in context.table1
.Where(x => x.table_Id == MinMax.table_Id_Min)
.Where(firstNoticeFilter) //a working expression<func<>>
.Where(includeFrom) //<--- this line make it a noop if the expression stay false
.DefaultIfEmpty()
but I don't want to do this if it's possible to make a custom expression that would go into the .Where()
Instead of creating an expression based on one type, you can create a combined type and use that for your where expression.
Two Table Combined Type
public class TwoTableDto
{
public Table1 t { get; set; }
public Table2 a { get; set; }
}
Query without expression
var query = (from t in context.table1
from a in context.anothertable1
select new TwoTableDto { t = t, a = a })
.Where(x => x.t.id == x.a.id);
Expression
Expression<Func<TwoTableDto, bool>> expr = x => x.t.id == x.a.id;
Query with expression
var query = (from t in context.table1
from a in context.anothertable1
select new TwoTableDto { t = t, a = a })
.Where(expr);
I have difficulty in translating SQL to LINQ statement.
Here is SQL statement:
SELECT * FROM dataTableA INNER JOIN dataTableB ON dataTableA.ID =dataTableB.SNo OR
dataTableA.Address = dataTableB.Address
WHERE (dataTableA.Name = dataTableB.UserName)
It is OR part in On clause where I don't know how to write LINQ syntax. I have tried with below quote without OR condition. Kindly advise.
var matches = from rowA in dataTableA.AsEnumerable()
join rowB in dataTableB.AsEnumerable()
on rowA["ID"].ToString().Trim() equals rowB["SNo"].ToString().Trim()
where rowA["Name"].ToString().Trim() == rowB["UserName"].ToString().Trim()
select new { rowA, rowB } ;
Try this way
var matches = from rowA in dataTableA.AsEnumerable()
from rowB in dataTableB.AsEnumerable().Where(x=>x.SNo==rowA.ID || x.Address ==rowA.Address) .AsEnumerable()
where rowA["Name"].ToString().Trim() == rowB["UserName"].ToString().Trim()
select new { rowA, rowB } ;
You can use composite keys to join on both ID and Adress
https://msdn.microsoft.com/en-us/library/bb907099.aspx
dataTableA.AsEnumerable().join(dataTableB.AsEnumerable(),
ta => new {ta.ID, ta.Adress}, tb => new {tb.SNo, tb.Adress},
(ta, tb) => new {ta, tb})
If you want to join on ID or Adress, you can union 2 joins, which I think should still be faster than n wheres: Why is LINQ JOIN so much faster than linking with WHERE?
dataTableA.AsEnumerable().join(dataTableB.AsEnumerable(),
ta => ta.ID, tb => tb.SNo, (ta, tb) => new {ta, tb})
.union(dataTableA.AsEnumerable().join(dataTableB.AsEnumerable(),
ta => ta.Adress, tb => tb.Adress, (ta, tb) => new {ta, tb}))
var matches = dataTableA.AsEnumerable()
.Select(a => new {
RowA = a,
RowB = dataTableB.AsEnumerable().FirstOrDefault(b => ((b["SNo"] == a["ID"]) || (b["Address"].Equals(a["Address"]))))
})
.Where(pair => pair.RowB != null) //to replicate the inner-join
.Where(pair => pair.RowA["Name"].Equals(pair.RowB["Username"]));
After minor changes to Mukesh Kalgude's answer, problem solved. Below here is finalized working codes. Thanks to all for your kind suggestions.
var matches = from rowA in dataTableA.AsEnumerable()
from rowB in dataTableB.AsEnumerable().Where(x=>x["SNo"]==rowA["ID"] || x["Address"]==rowA["Address"]) .AsEnumerable()
where rowA["Name"].ToString().Trim() == rowB["UserName"].ToString().Trim()
select new { rowA, rowB } ;
I've written this code to join two tables together from sql server, now I want to write this as in method syntax. How can I rewrite this code?
LinqToLoginDataContext lnqdore = new LinqToLoginDataContext();
var f = (from k in lnqdore.Table_Years
join h in lnqdore.Table_Dores on k.Id equals h.FK_Year
where h.Id == (int)dataviewDore.CurrentRow.Cells["Id"].Value
select k).Single();
var f = lnqdore.Table_Years
.Join(lnqdore.Table_Dores, k => k.ID, h => h.FK_Year, (k, h) => new { k, h })
.Where(res => res.h.ID == (int)dataviewDore.CurrentRow.Cells["Id"].Value)
.Select(res => res.k)
.Single();
Ok, so I have two lists of items which are of different types.
var whales = new List<Whale>();
var crabs = new List<Crab>();
So they both have the id property. So save the lists have objects with Ids of:
whales: 1, 3, 4, 5
crabs: 1, 2, 3, 4
Ok so I have a query:
var matchedPairs = from c in crabs
from w in whales
where c.Id = w.Id
select new { crab = c, whale = w };
So that works fine for getting the matches. Where I'm having trouble is I want to get a list of crabs that don't have a matching whale ie. Crab Id = 2. Then I want to get the whales that don't have a matching crab ie Whale Id = 5.
Can anyone tell me how to write these queries?
if you want to select only crabs.
var result = crabs.Where(c => whales.All(w => w.Id != c.Id));
Maybe something like this:
var unmatchedCrabs = from c in crabs
where !whales.Any(w => w.Id == c.Id)
select c;
You want an outer join:
var crabsWithoutWhales = from c in crabs
join w1 in whales on c.Id equals w1.Id into ws
from w2 in ws.DefaultIfEmpty()
where w2 == null
select c;
You can use Union operation from set operations.
To use it you will have to override default Equality comparer and GetHashCode method. Once you have those then you can do something like this:
var matchedPair = crabs.Union(whales);
In your case, you should have a base class; e.g. Animals with Equality comparer. Another option would be to implement IEqualityComparer<>
var result = crabs.SelectMany(c => whales, (c, w) => new { c, w })
.Where(#t => whales.All(x => x.Id != t.c.Id) && crabs.All(x => x.Id != t.w.Id))
.Select(#t => new {crab = #t.c, whale = #t.w});
Here's the neatest looking LINQ that I can think of to do what you need:
var whalesOnly =
from w in whales
join c in crabs on w.Id equals c.Id into gcs
where !gcs.Any()
select w;
var crabsOnly =
from c in crabs
join w in whales on c.Id equals w.Id into gws
where !gws.Any()
select c;
How do these look for you?
BTW, you can do your join query a little nicer like this:
var whalesAndCrabs =
from whale in whales
join crab in crabs on whale.Id equals crab.Id
select new { crab, whale };
You need two Left Join by GroupJoin method like this:
var result1 = whales.GroupJoin(crabs, w => w.ID, c => c.ID, (w,cs) => new {WhaleID = w.ID, Matches = cs});
var result2 = crabs.GroupJoin(whales, c => c.ID, w => w.ID, (c, ws) => new {CrabID = c.ID, Matches = ws});
Then, filter the result by what you want.