{"id":31834846,"url":"https://github.com/dasync/entityframeworkcore.extensions.projections","last_synced_at":"2025-10-12T00:28:56.902Z","repository":{"id":94891817,"uuid":"160074326","full_name":"Dasync/EntityFrameworkCore.Extensions.Projections","owner":"Dasync","description":"Extension for EFCore that decouples the read model from entities themselves","archived":false,"fork":false,"pushed_at":"2018-12-15T04:26:43.000Z","size":288,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-05-04T10:39:23.651Z","etag":null,"topics":["api","c-sharp","cqrs","database","ddd","domain-driven-design","dotnet-core","ef-core","entity-framework","extension","json","orm","projection","projection-mapping","read-model","serialization","view","view-model"],"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/Dasync.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":"2018-12-02T17:55:34.000Z","updated_at":"2024-01-03T18:49:11.000Z","dependencies_parsed_at":"2023-03-24T03:04:50.777Z","dependency_job_id":null,"html_url":"https://github.com/Dasync/EntityFrameworkCore.Extensions.Projections","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Dasync/EntityFrameworkCore.Extensions.Projections","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dasync%2FEntityFrameworkCore.Extensions.Projections","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dasync%2FEntityFrameworkCore.Extensions.Projections/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dasync%2FEntityFrameworkCore.Extensions.Projections/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dasync%2FEntityFrameworkCore.Extensions.Projections/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dasync","download_url":"https://codeload.github.com/Dasync/EntityFrameworkCore.Extensions.Projections/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dasync%2FEntityFrameworkCore.Extensions.Projections/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279009508,"owners_count":26084609,"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","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["api","c-sharp","cqrs","database","ddd","domain-driven-design","dotnet-core","ef-core","entity-framework","extension","json","orm","projection","projection-mapping","read-model","serialization","view","view-model"],"created_at":"2025-10-12T00:28:53.756Z","updated_at":"2025-10-12T00:28:56.896Z","avatar_url":"https://github.com/Dasync.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e _A small weekend project with a higher future purpose_\n\n![Domain Entity Projections](FeaturedImage.png)\n\nThis extension to the EntityFramework Core allows to decouple the read model from entities themselves. If you practice Domain-Driven Design, then you want to separate Domain Entity/Aggregate repositories from their querying mechanism. Query results must return Entity Projections/Views instead of Entities themselves (as they contain behavior), but building projection types by hand is tedious.\n\nThe full description is published in the [Domain Entity Projections in EFCore](https://medium.com/@sergiis/domain-entity-projections-in-efcore-2dbd6a9116ff) post. \n\n## Example\n\nThis is a Domain Entity that contains behaviors and implements a projection interface (as a contract) defined below.\n\n```csharp\npublic class City : ICityProjection\n{\n    public string Name { get; private set; }\n\n    public string State { get; private set; }\n\n    public long Population { get; private set; }\n\n    public int TimeZone { get; private set; }\n\n    public void SwitchToSummerTime()\n    {\n        TimeZone += 1;\n    }\n}\n```\nA sample projection interface. An entity can have implement multiple projection interfaces.\n```csharp\npublic interface ICityProjection\n{\n    string Name { get; }\n\n    string State { get; }\n\n    long Population { get; }\n}\n```\n\nJust use the `HasProjections` extension method on the desired entity(-ies). That will automatically find all interfaces with get-only properties.\n\n```csharp\nusing Dasync.EntityFrameworkCore.Extensions.Projections;\n\npublic class SampleDbContext : DbContext\n{\n    protected override void OnModelCreating(ModelBuilder modelBuilder)\n    {\n        modelBuilder.Entity\u003cCity\u003e(e =\u003e\n        {\n            // Declare that this entity has projection interfaces.\n            e.HasProjections();\n        });\n    }\n}\n```\n\nTime to query entities using their projection.\n\n```csharp\nvar smallCities = await dbContext\n    .Set\u003cICityProjection\u003e() // Query directly on the projection interface\n    .Where(c =\u003e c.Population \u003c 1_000_000)\n    .ToListAsync();\n```\n\nNote that the result set does not contain instances of the original `City` entity type. Instead, this extension library generates types at runtime that implement given projection interfaces.\n\nThen you can safely serialize your result set as it represents projections but not entities with behavior. Useful for API methods.\n\n```csharp\nvar json = JsonConvert.SerializeObject(smallCities);\n```\n\nDeserialization back can be done without involving entities as well (visit the '[samples](samples)' folder to see how `EntityProjectionJsonConverter` is implemented).\n\n```csharp\nvar cityProjections = JsonConvert.DeserializeObject\u003cList\u003cICityProjection\u003e\u003e(\n    json, EntityProjectionJsonConverter.Instance);\n```\n\n## How to start\n\nSee the '[samples](samples)' folder, but in a nutshell:\n\n1. Add [Dasync.EntityFrameworkCore.Extensions.Projections NuGet Package](https://www.nuget.org/packages/Dasync.EntityFrameworkCore.Extensions.Projections) to your app\n1. Define projection interfaces and implement them on your entities\n1. Add `using Dasync.EntityFrameworkCore.Extensions.Projections;` to your code\n1. Use `HasProjections` extension method on entities while building your DbContext model\n1. Query with projection interfaces as shown above\n1. Serialize projections at the API layer\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdasync%2Fentityframeworkcore.extensions.projections","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdasync%2Fentityframeworkcore.extensions.projections","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdasync%2Fentityframeworkcore.extensions.projections/lists"}