From time-to-time, I stumble on this problem that I use a subset of lambda joins. Given that I can use any LINQ extensions how should I go about implementing following joins:
For simplicity sake tables are defined as
CREATE TABLE [dbo].[TableA] (
[Key] INT IDENTITY (1, 1) NOT NULL,
[Value] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED ([Key] ASC)
);
CREATE TABLE [dbo].[TableB] (
[Key] INT IDENTITY (1, 1) NOT NULL,
[Value] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_TableB] PRIMARY KEY CLUSTERED ([Key] ASC)
);
or if you prefer code first
public class TableContext : DbContext
{
public DbSet<B> TableB { get; set; }
public DbSet<A> TableA { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(ConnectionString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TableB>().Property(o => o.Key).UseSqlServerIdentityColumn();
modelBuilder.Entity<TableA>().Property(o => o.Key).UseSqlServerIdentityColumn();
}
}
public class B : IKeyValue
{
public int Key { get; set; }
public string Value { get; set; }
}
public class A : IKeyValue
{
public int Key { get; set; }
public string Value { get; set; }
}
public interface IKeyValue
{
int Key { get; set; }
string Value { get; set; }
}
((A intersect not B) union (A intersect B))
var leftOuterJoin = TableA
.GroupJoin(
TableB,
a => a.Key,
b => b.Key,
(x, y) => new { TableA = x, TableA = y })
.SelectMany(
x => x.TableB.DefaultIfEmpty(),
(x, y) => new { TableA = x.TableA, TableB = y});
(A intersects B)
var innerJoin = TableA
.Join(
TableB,
a => a.Key,
b => b.Key,
(x, y) => x)
(A union B)
var fullOuterJoin = TableA
.FullOuterJoin(
TableB,
a => a.Key,
b => b.Key,
(x, y, Key) => new {x, y})
1); var join = query1. Join(query2, x => x. ParentId, y => y. ParentId, (query1, query2) => new { query1 , query2 }).
In a LINQ query expression, join operations are performed on object collections. Object collections cannot be "joined" in exactly the same way as two relational tables. In LINQ, explicit join clauses are only required when two source sequences are not tied by any relationship.
A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.
A lambda expression with an expression on the right side of the => operator is called an expression lambda. An expression lambda returns the result of the expression and takes the following basic form: C# Copy. (input-parameters) => expression. The body of an expression lambda can consist of a method call.
The most important thing for you, is to know how to perform an INNER JOIN
and an OUTER JOIN
.
For the INNER JOIN you use JOIN
from LINQ like so:
var result =
TableA
.Join(TableB, left => left.Id, right => right.ForeignKeyToTableA,
(left, right) => new { TableAColumns = left, TableBColumns = right });
The OUTER JOIN you already showed in your example.
Now you need to mix what you know, to get the desired results.
For example to perform a FULL OUTER JOIN do something like this pseudocode in LINQ:
SELECT TableA.*, TableB.* FROM TableA LEFT OUTER JOIN TableB
UNION
SELECT TableA.*, TableB.* FROM TableB LEFT OUTER JOIN TableA
This would be in LINQ as follows:
var fullOuterJoin =
(
TableA
.GroupJoin(TableB,
left => left.Id, right => right.ForeignKeyId,
(left, right) => new { TableA = left, TableB = right })
.SelectMany(p => p.TableB.DefaultIfEmpty(), (x, y) =>
new { TableA = x.TableA, TableB = y })
)
.Union
(
TableB
.GroupJoin(TableA,
left => left.Id, right => right.ForeignKeyId,
(left, right) => new { TableA = right, TableB = left })
.SelectMany(p => p.TableA.DefaultIfEmpty(), (x, y) =>
new { TableA = y, TableB = x.TableB })
);
The very last example of your image would then be:
var fullOuterJoinOnlyWithNulls =
fullOuterJoin
.Where(p => p.TableA == null || p.TableB == null);
A RIGHT OUTER JOIN is nothing but a LEFT OUTER JOIN where you swap your result columns like this:
var rightOuterJoin =
(
TableB
.GroupJoin(TableA,
left => left.Id, right => right.ForeignKeyId,
(left, right) => new { TableA = right, TableB = left })
.SelectMany(p => p.TableA.DefaultIfEmpty(), (x, y) =>
new { TableA = y, TableB = x.TableB })
);
Like this you can construct all your example scenarios. Just check the tables for null when needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With