{"id":21035239,"url":"https://github.com/zompinc/efcore-extensions","last_synced_at":"2025-05-15T13:33:24.264Z","repository":{"id":43026592,"uuid":"450148852","full_name":"zompinc/efcore-extensions","owner":"zompinc","description":"Provides window (analytics) functions and binary functions for EF Core. Providers: SQL Server, SQLite, Postgres.","archived":false,"fork":false,"pushed_at":"2025-02-09T18:37:59.000Z","size":295,"stargazers_count":78,"open_issues_count":8,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-20T21:04:11.405Z","etag":null,"topics":["efcore","linq","postgres","sql","sql-server","sqlite"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zompinc.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-20T15:20:06.000Z","updated_at":"2025-04-04T13:51:07.000Z","dependencies_parsed_at":"2023-11-21T21:27:56.399Z","dependency_job_id":"28af2442-f04f-4627-a07d-c4361006e907","html_url":"https://github.com/zompinc/efcore-extensions","commit_stats":{"total_commits":36,"total_committers":3,"mean_commits":12.0,"dds":0.05555555555555558,"last_synced_commit":"bf0a6562619a5447b81da44dddd874d49965db6a"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompinc%2Fefcore-extensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompinc%2Fefcore-extensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompinc%2Fefcore-extensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompinc%2Fefcore-extensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zompinc","download_url":"https://codeload.github.com/zompinc/efcore-extensions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254349687,"owners_count":22056395,"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":["efcore","linq","postgres","sql","sql-server","sqlite"],"created_at":"2024-11-19T13:14:13.092Z","updated_at":"2025-05-15T13:33:19.242Z","avatar_url":"https://github.com/zompinc.png","language":"C#","readme":"# Zomp EF Core Extensions\n\n[![Build](https://github.com/zompinc/efcore-extensions/actions/workflows/build.yml/badge.svg)](https://github.com/zompinc/efcore-extensions/actions/workflows/build.yml)\n![Support .NET 6.0, .NET 8.0](https://img.shields.io/badge/dotnet%20version-net6.0,net8.0-blue)\n\nThis repository is home to two packages which extend [Entity Framework Core](https://github.com/dotnet/efcore):\n\n- Zomp.EFCore.WindowFunctions\n- Zomp.EFCore.BinaryFunctions\n\n## Zomp.EFCore.WindowFunctions\n\nProvides Window functions or analytics functions for providers. Currently supported for:\n\n| Provider                                                                                         | Package                                                                                                                                                |\n| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| [SQL Server](https://docs.microsoft.com/en-us/sql/t-sql/queries/select-over-clause-transact-sql) | [![Nuget](https://img.shields.io/nuget/v/Zomp.EFCore.WindowFunctions.SqlServer)](https://www.nuget.org/packages/Zomp.EFCore.WindowFunctions.SqlServer) |\n| [PostgreSQL](https://www.postgresql.org/docs/current/tutorial-window.html)                       | [![Nuget](https://img.shields.io/nuget/v/Zomp.EFCore.WindowFunctions.Npgsql)](https://www.nuget.org/packages/Zomp.EFCore.WindowFunctions.Npgsql)       |\n| [SQLite](https://www.sqlite.org/windowfunctions.html)                                            | [![Nuget](https://img.shields.io/nuget/v/Zomp.EFCore.WindowFunctions.Sqlite)](https://www.nuget.org/packages/Zomp.EFCore.WindowFunctions.Sqlite)       |\n\nWindow functions supported:\n\n- MIN\n- MAX\n- SUM\n- AVG\n- COUNT\n- ROW_NUMBER\n- RANK\n- DENSE_RANK\n- PERCENT_RANK\n- LEAD\n- LAG\n\n### Installation\n\nTo add provider-specific library use:\n\n```sh\ndotnet add package Zomp.EFCore.WindowFunctions.SqlServer\ndotnet add package Zomp.EFCore.WindowFunctions.Npgsql\ndotnet add package Zomp.EFCore.WindowFunctions.Sqlite\n```\n\nTo add provider-agnostic library use:\n\n```sh\ndotnet add package Zomp.EFCore.WindowFunctions\n```\n\nSet up your specific provider to use Window Functions with `DbContextOptionsBuilder.UseWindowFunctions`. For example here is the SQL Server syntax:\n\n```cs\nprotected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\n{\n    optionsBuilder.UseSqlServer(\n        myConn,\n        sqlOptions =\u003e sqlOptions.UseWindowFunctions());\n}\n```\n\n### Basic usage\n\nLINQ query\n\n```cs\nusing var dbContext = new MyDbContext();\nvar query = dbContext.TestRows\n.Select(r =\u003e new\n{\n    Max = EF.Functions.Max(\n        r.Col1,\n        EF.Functions.Over()\n            .OrderBy(r.Col2)),\n});\n```\n\ntranslates into the following SQL on SQL Server:\n\n```sql\nSELECT MAX([t].[Col1]) OVER(ORDER BY [t].[Col2]) AS [Max]\nFROM [TestRows] AS [t]\nORDER BY [t].[Id]\n```\n\n### Advanced usage\n\nThis example shows:\n\n- Partition clause (can be chained)\n- Order by clause\n  - Can me chained\n  - Used in ascending or descending order\n- Range or Rows clause\n\n```cs\nusing var dbContext = new MyDbContext();\nvar query = dbContext.TestRows\n.Select(r =\u003e new\n{\n    Max = EF.Functions.Max(\n        r.Col1,\n        EF.Functions.Over()\n            .PartitionBy(r.Col2).ThenBy(r.Col3)\n            .OrderBy(r.Col4).ThenByDescending(r.Col5)\n                .Rows().FromUnbounded().ToCurrentRow()),\n});\n```\n\n## Zomp.EFCore.BinaryFunctions\n\nProvides Window functions or analytics functions for providers. Currently supported for:\n\n| Provider   | Package                                                                                                                                                |\n| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| SQL Server | [![Nuget](https://img.shields.io/nuget/v/Zomp.EFCore.BinaryFunctions.SqlServer)](https://www.nuget.org/packages/Zomp.EFCore.BinaryFunctions.SqlServer) |\n| PostgreSQL | [![Nuget](https://img.shields.io/nuget/v/Zomp.EFCore.BinaryFunctions.Npgsql)](https://www.nuget.org/packages/Zomp.EFCore.BinaryFunctions.Npgsql)       |\n| SQLite     | [![Nuget](https://img.shields.io/nuget/v/Zomp.EFCore.BinaryFunctions.Sqlite)](https://www.nuget.org/packages/Zomp.EFCore.BinaryFunctions.Sqlite)       |\n\nThe following extension methods are available\n\n- `DbFunctions.GetBytes` - converts an expression into binary expression\n- `DbFunctions.ToValue\u003cT\u003e` - Converts binary expression to type T\n- `DbFunctions.BinaryCast\u003cTFrom, TTo\u003e` - Converts one type to another by taking least significant bytes when overflow occurs.\n- `DbFunctions.Concat` - concatenates two binary expressions\n- `DbFunctions.Substring` - Returns part of a binary expression\n\n### Usage\n\nSet up your specific provider to use Binary Functions with `DbContextOptionsBuilder.UseWindowFunctions`. For example here is the SQL Server syntax:\n\n```cs\nprotected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\n{\n    optionsBuilder.UseSqlServer(\n        myConn,\n        sqlOptions =\u003e sqlOptions.UseBinaryFunctions());\n}\n```\n\nLINQ query\n\n```cs\nusing var dbContext = new MyDbContext();\nvar query = dbContext.TestRows\n    .Select(r =\u003e EF.Functions.GetBytes(r.Id));\n```\n\ntranslates into the following SQL on SQL Server:\n\n```sql\nSELECT CAST([t].[Id] AS binary(4))\nFROM [TestRows] AS [t]\n```\n\n## Applications\n\n### Last non null puzzle\n\nOne problem window functions are solving is displaying last non-null values for a given column / expressions. The problem is described in Itzik Ben-Gan's [article](https://www.itprotoday.com/sql-server/last-non-null-puzzle). Below are 2 effective approaches of solving this issue.\n\n#### Binary approach\n\nSolution 2 of the article above uses both binary functions and window functions. Here is how it can be combined using this library:\n\n```cs\n// Relies on Max over binary.\n// Currently works with SQL Server only.\nvar query = dbContext.TestRows\n.Select(r =\u003e new\n{\n    LastNonNull =\n    EF.Functions.ToValue\u003cint\u003e(\n        EF.Functions.Substring(\n            EF.Functions.Max(\n                EF.Functions.Concat(\n                    EF.Functions.GetBytes(r.Id),\n                    EF.Functions.GetBytes(r.Col1)),\n                EF.Functions.Over().OrderBy(r.Id)),\n            5,\n            4)),\n});\n```\n\nIn case of limitations of combining bytes (SQLite) and window max function on binary data (PostgreSQL) it might be possible to combine columns into 8-bit integer expression(s) and perform max window function on it:\n\n```cs\nvar query = dbContext.TestRows\n.Select(r =\u003e new\n{\n    LastNonNull =\n    EF.Functions.BinaryCast\u003clong, int\u003e(\n        EF.Functions.Max(\n            r.Col1.HasValue ? r.Id * (1L \u003c\u003c 32) | r.Col1.Value \u0026 uint.MaxValue : (long?)null,\n            EF.Functions.Over().OrderBy(r.Id))),\n});\n```\n\n#### LAG approach\n\nStarting with SQL Server 2022 (16.x) it is possible to use LAG with IGNORE NULLS to retrieve last non-null value. Ensure the latest cumulative update is applied due to a [bug fix](https://learn.microsoft.com/en-us/troubleshoot/sql/releases/sqlserver-2022/cumulativeupdate4#2278800).\n\nUse the following expression:\n\n```cs\nExpression\u003cFunc\u003cTestRow, int?\u003e\u003e lastNonNullExpr = r =\u003e EF.Functions.Lag(r.Col1, 0, NullHandling.IgnoreNulls, EF.Functions.Over().OrderBy(r.Id)\n```\n\nMore SQL Server related information on the LAG function here available [here](https://learn.microsoft.com/en-us/sql/t-sql/functions/lead-transact-sql?view=sql-server-ver16#-ignore-nulls--respect-nulls-).\n\nNote: PostgreSQL and SQLite don't support RESPECT NULLS / IGNORE NULLS at this time.\n\n## Examples\n\nSee the\n\n- Zomp.EFCore.WindowFunctions.Testing\n- Zomp.EFCore.BinaryFunctions.Testing\n- Zomp.EFCore.Combined.Testing\n\nprojects for more examples.\n","funding_links":[],"categories":["C# #"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzompinc%2Fefcore-extensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzompinc%2Fefcore-extensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzompinc%2Fefcore-extensions/lists"}