├── Nuget ├── PredicateExtensions.1.0.0.nupkg ├── PredicateExtensions.Source.1.0.0.nupkg ├── PredicateExtensionsSource.1.0.0.nuspec └── PredicateExtensions.nuspec ├── PredicateExtensions.Tests ├── Resources │ ├── BloggingContext.cs │ ├── Blog.cs │ ├── Post.cs │ └── BlogStub.cs ├── packages.config ├── App.config ├── Properties │ └── AssemblyInfo.cs ├── PredicateExtensions.Tests.csproj ├── ExtensionTests.cs └── EfExtensionTests.cs ├── .gitattributes ├── readme.md ├── LICENSE.md ├── PredicateExtensions ├── Properties │ └── AssemblyInfo.cs ├── PredicateExtensions.csproj └── PredicateExtensions.cs ├── PredicateExtensions.sln └── .gitignore /Nuget/PredicateExtensions.1.0.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdCharbeneau/PredicateExtensions/HEAD/Nuget/PredicateExtensions.1.0.0.nupkg -------------------------------------------------------------------------------- /Nuget/PredicateExtensions.Source.1.0.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdCharbeneau/PredicateExtensions/HEAD/Nuget/PredicateExtensions.Source.1.0.0.nupkg -------------------------------------------------------------------------------- /PredicateExtensions.Tests/Resources/BloggingContext.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Entity; 2 | namespace PredicateExtensions.Tests 3 | { 4 | public class BloggingContext : DbContext 5 | { 6 | public DbSet Blogs { get; set; } 7 | 8 | public DbSet Posts { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /PredicateExtensions.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /PredicateExtensions.Tests/Resources/Blog.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace PredicateExtensions.Tests 4 | { 5 | public class Blog 6 | { 7 | public int BlogId { get; set; } 8 | 9 | public string Name { get; set; } 10 | 11 | public virtual List Posts { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /PredicateExtensions.Tests/Resources/Post.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PredicateExtensions.Tests 8 | { 9 | public class Post 10 | { 11 | public int PostId { get; set; } 12 | public string Title { get; set; } 13 | public string Content { get; set; } 14 | 15 | public int BlogId { get; set; } 16 | public virtual Blog Blog { get; set; } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /PredicateExtensions.Tests/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # PredicateExtensions 2 | 3 | PredicateExtensions is a C# utility that will take two Lambda expressions and combine them using .And or .Or extension methods. Expressions be joined at runtime for dynamic LINQ queries. PredicateExtensions can be used with EntityFramework to refactor and create dynamic queries. 4 | 5 | 6 | ##Example 7 | Expression> equalsA = str => str == "A"; 8 | Expression> equalsB = str => str == "B"; 9 | 10 | IQueryable myValues = {"A", "B", "C", "D" }; 11 | myValues.Where(equalsA.Or(equalsB)); //"A", "B" 12 | 13 | 14 | **For more information see:** [Giving Clarity to LINQ Queries by Extending Expressions](https://www.simple-talk.com/dotnet/.net-framework/giving-clarity-to-linq-queries-by-extending-expressions/) 15 | -------------------------------------------------------------------------------- /PredicateExtensions.Tests/Resources/BlogStub.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PredicateExtensions.Tests 8 | { 9 | public class BlogStub 10 | { 11 | public IQueryable GetPosts() 12 | { 13 | //arrange 14 | Post[] posts = 15 | { 16 | new Post { Title = "First Post", Content = "Lorem Ipsum" }, 17 | new Post { Title = "Second Post", Content = "Lorem Ipsum" }, 18 | new Post { Title = "Third Post", Content = "keyword" }, 19 | new Post { Title = "Fourth Post", Content = "Lorem Ipsum" } 20 | }; 21 | 22 | // The IQueryable data to query. 23 | return posts.AsQueryable(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | PredicateExpressions is open source and MIT Licensed. (just in case you're paraniod, here it is) 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Nuget/PredicateExtensionsSource.1.0.0.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PredicateExtensions.Source 5 | 1.0.0 6 | Ed Charbeneau 7 | Ed Charbeneau 8 | https://github.com/EdCharbeneau/PredicateExtensions 9 | false 10 | This package adds the PredicateExtensions source directly to your project. For the full project, including tests, download the project from github. 11 | This package adds the PredicateExtensions source directly to your project. For the full project, including tests, download the project from github. 12 | Initial release 13 | MIT License 14 | LINQ, EntityFramework, ExpressionTree, predicate, Where 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Nuget/PredicateExtensions.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PredicateExtensions 5 | 1.0.0 6 | Ed Charbeneau 7 | Ed Charbeneau 8 | https://github.com/EdCharbeneau/PredicateExtensions 9 | false 10 | PredicateExtensions is a C# utility that will take two Lambda expressions and combine them using .And or .Or extension methods. Expressions be joined at runtime for dynamic LINQ queries. PredicateExtensions can be used with EntityFramework to refactor and create dynamic queries. 11 | PredicateExtensions is a C# utility that will take two Lambda expressions and combine them using .And or .Or extension methods. Expressions be joined at runtime for dynamic LINQ queries. PredicateExte 12 | Initial release 13 | MIT License 14 | LINQ, EntityFramework, ExpressionTree, predicate, Where 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /PredicateExtensions/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PredicateExtensions")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PredicateExtensions")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5b207652-d569-4184-8855-ba78c343b5a0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PredicateExtensions.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PredicateExtensions.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PredicateExtensions.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("777e9c64-1350-4878-82eb-c2f0ab2173ed")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PredicateExtensions.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PredicateExtensions", "PredicateExtensions\PredicateExtensions.csproj", "{EFC46BE7-B469-4599-B22D-CC878874B3CB}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PredicateExtensions.Tests", "PredicateExtensions.Tests\PredicateExtensions.Tests.csproj", "{9304E1C6-958E-4A52-833B-8D11BF39FC13}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{90058D89-092B-4D5D-A79E-239460A885BF}" 11 | ProjectSection(SolutionItems) = preProject 12 | .nuget\NuGet.Config = .nuget\NuGet.Config 13 | .nuget\NuGet.exe = .nuget\NuGet.exe 14 | .nuget\NuGet.targets = .nuget\NuGet.targets 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {EFC46BE7-B469-4599-B22D-CC878874B3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {EFC46BE7-B469-4599-B22D-CC878874B3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {EFC46BE7-B469-4599-B22D-CC878874B3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {EFC46BE7-B469-4599-B22D-CC878874B3CB}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {9304E1C6-958E-4A52-833B-8D11BF39FC13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {9304E1C6-958E-4A52-833B-8D11BF39FC13}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {9304E1C6-958E-4A52-833B-8D11BF39FC13}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {9304E1C6-958E-4A52-833B-8D11BF39FC13}.Release|Any CPU.Build.0 = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /PredicateExtensions/PredicateExtensions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EFC46BE7-B469-4599-B22D-CC878874B3CB} 8 | Library 9 | Properties 10 | PredicateExtensions 11 | PredicateExtensions 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 53 | -------------------------------------------------------------------------------- /PredicateExtensions/PredicateExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | 5 | namespace PredicateExtensions 6 | { 7 | //Attributed to: Adam Tegen via StackOverflow http://stackoverflow.com/questions/457316/combining-two-expressions-expressionfunct-bool 8 | //Modified by Ed Charbeneau 9 | public static class PredicateExtensions 10 | { 11 | /// 12 | /// Begin an expression chain 13 | /// 14 | /// 15 | /// Default return value if the chanin is ended early 16 | /// A lambda expression stub 17 | public static Expression> Begin(bool value = false) 18 | { 19 | if (value) 20 | return parameter => true; //value cannot be used in place of true/false 21 | 22 | return parameter => false; 23 | } 24 | 25 | public static Expression> And(this Expression> left, 26 | Expression> right) 27 | { 28 | return CombineLambdas(left, right, ExpressionType.AndAlso); 29 | } 30 | 31 | public static Expression> Or(this Expression> left, Expression> right) 32 | { 33 | return CombineLambdas(left, right, ExpressionType.OrElse); 34 | } 35 | 36 | #region private 37 | 38 | private static Expression> CombineLambdas(this Expression> left, 39 | Expression> right, ExpressionType expressionType) 40 | { 41 | //Remove expressions created with Begin() 42 | if (IsExpressionBodyConstant(left)) 43 | return (right); 44 | 45 | ParameterExpression p = left.Parameters[0]; 46 | 47 | SubstituteParameterVisitor visitor = new SubstituteParameterVisitor(); 48 | visitor.Sub[right.Parameters[0]] = p; 49 | 50 | Expression body = Expression.MakeBinary(expressionType, left.Body, visitor.Visit(right.Body)); 51 | return Expression.Lambda>(body, p); 52 | } 53 | 54 | private static bool IsExpressionBodyConstant(Expression> left) 55 | { 56 | return left.Body.NodeType == ExpressionType.Constant; 57 | } 58 | 59 | internal class SubstituteParameterVisitor : ExpressionVisitor 60 | { 61 | public Dictionary Sub = new Dictionary(); 62 | 63 | protected override Expression VisitParameter(ParameterExpression node) 64 | { 65 | Expression newValue; 66 | if (Sub.TryGetValue(node, out newValue)) 67 | { 68 | return newValue; 69 | } 70 | return node; 71 | } 72 | } 73 | 74 | #endregion 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | .nuget 81 | 82 | # Visual C++ cache files 83 | ipch/ 84 | *.aps 85 | *.ncb 86 | *.opensdf 87 | *.sdf 88 | *.cachefile 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | 102 | # TeamCity is a build add-in 103 | _TeamCity* 104 | 105 | # DotCover is a Code Coverage Tool 106 | *.dotCover 107 | 108 | # NCrunch 109 | *.ncrunch* 110 | .*crunch*.local.xml 111 | 112 | # Installshield output folder 113 | [Ee]xpress/ 114 | 115 | # DocProject is a documentation generator add-in 116 | DocProject/buildhelp/ 117 | DocProject/Help/*.HxT 118 | DocProject/Help/*.HxC 119 | DocProject/Help/*.hhc 120 | DocProject/Help/*.hhk 121 | DocProject/Help/*.hhp 122 | DocProject/Help/Html2 123 | DocProject/Help/html 124 | 125 | # Click-Once directory 126 | publish/ 127 | 128 | # Publish Web Output 129 | *.Publish.xml 130 | *.pubxml 131 | 132 | # NuGet Packages Directory 133 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 134 | packages/ 135 | 136 | # Windows Azure Build Output 137 | csx 138 | *.build.csdef 139 | 140 | # Windows Store app package directory 141 | AppPackages/ 142 | 143 | # Others 144 | sql/ 145 | *.Cache 146 | ClientBin/ 147 | [Ss]tyle[Cc]op.* 148 | ~$* 149 | *~ 150 | *.dbmdl 151 | *.[Pp]ublish.xml 152 | *.pfx 153 | *.publishsettings 154 | 155 | # RIA/Silverlight projects 156 | Generated_Code/ 157 | 158 | # Backup & report files from converting an old project file to a newer 159 | # Visual Studio version. Backup files are not needed, because we have git ;-) 160 | _UpgradeReport_Files/ 161 | Backup*/ 162 | UpgradeLog*.XML 163 | UpgradeLog*.htm 164 | 165 | # SQL Server files 166 | App_Data/*.mdf 167 | App_Data/*.ldf 168 | 169 | ############# 170 | ## Windows detritus 171 | ############# 172 | 173 | # Windows image file caches 174 | Thumbs.db 175 | ehthumbs.db 176 | 177 | # Folder config file 178 | Desktop.ini 179 | 180 | # Recycle Bin used on file shares 181 | $RECYCLE.BIN/ 182 | 183 | # Mac crap 184 | .DS_Store 185 | 186 | 187 | ############# 188 | ## Python 189 | ############# 190 | 191 | *.py[co] 192 | 193 | # Packages 194 | *.egg 195 | *.egg-info 196 | dist/ 197 | build/ 198 | eggs/ 199 | parts/ 200 | var/ 201 | sdist/ 202 | develop-eggs/ 203 | .installed.cfg 204 | 205 | # Installer logs 206 | pip-log.txt 207 | 208 | # Unit test / coverage reports 209 | .coverage 210 | .tox 211 | 212 | #Translations 213 | *.mo 214 | 215 | #Mr Developer 216 | .mr.developer.cfg 217 | -------------------------------------------------------------------------------- /PredicateExtensions.Tests/PredicateExtensions.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {9304E1C6-958E-4A52-833B-8D11BF39FC13} 8 | Library 9 | Properties 10 | PredicateExtensions.Tests 11 | PredicateExtensions.Tests 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll 37 | 38 | 39 | ..\packages\FluentAssertions.2.1.0.0\lib\net45\FluentAssertions.dll 40 | 41 | 42 | ..\packages\NUnit.2.6.2\lib\nunit.framework.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {efc46be7-b469-4599-b22d-cc878874b3cb} 70 | PredicateExtensions 71 | 72 | 73 | 74 | 75 | 82 | -------------------------------------------------------------------------------- /PredicateExtensions.Tests/ExtensionTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using FluentAssertions; 7 | 8 | namespace PredicateExtensions.Tests 9 | { 10 | /* 11 | * Data is not needed for these tests, we only need to see if the expression trees are formed correctly 12 | * Assertions are performed on strings instead of Expression objects 13 | * since two Expressions will evaluate to different instances 14 | */ 15 | 16 | [TestFixture] 17 | public class ExtensionTests 18 | { 19 | readonly Expression> equalsA = str => str == "A"; 20 | readonly Expression> equalsC = str => str == "C"; 21 | readonly Expression> containsB = str => str.Contains("B"); 22 | 23 | [Test] 24 | public void Can_Reduce_Predicates_With_PredicateExtensions_Or_Method() 25 | { 26 | //arrange 27 | Expression> expectedOrExpression = str => (str == "A" || str.Contains("B")); 28 | string expectedExpression = expectedOrExpression.ToString(); 29 | 30 | //Act 31 | Expression> orExpression = equalsA.Or(containsB); 32 | string resultExpression = orExpression.ToString(); 33 | 34 | //Assert 35 | resultExpression.Should().Be(expectedExpression); 36 | LogResults(expectedExpression, resultExpression); 37 | } 38 | 39 | [Test] 40 | public void Can_Reduce_Predicates_With_PredicateExtensions_And_Method() 41 | { 42 | //arrange 43 | Expression> expectedAndExpression = str => (str == "A" && str.Contains("B")); 44 | string expectedExpression = expectedAndExpression.ToString(); 45 | 46 | //Act 47 | Expression> andExpression = equalsA.And(containsB); 48 | string resultExpression = andExpression.ToString(); 49 | 50 | //Assert 51 | resultExpression.Should().Be(expectedExpression); 52 | LogResults(expectedExpression, resultExpression); 53 | 54 | } 55 | 56 | [Test] 57 | public void Can_Begin_New_Expression() 58 | { 59 | //arrange 60 | var predicate = PredicateExtensions.Begin(true); 61 | Expression> expectedOrExpression = str => (str == "A" || str.Contains("B")); 62 | string expectedExpression = expectedOrExpression.ToString(); 63 | 64 | //Act 65 | Expression> orExpression = predicate.Or(equalsA.Or(containsB)); 66 | string resultExpression = orExpression.ToString(); 67 | 68 | //Assert 69 | resultExpression.Should().Be(expectedExpression); 70 | LogResults(expectedExpression, resultExpression); 71 | 72 | } 73 | 74 | [Test] 75 | public void Can_Reduce_Grouped_Predicates() 76 | { 77 | //arrange 78 | Expression> expectedGroupedPredicate = 79 | str => (str == "A" || str.Contains("B")) && (str == "C"); 80 | 81 | string expectedExpression = expectedGroupedPredicate.ToString(); 82 | 83 | //act 84 | Expression> groupedPredicate = 85 | (equalsA.Or(containsB)) 86 | .And(equalsC); 87 | 88 | string resultExpression = groupedPredicate.ToString(); 89 | 90 | //assert 91 | resultExpression.Should().Be(resultExpression); 92 | 93 | LogResults(expectedExpression, resultExpression); 94 | 95 | } 96 | 97 | private void LogResults(string expectedExpression, string resultExpression) 98 | { 99 | Console.Write(expectedExpression); 100 | Console.WriteLine(); 101 | Console.Write(resultExpression); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /PredicateExtensions.Tests/EfExtensionTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using FluentAssertions; 7 | 8 | namespace PredicateExtensions.Tests 9 | { 10 | 11 | /* 12 | * SQL Server is required for these tests to run properly. 13 | * 14 | * Since Entity Framework can fail to translate predicates at run time 15 | * we'll check predicates built with predicate builder against EF. 16 | */ 17 | 18 | [TestFixture] 19 | public class EfExtensionTests 20 | { 21 | private BloggingContext dbContext; 22 | 23 | [TestFixtureSetUp] 24 | public void SetUp() 25 | { 26 | dbContext = new BloggingContext(); 27 | // TODO: Uncomment if you need to initialize a new database 28 | // InitDatabase(); 29 | } 30 | 31 | [Test] 32 | public void Can_Query_Using_Predicates_Built_With_Or_Extension() 33 | { 34 | //Act 35 | var results = dbContext.Posts.Where 36 | ( 37 | HasTitle("First Post") 38 | .Or(ContentContains("keyword")) 39 | ); 40 | 41 | Console.WriteLine(results); 42 | 43 | //Assert 44 | results.Count().Should().Be(2); 45 | foreach (var item in results) 46 | { 47 | Console.WriteLine("Title: {0}", item.Title); 48 | Console.WriteLine("Content: {0}", item.Content); 49 | Console.WriteLine("-------"); 50 | } 51 | } 52 | 53 | [Test] 54 | public void Can_Query_Using_Predicates_Built_With_And_Extension() 55 | { 56 | //Act 57 | var results = dbContext.Posts.Where 58 | ( 59 | HasTitle("First Post") 60 | .And(ContentContains("Lorem")) 61 | ); 62 | 63 | Console.WriteLine(results); 64 | 65 | //Assert 66 | results.Count().Should().Be(1); 67 | foreach (var item in results) 68 | { 69 | Console.WriteLine("Title: {0}", item.Title); 70 | Console.WriteLine("Content: {0}", item.Content); 71 | Console.WriteLine("-------"); 72 | } 73 | } 74 | 75 | [Test] 76 | public void Can_Query_Using_Dynamic_Predicates() 77 | { 78 | //arrange 79 | IEnumerable keywords = new List { "First", "Third", "Fourth" }; 80 | 81 | //act 82 | //Dynimaically build 83 | //post => post.Title == "First" || post.Title == "Third" || post.Title == "Fourth" 84 | var results = dbContext.Posts.Where( 85 | TitleContains(keywords)); 86 | 87 | //assert 88 | Console.WriteLine(results); 89 | results.Count().Should().Be(3); 90 | } 91 | 92 | [Test] 93 | public void Given_Empty_Parameters_Dynamic_Predicate_Returns_Empty_Results() 94 | { 95 | //arrange 96 | IEnumerable keywords = new List(); 97 | 98 | //act 99 | //Dynimaically build 100 | //post => post.Title == "First" || post.Title == "Third" || post.Title == "Fourth" 101 | var results = dbContext.Posts.Where( 102 | TitleContains(keywords)); 103 | 104 | //assert 105 | Console.WriteLine(results); 106 | results.Count().Should().Be(0); 107 | 108 | } 109 | 110 | private Expression> TitleContains(IEnumerable keywords) 111 | { 112 | var predicate = PredicateExtensions.Begin(); 113 | 114 | foreach (var keyword in keywords) 115 | { 116 | predicate = predicate.Or(TitleContains(keyword)); 117 | } 118 | return predicate; 119 | } 120 | 121 | private Expression> TitleContains(string keyword) 122 | { 123 | return post => post.Title.Contains(keyword); 124 | } 125 | 126 | private Expression> HasTitle(string title) 127 | { 128 | return post => post.Title == title; 129 | } 130 | 131 | private Expression> ContentContains(string keyword) 132 | { 133 | return post => post.Content.Contains(keyword); 134 | } 135 | 136 | private void InitDatabase() 137 | { 138 | //Initialize Data 139 | //Add Blog 140 | dbContext.Blogs.Add(new Blog { Name = "First Blog" }); 141 | dbContext.SaveChanges(); 142 | 143 | var blog = dbContext.Blogs.First(); 144 | 145 | //Add posts 146 | blog.Posts.Add(new Post { Title = "First Post", Content = "Lorem Ipsum" }); 147 | blog.Posts.Add(new Post { Title = "Second Post", Content = "Lorem Ipsum" }); 148 | blog.Posts.Add(new Post { Title = "Third Post", Content = "keyword" }); 149 | blog.Posts.Add(new Post { Title = "Fourth Post", Content = "Lorem Ipsum" }); 150 | 151 | dbContext.SaveChanges(); 152 | } 153 | 154 | // TODO: Uncomment if you are having trouble initializing a database 155 | //[Test] 156 | //public void Db_Has_Data() 157 | //{ 158 | // Assert.Greater(dbContext.Posts.Count(), 0); 159 | //} 160 | 161 | } 162 | } 163 | --------------------------------------------------------------------------------