A standalone linq to sql translator that can be used with EF and Dapper.
The translator is a nuget libary. To use the libary, use your nuget managment tool to install package EFSqlTranslator.Translation and EFSqlTranslator.EFModels.
Check out EFSqlTranslator.ConsoleApp project to see how to setup the translator.
This section demostrates how the basic linq expression is translated into sql.
// Linq expression:
db.Blogs.Where(b => ((b.Url != null) && b.Name.StartsWith("Ethan")) && ((b.UserId > 1) || (b.UserId < 100)))
-- Transalted Sql:
select b0.*
from Blogs b0
where ((b0.Url is not null) and (b0.Name like 'Ethan%')) and ((b0.UserId > 1) or (b0.UserId < 100))
// Linq expression:
var ids = new[] { 2, 3, 5 };
db.Blogs.Where(b => b.BlogId.In(new[] { 1, 2, 4 }) && b.BlogId.In(ids))
-- Transalted Sql:
select b0.*
from Blogs b0
where (b0.BlogId in (1, 2, 4)) and (b0.BlogId in (2, 3, 5))
In this section, we will show you how relationships are translated. The basic rules are:
- All relations is translated into a inner join by default.
- If a relation is used in a Or binary expression, Select, or Group By then join type will be changed to Left Outer Join.
- Parent relation will be a join to the parent entity.
- Child relation will be converted into a sub-select, which then got joined to.
// Linq expression:
db.Posts.Where(p => p.Blog.Url != null)
-- Transalted Sql:
select p0.*
from Posts p0
inner join Blogs b0 on p0.BlogId = b0.BlogId
where b0.Url is not null
// Linq expression:
db.Blogs.Where(b => b.Posts.Any(p => p.Content != null))
-- Transalted Sql:
select b0.*
from Blogs b0
left outer join (
select p0.BlogId as 'BlogId_jk0'
from Posts p0
where p0.Content is not null
group by p0.BlogId
) sq0 on b0.BlogId = sq0.BlogId_jk0
where sq0.BlogId_jk0 is not null
// Linq expression:
db.Blogs.Where(b => b.User.Comments.Any(c => c.Post.Content != null))
-- Transalted Sql:
select b0.*
from Blogs b0
inner join Users u0 on b0.UserId = u0.UserId
left outer join (
select c0.UserId as 'UserId_jk0'
from Comments c0
inner join Posts p0 on c0.PostId = p0.PostId
where p0.Content is not null
group by c0.UserId
) sq0 on u0.UserId = sq0.UserId_jk0
where sq0.UserId_jk0 is not null
In this section, we will show you multiple ways to select data. You can basically:
- Translate an anonymous object by selecting columns from different table.
- Do multiple Selects to get the final output.
- Use relations in your Select method calls.
// Linq expression:
db.Posts.Where(p => p.User.UserName != null).Select(p => new { Content = p.Content, Title = p.Title })
-- Transalted Sql:
select p0.Content, p0.Title
from Posts p0
inner join Users u0 on p0.UserId = u0.UserId
where u0.UserName is not null
// Linq expression:
db.Posts.Where(p => p.User.UserName != null).Select(p => new { Content = p.Content, UserName = p.Blog.User.UserName })
-- Transalted Sql:
select p0.Content, u1.UserName
from Posts p0
inner join Users u0 on p0.UserId = u0.UserId
left outer join Blogs b0 on p0.BlogId = b0.BlogId
left outer join Users u1 on b0.UserId = u1.UserId
where u0.UserName is not null
// Linq expression:
db.Posts.Where(p => p.Content != null).Select(p => new { TitleContent = p.Title + "|" + p.Content, Num = (p.BlogId / p.User.UserId) })
-- Transalted Sql:
select (p0.Title + '|') + p0.Content as 'TitleContent', p0.BlogId / u0.UserId as 'Num'
from Posts p0
inner join Users u0 on p0.UserId = u0.UserId
where p0.Content is not null
This will become really useful when combining with Group By.
// Linq expression:
db.Posts
.Where(p => p.Content != null)
.Select(p => new { Blog = p.Blog, UserName = p.User.UserName })
.Select(p => new { Url = p.Blog.Url, Name = p.Blog.Name, UserName = p.UserName })
-- Transalted Sql:
select b0.Url, b0.Name, u0.UserName
from Posts p0
left outer join Blogs b0 on p0.BlogId = b0.BlogId
left outer join Users u0 on p0.UserId = u0.UserId
where p0.Content is not null
Grouping is always used along with aggregations. In this section, we will demostrate number of ways that you can group your data. In the next section, you will then see how the group by works with aggregation methods.
// Linq expression:
db.Posts
.Where(p => p.Content != null)
.GroupBy(p => p.BlogId)
.Select(g => new { Key = g.Key })
-- Transalted Sql:
select p0.BlogId as 'Key'
from Posts p0
where p0.Content is not null
group by p0.BlogId
// Linq expression:
db.Posts
.Where(p => p.Content != null)
.GroupBy(p => new { Url = p.Blog.Url, UserName = p.User.UserName })
.Select(g => new { Url = g.Key.Url, UserName = g.Key.UserName })
-- Transalted Sql:
select b0.Url, u0.UserName
from Posts p0
left outer join Blogs b0 on p0.BlogId = b0.BlogId
left outer join Users u0 on p0.UserId = u0.UserId
where p0.Content is not null
group by b0.Url, u0.UserName
This feature allows developers to write sophisticated aggregtion in a much simplier way.
// Linq expression:
db.Posts
.Where(p => p.Content != null)
.GroupBy(p => new { Blog = p.Blog })
.Select(g => new { UserId = g.Key.Blog.User.UserId })
-- Transalted Sql:
select u0.UserId
from Posts p0
left outer join Blogs b0 on p0.BlogId = b0.BlogId
left outer join Users u0 on b0.UserId = u0.UserId
where p0.Content is not null
group by b0.BlogId, u0.UserId
// Linq expression:
db.Posts
.Where(p => p.Content != null)
.Select(p => new { Blog = p.Blog, User = p.User })
.GroupBy(x => new { Blog = x.Blog })
.Select(x => new { Url = x.Key.Blog.Url, UserName = x.Key.Blog.User.UserName })
-- Transalted Sql:
select sq0.Url, u0.UserName
from (
select b0.BlogId, b0.Url, b0.UserId as 'UserId_jk0'
from Posts p0
left outer join Blogs b0 on p0.BlogId = b0.BlogId
left outer join Users u0 on p0.UserId = u0.UserId
where p0.Content is not null
) sq0
left outer join Users u0 on sq0.UserId_jk0 = u0.UserId
group by sq0.BlogId, sq0.Url, u0.UserName
// Linq expression:
db.Blogs
.Where(b => b.Url != null)
.GroupBy(b => new { Cnt = b.Posts.Count(), Avg = b.Posts.Average(p => p.LikeCount) })
.Select(x => new { Cnt = x.Key.Cnt, Avg = x.Key.Avg, CommentCount = x.Sum(b => b.CommentCount) })
-- Transalted Sql:
select coalesce(sq0.count0, 0) as 'Cnt', coalesce(sq0.avg0, 0) as 'Avg', sum(b0.CommentCount) as 'CommentCount'
from Blogs b0
left outer join (
select p0.BlogId as 'BlogId_jk0', count(1) as 'count0', avg(p0.LikeCount) as 'avg0'
from Posts p0
group by p0.BlogId
) sq0 on b0.BlogId = sq0.BlogId_jk0
where b0.Url is not null
group by coalesce(sq0.count0, 0), coalesce(sq0.avg0, 0)
In this section, we will give you several examples to show how the aggregation is translated. We will also demostrate few powerful aggregations that you can do with this libary.
// Linq expression:
db.Posts
.Where(p => p.Content != null)
.GroupBy(p => p.BlogId)
.Select(g => new { cnt = g.Count() })
-- Transalted Sql:
select count(1) as 'cnt'
from Posts p0
where p0.Content is not null
group by p0.BlogId
// Linq expression:
db.Posts
.Where(p => p.Content != null)
.GroupBy(p => p.BlogId)
.Select(g => new { BId = g.Key, cnt = g.Count(), Exp = (g.Sum(p => p.User.UserId) * g.Count(p => p.Content.StartsWith("Ethan"))) })
-- Transalted Sql:
select p0.BlogId as 'BId', count(1) as 'cnt', sum(u0.UserId) * count(case
when p0.Content like 'Ethan%' then 1
else null
end) as 'Exp'
from Posts p0
inner join Users u0 on p0.UserId = u0.UserId
where p0.Content is not null
group by p0.BlogId
// Linq expression:
db.Posts
.Where(p => p.Content != null)
.GroupBy(p => p.BlogId)
.Select(g => new { BID = g.Key, cnt = g.Count(p => (p.Blog.Url != null) || (p.User.UserId > 0)) })
-- Transalted Sql:
select p0.BlogId as 'BID', count(case
when (b0.Url is not null) or (u0.UserId > 0) then 1
else null
end) as 'cnt'
from Posts p0
left outer join Blogs b0 on p0.BlogId = b0.BlogId
left outer join Users u0 on p0.UserId = u0.UserId
where p0.Content is not null
group by p0.BlogId
// Linq expression:
db.Blogs.Where(b => b.Url != null).Select(b => new { Name = b.Name, cnt = b.Posts.Sum(p => p.PostId) })
-- Transalted Sql:
select b0.Name, coalesce(sq0.sum0, 0) as 'cnt'
from Blogs b0
left outer join (
select p0.BlogId as 'BlogId_jk0', sum(p0.PostId) as 'sum0'
from Posts p0
group by p0.BlogId
) sq0 on b0.BlogId = sq0.BlogId_jk0
where b0.Url is not null
// Linq expression:
db.Posts
.Where(p => p.Content != null)
.GroupBy(p => new { Blog = p.Blog })
.Select(g => new { Url = g.Key.Blog.Url, UserId = g.Key.Blog.User.UserId, Cnt = g.Key.Blog.Comments.Count(c => c.User.UserName.StartsWith("Ethan")) })
-- Transalted Sql:
select b0.Url, u0.UserId, count(case
when u1.UserName like 'Ethan%' then 1
else null
end) as 'Cnt'
from Posts p0
left outer join Blogs b0 on p0.BlogId = b0.BlogId
left outer join Users u0 on b0.UserId = u0.UserId
left outer join (
select c0.BlogId as 'BlogId_jk0', c0.UserId as 'UserId_jk0'
from Comments c0
group by c0.BlogId, c0.UserId
) sq0 on b0.BlogId = sq0.BlogId_jk0
left outer join Users u1 on sq0.UserId_jk0 = u1.UserId
where p0.Content is not null
group by b0.BlogId, b0.Url, u0.UserId
This section demostrates how the OrderBy is translated into sql.
// Linq expression:
db.Blogs.Where(b => b.Url.StartsWith("ethan.com")).OrderBy(b => b.User.UserName)
-- Transalted Sql:
select b0.*
from Blogs b0
left outer join Users u0 on b0.UserId = u0.UserId
where b0.Url like 'ethan.com%'
order by u0.UserName
// Linq expression:
db.Blogs
.Where(b => b.Url.StartsWith("ethan.com"))
.OrderBy(b => b.User.UserName)
.ThenByDescending(b => b.CommentCount)
-- Transalted Sql:
select b0.*
from Blogs b0
left outer join Users u0 on b0.UserId = u0.UserId
where b0.Url like 'ethan.com%'
order by u0.UserName, b0.CommentCount desc
Not like Entity Framework, Include and ThenInclude are translated as seperated select statements. This will give us better performance when includes a one to many relation. As we do not need to return all parent rows repeatly, this will significantly reduce the amount of data that needs to be returned from database.
// Linq expression:
db.Posts.Where(p => p.Blog.Url != null).Include(p => p.User)
-- Transalted Sql:
create temporary table if not exists Temp_Table_Posts0 as
select p0.PostId, p0.UserId
from Posts p0
inner join Blogs b0 on p0.BlogId = b0.BlogId
where b0.Url is not null;
select p0.*
from Posts p0
inner join (
select t0.PostId, t0._rowid_
from Temp_Table_Posts0 t0
group by t0.PostId, t0._rowid_
) s0 on p0.PostId = s0.PostId
order by s0._rowid_;
select u0.*
from Users u0
inner join (
select t0.UserId
from Temp_Table_Posts0 t0
group by t0.UserId
) s0 on u0.UserId = s0.UserId;
drop table if exists Temp_Table_Posts0
// Linq expression:
db.Posts
.Where(p => p.Blog.Url != null)
.Include(p => p.User)
.ThenInclude(u => u.Blogs)
-- Transalted Sql:
create temporary table if not exists Temp_Table_Posts0 as
select p0.PostId, p0.UserId
from Posts p0
inner join Blogs b0 on p0.BlogId = b0.BlogId
where b0.Url is not null;
select p0.*
from Posts p0
inner join (
select t0.PostId, t0._rowid_
from Temp_Table_Posts0 t0
group by t0.PostId, t0._rowid_
) s0 on p0.PostId = s0.PostId
order by s0._rowid_;
create temporary table if not exists Temp_Table_Users0 as
select u0.UserId
from Users u0
inner join (
select t0.UserId
from Temp_Table_Posts0 t0
group by t0.UserId
) s0 on u0.UserId = s0.UserId;
select u0.*
from Users u0
inner join (
select t0.UserId, t0._rowid_
from Temp_Table_Users0 t0
group by t0.UserId, t0._rowid_
) s0 on u0.UserId = s0.UserId
order by s0._rowid_;
select b0.*
from Blogs b0
inner join (
select t0.UserId
from Temp_Table_Users0 t0
group by t0.UserId
) s0 on b0.UserId = s0.UserId;
drop table if exists Temp_Table_Users0;
drop table if exists Temp_Table_Posts0
This libary supports more complicated join. You can define your own join condition rather than have to be limited to column pairs.
// Linq expression:
db.Posts.Join(
db.Blogs.Where(b => b.Posts.Any(p => p.User.UserName != null)),
(p, b) => (p.BlogId == b.BlogId) && (p.User.UserName == "ethan"),
(p, b) => new { PId = p.PostId, Name = b.Name },
DbJoinType.LeftOuter)
-- Transalted Sql:
select p0.PostId as 'PId', sq0.Name
from Posts p0
inner join Users u0 on p0.UserId = u0.UserId
left outer join (
select b0.Name, b0.BlogId as 'BlogId_jk0'
from Blogs b0
left outer join (
select p0.BlogId as 'BlogId_jk0'
from Posts p0
inner join Users u0 on p0.UserId = u0.UserId
where u0.UserName is not null
group by p0.BlogId
) sq0 on b0.BlogId = sq0.BlogId_jk0
where sq0.BlogId_jk0 is not null
) sq0 on (p0.BlogId = sq0.BlogId_jk0) and (u0.UserName = 'ethan')