{"id":19992502,"url":"https://github.com/ethanli83/EFSqlTranslator","last_synced_at":"2025-05-04T11:31:19.575Z","repository":{"id":10990817,"uuid":"67926110","full_name":"ethanli83/EFSqlTranslator","owner":"ethanli83","description":"A standalone linq to sql translator that can be used with EF and Dapper.","archived":false,"fork":false,"pushed_at":"2022-12-08T08:56:27.000Z","size":619,"stargazers_count":52,"open_issues_count":4,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-13T04:55:19.566Z","etag":null,"topics":["dapper","efcore","entity-framework","linq","netcore","sql","sql-translator"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ethanli83.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-09-11T11:26:51.000Z","updated_at":"2024-09-01T04:54:06.000Z","dependencies_parsed_at":"2023-01-11T20:15:29.850Z","dependency_job_id":null,"html_url":"https://github.com/ethanli83/EFSqlTranslator","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ethanli83%2FEFSqlTranslator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ethanli83%2FEFSqlTranslator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ethanli83%2FEFSqlTranslator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ethanli83%2FEFSqlTranslator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ethanli83","download_url":"https://codeload.github.com/ethanli83/EFSqlTranslator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252329393,"owners_count":21730606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dapper","efcore","entity-framework","linq","netcore","sql","sql-translator"],"created_at":"2024-11-13T04:52:11.802Z","updated_at":"2025-05-04T11:31:14.566Z","avatar_url":"https://github.com/ethanli83.png","language":"C#","readme":"# \u003cimg src=\"https://github.com/ethanli83/LinqRunner/blob/master/LinqRunner.Client/src/img/Butterfly.png\" align=\"left\" height=\"40\" width=\"40\"/\u003eEFSqlTranslator [![Build Status](https://travis-ci.org/ethanli83/EFSqlTranslator.svg?branch=master)](https://travis-ci.org/ethanli83/EFSqlTranslator)\n\nA standalone linq to sql translator that can be used with EF and Dapper.\n\nThe translator is a nuget libary. To use the libary, use your nuget managment tool to install package [EFSqlTranslator.Translation](https://www.nuget.org/packages/EFSqlTranslator.Translation/) and [EFSqlTranslator.EFModels](https://www.nuget.org/packages/EFSqlTranslator.EFModels/).\n\nCheck out EFSqlTranslator.ConsoleApp project to see how to setup the translator.\n\n## I. Basic Translation\nThis section demostrates how the basic linq expression is translated into sql.\n### 1. Basic filtering on column values in where clause\n```csharp\n// Linq expression:\ndb.Blogs.Where(b =\u003e ((b.Url != null) \u0026\u0026 b.Name.StartsWith(\"Ethan\")) \u0026\u0026 ((b.UserId \u003e 1) || (b.UserId \u003c 100)))\n```\n```sql\n-- Transalted Sql:\nselect b0.*\nfrom Blogs b0\nwhere ((b0.Url is not null) and (b0.Name like 'Ethan%')) and ((b0.UserId \u003e 1) or (b0.UserId \u003c 100))\n```\n\n### 2. Filter result using list of values\n```csharp\n// Linq expression:\nvar ids = new[] { 2, 3, 5 };\ndb.Blogs.Where(b =\u003e b.BlogId.In(new[] { 1, 2, 4 }) \u0026\u0026 b.BlogId.In(ids))\n```\n```sql\n-- Transalted Sql:\nselect b0.*\nfrom Blogs b0\nwhere (b0.BlogId in (1, 2, 4)) and (b0.BlogId in (2, 3, 5))\n```\n## II. Translating Relationsheips\nIn this section, we will show you how relationships are translated. The basic rules are:\n  1. All relations is translated into a inner join by default.\n  2. If a relation is used in a Or binary expression, Select, or Group By then join type will be changed to Left Outer Join.\n  3. Parent relation will be a join to the parent entity.\n  4. Child relation will be converted into a sub-select, which then got joined to.\n\n### 1. Join to a parent relation\n```csharp\n// Linq expression:\ndb.Posts.Where(p =\u003e p.Blog.Url != null)\n```\n```sql\n-- Transalted Sql:\nselect p0.*\nfrom Posts p0\ninner join Blogs b0 on p0.BlogId = b0.BlogId\nwhere b0.Url is not null\n```\n\n### 2. Join to a child relation\n```csharp\n// Linq expression:\ndb.Blogs.Where(b =\u003e b.Posts.Any(p =\u003e p.Content != null))\n```\n```sql\n-- Transalted Sql:\nselect b0.*\nfrom Blogs b0\nleft outer join (\n    select p0.BlogId as 'BlogId_jk0'\n    from Posts p0\n    where p0.Content is not null\n    group by p0.BlogId\n) sq0 on b0.BlogId = sq0.BlogId_jk0\nwhere sq0.BlogId_jk0 is not null\n```\n\n### 3. Use relationships in a chain\n```csharp\n// Linq expression:\ndb.Blogs.Where(b =\u003e b.User.Comments.Any(c =\u003e c.Post.Content != null))\n```\n```sql\n-- Transalted Sql:\nselect b0.*\nfrom Blogs b0\ninner join Users u0 on b0.UserId = u0.UserId\nleft outer join (\n    select c0.UserId as 'UserId_jk0'\n    from Comments c0\n    inner join Posts p0 on c0.PostId = p0.PostId\n    where p0.Content is not null\n    group by c0.UserId\n) sq0 on u0.UserId = sq0.UserId_jk0\nwhere sq0.UserId_jk0 is not null\n```\n## III. Translating Select\nIn this section, we will show you multiple ways to select data. You can basically:\n  1. Translate an anonymous object by selecting columns from different table.\n  2. Do multiple Selects to get the final output.\n  3. Use relations in your Select method calls.\n\n### 1. Select out only required columns\n```csharp\n// Linq expression:\ndb.Posts.Where(p =\u003e p.User.UserName != null).Select(p =\u003e new { Content = p.Content, Title = p.Title })\n```\n```sql\n-- Transalted Sql:\nselect p0.Content, p0.Title\nfrom Posts p0\ninner join Users u0 on p0.UserId = u0.UserId\nwhere u0.UserName is not null\n```\n\n### 2. Select out required columns from related entity\n```csharp\n// Linq expression:\ndb.Posts.Where(p =\u003e p.User.UserName != null).Select(p =\u003e new { Content = p.Content, UserName = p.Blog.User.UserName })\n```\n```sql\n-- Transalted Sql:\nselect p0.Content, u1.UserName\nfrom Posts p0\ninner join Users u0 on p0.UserId = u0.UserId\nleft outer join Blogs b0 on p0.BlogId = b0.BlogId\nleft outer join Users u1 on b0.UserId = u1.UserId\nwhere u0.UserName is not null\n```\n\n### 3. Translate up selection with columns and expression\n```csharp\n// Linq expression:\ndb.Posts.Where(p =\u003e p.Content != null).Select(p =\u003e new { TitleContent = p.Title + \"|\" + p.Content, Num = (p.BlogId / p.User.UserId) })\n```\n```sql\n-- Transalted Sql:\nselect (p0.Title + '|') + p0.Content as 'TitleContent', p0.BlogId / u0.UserId as 'Num'\nfrom Posts p0\ninner join Users u0 on p0.UserId = u0.UserId\nwhere p0.Content is not null\n```\n\n### 4. Multiple selections with selecting whole entity\nThis will become really useful when combining with Group By.\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Content != null)\n    .Select(p =\u003e new { Blog = p.Blog, UserName = p.User.UserName })\n    .Select(p =\u003e new { Url = p.Blog.Url, Name = p.Blog.Name, UserName = p.UserName })\n```\n```sql\n-- Transalted Sql:\nselect b0.Url, b0.Name, u0.UserName\nfrom Posts p0\nleft outer join Blogs b0 on p0.BlogId = b0.BlogId\nleft outer join Users u0 on p0.UserId = u0.UserId\nwhere p0.Content is not null\n```\n## IV. Translating GroupBy\nGrouping is always used along with aggregations. In this section, we will demostrate number of\nways that you can group your data. In the next section, you will then see how the group by works\nwith aggregation methods.\n\n### 1. Basic grouping on table column\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Content != null)\n    .GroupBy(p =\u003e p.BlogId)\n    .Select(g =\u003e new { Key = g.Key })\n```\n```sql\n-- Transalted Sql:\nselect p0.BlogId as 'Key'\nfrom Posts p0\nwhere p0.Content is not null\ngroup by p0.BlogId\n```\n\n### 2. Using relationships in grouping\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Content != null)\n    .GroupBy(p =\u003e new { Url = p.Blog.Url, UserName = p.User.UserName })\n    .Select(g =\u003e new { Url = g.Key.Url, UserName = g.Key.UserName })\n```\n```sql\n-- Transalted Sql:\nselect b0.Url, u0.UserName\nfrom Posts p0\nleft outer join Blogs b0 on p0.BlogId = b0.BlogId\nleft outer join Users u0 on p0.UserId = u0.UserId\nwhere p0.Content is not null\ngroup by b0.Url, u0.UserName\n```\n\n### 3. Group on whole entity\nThis feature allows developers to write sophisticated aggregtion in a much simplier way.\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Content != null)\n    .GroupBy(p =\u003e new { Blog = p.Blog })\n    .Select(g =\u003e new { UserId = g.Key.Blog.User.UserId })\n```\n```sql\n-- Transalted Sql:\nselect u0.UserId\nfrom Posts p0\nleft outer join Blogs b0 on p0.BlogId = b0.BlogId\nleft outer join Users u0 on b0.UserId = u0.UserId\nwhere p0.Content is not null\ngroup by b0.BlogId, u0.UserId\n```\n\n### 4. Mix of Select and Group method calls\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Content != null)\n    .Select(p =\u003e new { Blog = p.Blog, User = p.User })\n    .GroupBy(x =\u003e new { Blog = x.Blog })\n    .Select(x =\u003e new { Url = x.Key.Blog.Url, UserName = x.Key.Blog.User.UserName })\n```\n```sql\n-- Transalted Sql:\nselect sq0.Url, u0.UserName\nfrom (\n    select b0.BlogId, b0.Url, b0.UserId as 'UserId_jk0'\n    from Posts p0\n    left outer join Blogs b0 on p0.BlogId = b0.BlogId\n    left outer join Users u0 on p0.UserId = u0.UserId\n    where p0.Content is not null\n) sq0\nleft outer join Users u0 on sq0.UserId_jk0 = u0.UserId\ngroup by sq0.BlogId, sq0.Url, u0.UserName\n```\n\n### 5. Group On Aggregation\n```csharp\n// Linq expression:\ndb.Blogs\n    .Where(b =\u003e b.Url != null)\n    .GroupBy(b =\u003e new { Cnt = b.Posts.Count(), Avg = b.Posts.Average(p =\u003e p.LikeCount) })\n    .Select(x =\u003e new { Cnt = x.Key.Cnt, Avg = x.Key.Avg, CommentCount = x.Sum(b =\u003e b.CommentCount) })\n```\n```sql\n-- Transalted Sql:\nselect coalesce(sq0.count0, 0) as 'Cnt', coalesce(sq0.avg0, 0) as 'Avg', sum(b0.CommentCount) as 'CommentCount'\nfrom Blogs b0\nleft outer join (\n    select p0.BlogId as 'BlogId_jk0', count(1) as 'count0', avg(p0.LikeCount) as 'avg0'\n    from Posts p0\n    group by p0.BlogId\n) sq0 on b0.BlogId = sq0.BlogId_jk0\nwhere b0.Url is not null\ngroup by coalesce(sq0.count0, 0), coalesce(sq0.avg0, 0)\n```\n## V. Translating Aggregtaions\nIn this section, we will give you several examples to show how the aggregation is translated.\nWe will also demostrate few powerful aggregations that you can do with this libary.\n\n### 1. Count on basic grouping\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Content != null)\n    .GroupBy(p =\u003e p.BlogId)\n    .Select(g =\u003e new { cnt = g.Count() })\n```\n```sql\n-- Transalted Sql:\nselect count(1) as 'cnt'\nfrom Posts p0\nwhere p0.Content is not null\ngroup by p0.BlogId\n```\n\n### 2. Combine aggregations in selection\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Content != null)\n    .GroupBy(p =\u003e p.BlogId)\n    .Select(g =\u003e new { BId = g.Key, cnt = g.Count(), Exp = (g.Sum(p =\u003e p.User.UserId) * g.Count(p =\u003e p.Content.StartsWith(\"Ethan\"))) })\n```\n```sql\n-- Transalted Sql:\nselect p0.BlogId as 'BId', count(1) as 'cnt', sum(u0.UserId) * count(case\n    when p0.Content like 'Ethan%' then 1\n    else null\nend) as 'Exp'\nfrom Posts p0\ninner join Users u0 on p0.UserId = u0.UserId\nwhere p0.Content is not null\ngroup by p0.BlogId\n```\n\n### 3. Count on basic grouping with condition\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Content != null)\n    .GroupBy(p =\u003e p.BlogId)\n    .Select(g =\u003e new { BID = g.Key, cnt = g.Count(p =\u003e (p.Blog.Url != null) || (p.User.UserId \u003e 0)) })\n```\n```sql\n-- Transalted Sql:\nselect p0.BlogId as 'BID', count(case\n    when (b0.Url is not null) or (u0.UserId \u003e 0) then 1\n    else null\nend) as 'cnt'\nfrom Posts p0\nleft outer join Blogs b0 on p0.BlogId = b0.BlogId\nleft outer join Users u0 on p0.UserId = u0.UserId\nwhere p0.Content is not null\ngroup by p0.BlogId\n```\n\n### 4. Sum on child relationship\n```csharp\n// Linq expression:\ndb.Blogs.Where(b =\u003e b.Url != null).Select(b =\u003e new { Name = b.Name, cnt = b.Posts.Sum(p =\u003e p.PostId) })\n```\n```sql\n-- Transalted Sql:\nselect b0.Name, coalesce(sq0.sum0, 0) as 'cnt'\nfrom Blogs b0\nleft outer join (\n    select p0.BlogId as 'BlogId_jk0', sum(p0.PostId) as 'sum0'\n    from Posts p0\n    group by p0.BlogId\n) sq0 on b0.BlogId = sq0.BlogId_jk0\nwhere b0.Url is not null\n```\n\n### 5. Aggregate after grouping on an entity.\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Content != null)\n    .GroupBy(p =\u003e new { Blog = p.Blog })\n    .Select(g =\u003e new { Url = g.Key.Blog.Url, UserId = g.Key.Blog.User.UserId, Cnt = g.Key.Blog.Comments.Count(c =\u003e c.User.UserName.StartsWith(\"Ethan\")) })\n```\n```sql\n-- Transalted Sql:\nselect b0.Url, u0.UserId, count(case\n    when u1.UserName like 'Ethan%' then 1\n    else null\nend) as 'Cnt'\nfrom Posts p0\nleft outer join Blogs b0 on p0.BlogId = b0.BlogId\nleft outer join Users u0 on b0.UserId = u0.UserId\nleft outer join (\n    select c0.BlogId as 'BlogId_jk0', c0.UserId as 'UserId_jk0'\n    from Comments c0\n    group by c0.BlogId, c0.UserId\n) sq0 on b0.BlogId = sq0.BlogId_jk0\nleft outer join Users u1 on sq0.UserId_jk0 = u1.UserId\nwhere p0.Content is not null\ngroup by b0.BlogId, b0.Url, u0.UserId\n```\n## VI. Translating OrderBys\nThis section demostrates how the OrderBy is translated into sql.\n### 1. OrderBy on normal column\n```csharp\n// Linq expression:\ndb.Blogs.Where(b =\u003e b.Url.StartsWith(\"ethan.com\")).OrderBy(b =\u003e b.User.UserName)\n```\n```sql\n-- Transalted Sql:\nselect b0.*\nfrom Blogs b0\nleft outer join Users u0 on b0.UserId = u0.UserId\nwhere b0.Url like 'ethan.com%'\norder by u0.UserName\n```\n\n### 2. OrderBy with different direction\n```csharp\n// Linq expression:\ndb.Blogs\n    .Where(b =\u003e b.Url.StartsWith(\"ethan.com\"))\n    .OrderBy(b =\u003e b.User.UserName)\n    .ThenByDescending(b =\u003e b.CommentCount)\n```\n```sql\n-- Transalted Sql:\nselect b0.*\nfrom Blogs b0\nleft outer join Users u0 on b0.UserId = u0.UserId\nwhere b0.Url like 'ethan.com%'\norder by u0.UserName, b0.CommentCount desc\n```\n## VII. Translating Includes\nNot like Entity Framework, Include and ThenInclude are translated as seperated select statements.\nThis will give us better performance when includes a one to many relation. As we do not need to\nreturn all parent rows repeatly, this will significantly reduce the amount of data that needs to be\nreturned from database.\n\n### 1. Include an entity by parent relation\n```csharp\n// Linq expression:\ndb.Posts.Where(p =\u003e p.Blog.Url != null).Include(p =\u003e p.User)\n```\n```sql\n-- Transalted Sql:\ncreate temporary table if not exists Temp_Table_Posts0 as \n    select p0.PostId, p0.UserId\n    from Posts p0\n    inner join Blogs b0 on p0.BlogId = b0.BlogId\n    where b0.Url is not null;\n\nselect p0.*\nfrom Posts p0\ninner join (\n    select t0.PostId, t0._rowid_\n    from Temp_Table_Posts0 t0\n    group by t0.PostId, t0._rowid_\n) s0 on p0.PostId = s0.PostId\norder by s0._rowid_;\n\nselect u0.*\nfrom Users u0\ninner join (\n    select t0.UserId\n    from Temp_Table_Posts0 t0\n    group by t0.UserId\n) s0 on u0.UserId = s0.UserId;\n\ndrop table if exists Temp_Table_Posts0\n```\n\n### 2. Include a parent relation, then include a child relation\n```csharp\n// Linq expression:\ndb.Posts\n    .Where(p =\u003e p.Blog.Url != null)\n    .Include(p =\u003e p.User)\n    .ThenInclude(u =\u003e u.Blogs)\n```\n```sql\n-- Transalted Sql:\ncreate temporary table if not exists Temp_Table_Posts0 as \n    select p0.PostId, p0.UserId\n    from Posts p0\n    inner join Blogs b0 on p0.BlogId = b0.BlogId\n    where b0.Url is not null;\n\nselect p0.*\nfrom Posts p0\ninner join (\n    select t0.PostId, t0._rowid_\n    from Temp_Table_Posts0 t0\n    group by t0.PostId, t0._rowid_\n) s0 on p0.PostId = s0.PostId\norder by s0._rowid_;\n\ncreate temporary table if not exists Temp_Table_Users0 as \n    select u0.UserId\n    from Users u0\n    inner join (\n        select t0.UserId\n        from Temp_Table_Posts0 t0\n        group by t0.UserId\n    ) s0 on u0.UserId = s0.UserId;\n\nselect u0.*\nfrom Users u0\ninner join (\n    select t0.UserId, t0._rowid_\n    from Temp_Table_Users0 t0\n    group by t0.UserId, t0._rowid_\n) s0 on u0.UserId = s0.UserId\norder by s0._rowid_;\n\nselect b0.*\nfrom Blogs b0\ninner join (\n    select t0.UserId\n    from Temp_Table_Users0 t0\n    group by t0.UserId\n) s0 on b0.UserId = s0.UserId;\n\ndrop table if exists Temp_Table_Users0;\n\ndrop table if exists Temp_Table_Posts0\n```\n## VIII. Translating Manual Join\nThis libary supports more complicated join. You can define your own join condition rather than\nhave to be limited to column pairs.\n\n### 1. Join on custom condition\n```csharp\n// Linq expression:\ndb.Posts.Join(\n    db.Blogs.Where(b =\u003e b.Posts.Any(p =\u003e p.User.UserName != null)),\n    (p, b) =\u003e (p.BlogId == b.BlogId) \u0026\u0026 (p.User.UserName == \"ethan\"),\n    (p, b) =\u003e new { PId = p.PostId, Name = b.Name },\n    DbJoinType.LeftOuter)\n```\n```sql\n-- Transalted Sql:\nselect p0.PostId as 'PId', sq0.Name\nfrom Posts p0\ninner join Users u0 on p0.UserId = u0.UserId\nleft outer join (\n    select b0.Name, b0.BlogId as 'BlogId_jk0'\n    from Blogs b0\n    left outer join (\n        select p0.BlogId as 'BlogId_jk0'\n        from Posts p0\n        inner join Users u0 on p0.UserId = u0.UserId\n        where u0.UserName is not null\n        group by p0.BlogId\n    ) sq0 on b0.BlogId = sq0.BlogId_jk0\n    where sq0.BlogId_jk0 is not null\n) sq0 on (p0.BlogId = sq0.BlogId_jk0) and (u0.UserName = 'ethan')\n```\n\n\n","funding_links":[],"categories":["C\\#","C# #"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fethanli83%2FEFSqlTranslator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fethanli83%2FEFSqlTranslator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fethanli83%2FEFSqlTranslator/lists"}