{"id":23878314,"url":"https://github.com/jscarle/generatedentityframework","last_synced_at":"2025-09-09T04:32:42.480Z","repository":{"id":223539623,"uuid":"760640522","full_name":"jscarle/GeneratedEntityFramework","owner":"jscarle","description":"Generated interface implementations for Entity Framework Core.","archived":false,"fork":false,"pushed_at":"2024-07-15T15:10:16.000Z","size":280,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-08T17:48:37.259Z","etag":null,"topics":["clean-architecture","csharp","dotnet","entity-framework","entity-framework-core","source-generator","vertical-slice-architecture"],"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/jscarle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","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},"funding":{"github":"jscarle"}},"created_at":"2024-02-20T17:02:34.000Z","updated_at":"2024-09-23T12:35:31.000Z","dependencies_parsed_at":"2024-02-20T19:47:41.145Z","dependency_job_id":"31c3287b-5547-4017-990f-864b25d8a75d","html_url":"https://github.com/jscarle/GeneratedEntityFramework","commit_stats":null,"previous_names":["jscarle/generatedentityframework"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jscarle%2FGeneratedEntityFramework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jscarle%2FGeneratedEntityFramework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jscarle%2FGeneratedEntityFramework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jscarle%2FGeneratedEntityFramework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jscarle","download_url":"https://codeload.github.com/jscarle/GeneratedEntityFramework/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232395326,"owners_count":18516612,"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":["clean-architecture","csharp","dotnet","entity-framework","entity-framework-core","source-generator","vertical-slice-architecture"],"created_at":"2025-01-03T21:19:28.724Z","updated_at":"2025-01-03T21:19:29.351Z","avatar_url":"https://github.com/jscarle.png","language":"C#","readme":"[![Banner](https://raw.githubusercontent.com/jscarle/GeneratedEntityFramework/main/Banner.png)](https://github.com/jscarle/GeneratedEntityFramework)\n\n# GeneratedEntityFramework - Generated interface implementations for Entity Framework Core\n\nGeneratedEntityFramework is a.NET source generator that automatically generates the `DbSet` implementations for a\n`DbContext` based on the properties of an interface. This greatly facilitates integration of Entity Framework within a\nClean Architecture (CA) or a Vertical Slice Architecture (VSA) by segmenting one or more DbContexts into one or more\ninterfaces.\n\n[![main](https://img.shields.io/github/actions/workflow/status/jscarle/GeneratedEntityFramework/main.yml?logo=github)](https://github.com/jscarle/GeneratedEntityFramework)\n[![nuget](https://img.shields.io/nuget/v/GeneratedEntityFramework)](https://www.nuget.org/packages/GeneratedEntityFramework)\n[![downloads](https://img.shields.io/nuget/dt/GeneratedEntityFramework)](https://www.nuget.org/packages/GeneratedEntityFramework)\n\n## Requirements\n\nThis source generator will generate source that is only compatible with\n[EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) and Microsoft's\n[Dependency Injection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection) abstraction.\n\n## Getting Started\n\n### The Basics\n\nUsually, a [DbContext](https://learn.microsoft.com/en-us/ef/core/#the-model) will contain or more DbSets:\n\n```csharp\npublic class BloggingContext : DbContext\n{\n    public DbSet\u003cBlog\u003e Blogs { get; set; }\n    public DbSet\u003cPost\u003e Posts { get; set; }\n}\n```\n\nIn a typical Clean Architecture project, those DbSets are often presented to the\napplication [as an interface](https://github.com/jasontaylordev/CleanArchitecture/blob/cea275b3c5716fd48e1aaeda231f041f837e9be2/src/Application/Common/Interfaces/IApplicationDbContext.cs):\n\n```csharp\npublic class BloggingContext : DbContext, IBloggingContext\n{\n    public DbSet\u003cBlog\u003e Blogs { get; set; }\n    public DbSet\u003cPost\u003e Posts { get; set; }\n}\n\npublic interface IBloggingContext\n{\n    public DbSet\u003cBlog\u003e Blogs { get; }\n    public DbSet\u003cPost\u003e Posts { get; }\n}\n```\n\nKeeping both the DbContext and the interface up to date with each other can quickly become tedious as each\nDbSet added to the interface must also be duplicated by hand in the DbContext and vice versa.\n[GeneratedEntityFramework](https://github.com/jscarle/GeneratedEntityFramework)'s source generator solves this\nby source generating a `partial` implementation of the DbContext based on it's association with one or more\ninterfaces.\n\n### How to use the source generator\n\nThe are three different ways for the source generator to detect which implementations to generate for the DbContext.\n\n#### Inheriting from the interface\n\nIf the DbContext is marked with the `GeneratedDbContext` attribute, it will generate the implementations for all\nof the inherited interfaces.\n\n```csharp\n[GeneratedDbContext]\npublic partial class BloggingContext : DbContext, IBloggingContext\n{\n}\n\npublic interface IBloggingContext\n{\n    public DbSet\u003cBlog\u003e Blogs { get; }\n    public DbSet\u003cPost\u003e Posts { get; }\n}\n```\n\n#### Specifying the interface\n\nIf the DbContext is marked with the `GeneratedDbContext` attribute and the interface is specified as the constructor\nparameter, it will generate the implementations for the specified interface and automatically add the interface as\nan inherited interface to the partial DbContext.\n\n```csharp\n[GeneratedDbContext\u003cIBloggingContext\u003e]\npublic partial class BloggingContext : DbContext\n{\n}\n\npublic interface IBloggingContext\n{\n    public DbSet\u003cBlog\u003e Blogs { get; }\n    public DbSet\u003cPost\u003e Posts { get; }\n}\n```\n\n#### Specifying the DbContext\n\nIf the interface is marked with the `DbContext` attribute and the DbContext is specified as the constructor\nparameter, it will generate the implementations for the specified interface and automatically add the interface as\nan inherited interface to the partial DbContext.\n\n```csharp\npublic partial class BloggingContext : DbContext\n{\n}\n\n[DbContext\u003cBloggingContext\u003e]\npublic interface IBloggingContext\n{\n    public DbSet\u003cBlog\u003e Blogs { get; }\n    public DbSet\u003cPost\u003e Posts { get; }\n}\n```\n\n### Notes about the attributes\n\nGeneric attributes are available from .NET 7.0 onwards, in order to use the `GeneratedDbContext` and `DbContext`\nattributes with .NET 6.0 and prior, simply use the constructor with a `typeof` value of the interface or DbContext\nas follows:\n\n```csharp\n[GeneratedDbContext(typeof(IBloggingContext))]\npublic partial class BloggingContext : DbContext { }\n\n[DbContext(typeof(BloggingContext))]\npublic interface IBloggingContext { }\n```\n\nThe `GeneratedDbContext` and `DbContext` attributes can be used multiple times in any combinations, the source generator\nwill automatically eliminate any duplication and redundancies. This is incredibly useful for Vertical Sliced Architecture\n(VSA) as this allows different slices to define segmented interfaces while merging of all the implementations over a single\nDbContext. For example, the following will produce a single implementation of each of the DbSets on the DbContext:\n\n```csharp\n[GeneratedDbContext\u003cIBloggingContext\u003e]\n[GeneratedDbContext\u003cIBlogsContext\u003e]\n[GeneratedDbContext\u003cIPostsContext\u003e]\npublic partial class BloggingContext : DbContext\n{\n}\n\n[DbContext\u003cBloggingContext\u003e]\npublic interface IBloggingContext\n{\n    public DbSet\u003cBlog\u003e Blogs { get; }\n    public DbSet\u003cPost\u003e Posts { get; }\n}\n\n\n[DbContext\u003cBloggingContext\u003e]\npublic interface IBlogsContext\n{\n    public DbSet\u003cBlog\u003e Blogs { get; }\n}\n\n\n[DbContext\u003cBloggingContext\u003e]\npublic interface IPostsContext\n{\n    public DbSet\u003cPost\u003e Posts { get; }\n}\n```\n\n### IQueryable properties\n\nOne of the issues with specifying `DbSet` in the interface is that it creates high coupling with Entity Framework and\nnegates the benefits of using an abstraction to access the database. As an alternative, if the interface specifies an\n`IQueryable` property instead of a `DbSet` one, then a private DbSet property will be generated as a backing field\nwithin the DbContext. Thus, the following:\n\n```csharp\n[GeneratedDbContext\u003cIBloggingContext\u003e]\npublic partial class BloggingContext : DbContext\n{\n}\n\npublic interface IBloggingContext\n{\n    public IQueryable\u003cBlog\u003e Blogs { get; }\n    public IQueryable\u003cPost\u003e Posts { get; }\n}\n```\n\nWould generate the following partial DbContext:\n\n```csharp\npublic partial class BloggingContext : IBloggingContext\n{\n    private DbSet\u003cBlog\u003e DbSet__Blogs { get; set; } = default!;\n    public IQueryable\u003cBlog\u003e Blogs =\u003e DbSet__Blogs;\n\n    private DbSet\u003cPost\u003e DbSet__Posts { get; set; } = default!;\n    public IQueryable\u003cPost\u003e Posts =\u003e DbSet__Posts;\n}\n```\n\nIf a `DbSet` exists on the interface for the same entity type as the `IQueryable`, that will be used instead of\ncreating a backing field. This allows both DbSet and IQueryable properties to be combined as needed like so:\n\n```csharp\n[GeneratedDbContext\u003cIBloggingContext\u003e]\npublic partial class BloggingContext : DbContext\n{\n}\n\npublic interface IBloggingContext\n{\n    public DbSet\u003cBlog\u003e BlogsDbSet { get; }\n    public IQueryable\u003cBlog\u003e Blogs { get; }\n}\n```\n\nWould instead generate the following partial DbContext:\n\n```csharp\npublic partial class BloggingContext : IBloggingContext\n{\n    public DbSet\u003cBlog\u003e BlogsDbSet { get; set; } = default!;\n    public IQueryable\u003cBlog\u003e Blogs =\u003e BlogsDbSet;\n}\n```\n\n### AsNoTracking on IQueryable properties\n\nThe `AsNoTracking` attribute can be added to `IQueryable` properties and `.AsNoTracking()` will added to the implementation.\n\n```csharp\n[GeneratedDbContext\u003cIBloggingContext\u003e]\npublic partial class BloggingContext : DbContext\n{\n}\n\npublic interface IBloggingContext\n{\n    public DbSet\u003cBlog\u003e BlogsDbSet { get; }\n\n    [AsNoTracking]\n    public IQueryable\u003cBlog\u003e Blogs { get; }\n}\n```\n\nWill generate the following partial DbContext:\n\n```csharp\npublic partial class BloggingContext : IBloggingContext\n{\n    public DbSet\u003cBlog\u003e BlogsDbSet { get; set; } = default!;\n    public IQueryable\u003cBlog\u003e Blogs =\u003e BlogsDbSet.AsNoTracking();\n}\n```\n\n### Registering the interfaces\n\nIn the `GeneratedEntityFramework` namespace, an extension method named `AddDbContextInterfaces` is added which can be used\nwith the `IServiceCollection` to register all of the interfaces against their respective DbContexts.\n\n```csharp\npublic static void AddDbContextInterfaces(this IServiceCollection services)\n{\n    services.AddScoped\u003cIBlogsContext\u003e(sp =\u003e sp.GetRequiredService\u003cBloggingContext\u003e());\n    services.AddScoped\u003cIPostsContext\u003e(sp =\u003e sp.GetRequiredService\u003cBloggingContext\u003e());\n}\n```\n\nWith a host builder, simply call the extension method on the service collection.\n\n```csharp\nbuilder.Services.AddDbContextInterfaces();\n```\n\nBy default, the service lifetime is the same as the Entity Framework default of Scoped. To specify a different service lifetime,\nadd the `DbContextInterfaceLifetime` attribute to the DbContext and any associated interfaces will be registered with the\nspecified lifetime.\n\n```csharp\n[GeneratedDbContext\u003cIBloggingContext\u003e]\n[DbContextInterfaceLifetime(ServiceLifetime.Transient)]\npublic partial class BloggingContext : DbContext\n{\n}\n```\n","funding_links":["https://github.com/sponsors/jscarle"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjscarle%2Fgeneratedentityframework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjscarle%2Fgeneratedentityframework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjscarle%2Fgeneratedentityframework/lists"}