{"id":22886387,"url":"https://github.com/baune8d/linqbuilder","last_synced_at":"2025-04-05T23:09:25.166Z","repository":{"id":65413848,"uuid":"97414152","full_name":"Baune8D/LinqBuilder","owner":"Baune8D","description":"LinqBuilder is an advanced implementation of the specification pattern specifically targeting LINQ query generation.","archived":false,"fork":false,"pushed_at":"2024-12-30T20:35:03.000Z","size":451,"stargazers_count":34,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-29T22:07:43.786Z","etag":null,"topics":["csharp","dotnet","dotnet-core","dotnet-standard","dotnet5","dotnet6","entity-framework","entity-framework-core","linq","specification-pattern"],"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/Baune8D.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2017-07-16T22:08:12.000Z","updated_at":"2025-01-19T13:52:37.000Z","dependencies_parsed_at":"2024-05-05T21:30:27.683Z","dependency_job_id":"08a9b04a-1613-4447-b349-98cdb9c12914","html_url":"https://github.com/Baune8D/LinqBuilder","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Baune8D%2FLinqBuilder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Baune8D%2FLinqBuilder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Baune8D%2FLinqBuilder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Baune8D%2FLinqBuilder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Baune8D","download_url":"https://codeload.github.com/Baune8D/LinqBuilder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247411235,"owners_count":20934653,"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":["csharp","dotnet","dotnet-core","dotnet-standard","dotnet5","dotnet6","entity-framework","entity-framework-core","linq","specification-pattern"],"created_at":"2024-12-13T20:18:29.650Z","updated_at":"2025-04-05T23:09:25.145Z","avatar_url":"https://github.com/Baune8D.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LinqBuilder\n[![Build status](https://ci.appveyor.com/api/projects/status/v0t8rfsv0d4q3hap?svg=true)](https://ci.appveyor.com/project/Baune8D/linqbuilder)\n[![codecov](https://codecov.io/gh/Baune8D/linqbuilder/branch/main/graph/badge.svg)](https://codecov.io/gh/Baune8D/linqbuilder)\n[![NuGet Badge](https://buildstats.info/nuget/LinqBuilder)](https://www.nuget.org/packages/LinqBuilder)\n\n**Available on NuGet:** [https://www.nuget.org/packages/LinqBuilder/](https://www.nuget.org/packages/LinqBuilder/)  \n**MyGet development feed:** [https://www.myget.org/F/baunegaard/api/v3/index.json](https://www.myget.org/F/baunegaard/api/v3/index.json)  \n\nLinqBuilder is based on the specification pattern.\n\n## Table of Contents\n1. [LinqBuilder Specifications](#linqbuilder-specifications)\n2. [LinqBuilder OrderSpecifications](#linqbuilder-orderspecifications)\n3. [LinqBuilder.EFCore / LinqBuilder.EF6](#linqbuilderefcore--linqbuilderef6)\n4. [Full Example](#full-example)\n\n## LinqBuilder Specifications\n\n### Usage\nSpecifications can be constructed in three different ways.\n\n**By extending Specification:**\n```csharp\npublic class FirstnameIsFoo : Specification\u003cPerson\u003e\n{\n    public override Expression\u003cFunc\u003cPerson, bool\u003e\u003e AsExpression()\n    {\n        return person =\u003e person.Firstname == \"Foo\";\n    }\n}\n\nISpecification\u003cPerson\u003e firstnameIsFoo = new FirstnameIsFoo();\n```\n\n**By extending DynamicSpecification:**\n```csharp\npublic class FirstnameIs : DynamicSpecification\u003cPerson, string\u003e\n{\n    public override Expression\u003cFunc\u003cPerson, bool\u003e\u003e AsExpression()\n    {\n        return person =\u003e person.Firstname == Value;\n    }\n}\n\nISpecification\u003cPerson\u003e firstnameIsFoo = new FirstnameIs().Set(\"Foo\");\n```\n\n**By extending MultiSpecification:**\n```csharp\npublic class FirstnameIsFoo : MultiSpecification\u003cPerson, OtherPerson\u003e\n{\n    public override Expression\u003cFunc\u003cPerson, bool\u003e\u003e AsExpressionForEntity1()\n    {\n        return person =\u003e person.Firstname == \"Foo\";\n    }\n\n    public override Expression\u003cFunc\u003cOtherPerson, bool\u003e\u003e AsExpressionForEntity2()\n    {\n        return person =\u003e person.Firstname == \"Foo\";\n    }\n}\n\nISpecification\u003cPerson\u003e firstnameIsFoo = new FirstnameIsFoo(); // First generic is default\nISpecification\u003cPerson\u003e firstnameIsFoo = new FirstnameIsFoo().For\u003cPerson\u003e();\nISpecification\u003cOtherPerson\u003e firstnameIsFoo = new FirstnameIsFoo().For\u003cOtherPerson\u003e();\n```\n\n**By static New method:**\n```csharp\nISpecification\u003cPerson\u003e firstnameIsFoo = Specification\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Foo\");\n// Or by alias\nISpecification\u003cPerson\u003e firstnameIsFoo = Spec\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Foo\");\n```\n\n### Example\n```csharp\nvar collection = new List\u003cPerson\u003e() { ... };\n\nISpecification\u003cPerson\u003e firstnameIsFoo = Spec\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Foo\");\nISpecification\u003cPerson\u003e firstnameIsBar = Spec\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Bar\");\n\nISpecification\u003cEntity\u003e specification = firstnameIsFoo.Or(firstnameIsBar);\n\nvar result = collection.ExeSpec(specification).ToList();\n// result = Collection items satisfied by specification\n```\nThe extension ```ExeSpec``` allows all types of ```ISpecification``` to be executed on ```IQueryable``` and ```IEnumerable```.\n\n### Methods\n```csharp\nISpecification\u003cEntity\u003e specification = Spec\u003cEntity\u003e.All(\n    new SomeSpecification(),\n    new SomeOtherSpecification(),\n    ...\n);\n\nISpecification\u003cEntity\u003e specification = Spec\u003cEntity\u003e.None(\n    new SomeSpecification(),\n    new SomeOtherSpecification(),\n    ...\n);\n\nISpecification\u003cEntity\u003e specification = Spec\u003cEntity\u003e.Any(\n    new SomeSpecification(),\n    new SomeOtherSpecification(),\n    ...\n);\n```\n\n### Extensions\n```csharp\nISpecification\u003cTEntity\u003e And\u003cTEntity\u003e(this ISpecification\u003cTEntity\u003e left, ISpecification\u003cTEntity\u003e right);\nISpecification\u003cTEntity\u003e Or\u003cTEntity\u003e(this ISpecification\u003cTEntity\u003e left, ISpecification\u003cTEntity\u003e right);\nISpecification\u003cTEntity\u003e Not\u003cTEntity\u003e(this ISpecification\u003cTEntity\u003e specification);\nbool IsSatisfiedBy\u003cTEntity\u003e(this ISpecification\u003cTEntity\u003e specification, TEntity entity);\nISpecification\u003cTEntity\u003e Clone\u003cTEntity\u003e(this ISpecification\u003cTEntity\u003e specification);\n```\n\n**LinqBuilder** also extends the following extensions to support ```ISpecification``` on ```IQueryable``` and ```IEnumerable```.\n```csharp\nIEnumerable\u003cEntity\u003e collection = collection.Where(specification);\nbool result = collection.Any(specification);\nbool result = collection.All(specification);\nint result = collection.Count(specification);\nEntity result = collection.First(specification);\nEntity result = collection.FirstOrDefault(specification);\nEntity result = collection.Single(specification);\nEntity result = collection.SingleOrDefault(specification);\n```\n\n## LinqBuilder OrderSpecifications\n\n### Usage\nOrder specifications can be constructed in almost the same way as regular specifications.\n\n**By extending OrderSpecification:**\n```csharp\npublic class FirstnameDescending : OrderSpecification\u003cPerson, string\u003e\n{\n    public DescNumberOrderSpecification() : base(Sort.Descending) { }\n\n    public override Expression\u003cFunc\u003cPerson, string\u003e\u003e AsExpression()\n    {\n        return person =\u003e person.Firstname;\n    }\n}\n\nISpecification\u003cPerson\u003e firstnameDescending = new FirstnameDescending();\n```\n\n**By static New method:**\n```csharp\nISpecification\u003cPerson\u003e firstnameDescending = OrderSpecification\u003cPerson, string\u003e.New(p =\u003e p.Firstname, Sort.Descending);\n// Or by alias\nISpecification\u003cPerson\u003e firstnameDescending = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Firstname, Sort.Descending);\n```\n\n### Example\n```csharp\nvar collection = new List\u003cPerson\u003e() { ... };\n\nISpecification\u003cPerson\u003e firstnameDescending = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Firstname, Sort.Descending);\nISpecification\u003cPerson\u003e lastnameDescending = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Lastname, Sort.Descending);\n\nISpecification\u003cPerson\u003e specification = firstnameDescending.ThenBy(lastnameDescending);\n\nvar result = collection.ExeSpec(specification).ToList();\n// result = Collection ordered by descending number, then by other number\n```\n\n### Methods\n```csharp\nISpecification\u003cPerson\u003e specification = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Firstname)\n    .Take(10);\n\nISpecification\u003cPerson\u003e specification = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Firstname)\n    .Skip(5);\n\nISpecification\u003cPerson\u003e specification = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Firstname)\n    .Paginate(2, 10); // Equals .Skip((2 - 1) * 10).Take(10)\n```\n\n### Extensions\n```csharp\nIOrderedEnumerable\u003cEntity\u003e collection = collection\n    .OrderBy(specification);\n    .ThenBy(otherSpecification);\n```\n\nOrder specifications can also be chained with regular LinqBuilder specifications.\n```csharp\nISpecification\u003cPerson\u003e firstnameIsFoo = Spec\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Foo\");\nISpecification\u003cPerson\u003e firstnameAscending = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Firstname);\n\nISpecification\u003cEntity\u003e specification = firstnameIsFoo.OrderBy(firstnameAscending);\n```\n\nChained ```OrderSpecification```'s can also be attatched to a specification later.\n```csharp\nISpecification\u003cPerson\u003e firstnameIsFoo = Spec\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Foo\");\nISpecification\u003cPerson\u003e firstnameAscending = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Firstname);\nISpecification\u003cPerson\u003e lastnameAscending = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Firstname);\n\nISpecification\u003cPerson\u003e orderSpecification = firstnameAscending.ThenBy(lastnameAscending);\n\nISpecification\u003cPerson\u003e specification = firstnameIsFoo.UseOrdering(orderSpecification);\n```\n\nThe following extensions will help to check what kind of ordering is applied.\n```csharp\nISpecification\u003cPerson\u003e firstnameIsFoo = Spec\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Foo\");\nISpecification\u003cPerson\u003e firstnameAscending = OrderSpec\u003cPerson, string\u003e.New(p =\u003e p.Firstname);\n\nfirstnameIsFoo.IsOrdered(); // Returns false\n\nISpecification\u003cPerson\u003e specification = firstnameIsFoo.OrderBy(firstnameAscending);\nspecification.IsOrdered(); // Returns true\n```\n```csharp\nISpecification\u003cPerson\u003e specification = Spec\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Foo\");\nspecification.HasSkip(); // Returns false\n\nISpecification\u003cPerson\u003e specification = specification.Skip(10);\nspecification.HasSkip(); // Returns true\n```\n```csharp\nISpecification\u003cPerson\u003e specification = Spec\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Foo\");\nspecification.HasTake(); // Returns false\n\nISpecification\u003cPerson\u003e specification = specification.Take(10);\nspecification.HasTake(); // Returns true\n```\n\n## LinqBuilder.EFCore / LinqBuilder.EF6\n| Package            | Version                                                                                                               |\n| -------------------|:---------------------------------------------------------------------------------------------------------------------:|\n| LinqBuilder.EFCore | [![NuGet Badge](https://buildstats.info/nuget/LinqBuilder.EFCore)](https://www.nuget.org/packages/LinqBuilder.EFCore) |\n| LinqBuilder.EF6    | [![NuGet Badge](https://buildstats.info/nuget/LinqBuilder.EF6)](https://www.nuget.org/packages/LinqBuilder.EF6)       |\n\n### Extensions\n**LinqBuilder.EF** packages extends the following extensions to support ```ISpecification```.\n```csharp\nbool result = await _sampleContext.Entities.AnyAsync(specification);\nbool result = await _sampleContext.Entities.AllAsync(specification);\nint result = await _sampleContext.Entities.CountAsync(specification);\nEntity result = await _sampleContext.Entities.FirstAsync(specification);\nEntity result = await _sampleContext.Entities.FirstOrDefaultAsync(specification);\nEntity result = await _sampleContext.Entities.SingleAsync(specification);\nEntity result = await _sampleContext.Entities.SingleOrDefaultAsync(specification);\n```\n\n## Full example\n\n```csharp\npublic class Person\n{\n    public int Id { get; set; }\n    public string Firstname { get; set; }\n    public string Lastname { get; set; }\n}\n\npublic class SampleDbContext : DbContext // Simplified DbContext\n{\n    public virtual DbSet\u003cPerson\u003e Persons { get; set; }\n}\n\npublic class DbService\u003cTEntity\u003e where TEntity : class\n{\n    private readonly DbSet\u003cTEntity\u003e _dbSet;\n\n    public DbService(SampleDbContext context)\n    {\n        _dbSet = context.Set\u003cTEntity\u003e();\n    }\n\n    public int Count(ISpecification\u003cTEntity\u003e specification)\n    {\n        return _dbSet.Count(specification);\n    }\n\n    public List\u003cEntity\u003e Get(ISpecification\u003cTEntity\u003e specification)\n    {\n        return _dbSet.ExeSpec(specification).ToList();\n    }\n\n    public (List\u003cPerson\u003e items, int count) GetAndCount(ISpecification\u003cTEntity\u003e specification)\n    {\n        return (Get(specification), Count(specification));\n    }\n}\n\nISpecification\u003cPerson\u003e firstnameIsFoo = Spec\u003cPerson\u003e.New(p =\u003e p.Firstname == \"Foo\");\nISpecification\u003cPerson\u003e lastnameIsBar = Spec\u003cPerson\u003e.New(p =\u003e p.Lastname == \"Bar\");\nISpecification\u003cPerson\u003e idDescending = OrderSpec\u003cPerson, int\u003e.New(p =\u003e p.Id, Sort.Descending);\n\nISpecification\u003cPerson\u003e specification = firstnameIsFoo.And(lastnameIsBar)\n    .OrderBy(idDescending)\n    .Paginate(1, 5); // pageNo = 1, pageSize = 5\n\nusing (var context = new SampleDbContext())\n{\n    var result = new DbService\u003cPerson\u003e(context).GetAndCount(specification);\n    // result.items = Paginated list of Person's with name: Foo Bar\n    // result.count = Total unpaginated result count\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaune8d%2Flinqbuilder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbaune8d%2Flinqbuilder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaune8d%2Flinqbuilder/lists"}