├── .gitattributes
├── .gitignore
├── LICENSE
├── PoweredSoft.DynamicLinq.Dal
├── App.config
├── BlogContext.cs
├── BlogCoreContext.cs
├── Configurations
│ └── Configurations.cs
├── Pocos
│ ├── Author.cs
│ ├── Comment.cs
│ ├── CommentLike.cs
│ ├── Post.cs
│ ├── Uniqe.cs
│ └── Website.cs
├── PoweredSoft.DynamicLinq.Dal.csproj
└── packages.config
├── PoweredSoft.DynamicLinq.EntityFramework
├── App.config
├── Extensions
│ └── DbContextExtensions.cs
└── PoweredSoft.DynamicLinq.EntityFramework.csproj
├── PoweredSoft.DynamicLinq.EntityFrameworkCore
├── Extensions
│ └── DbContextExtensions.cs
└── PoweredSoft.DynamicLinq.EntityFrameworkCore.csproj
├── PoweredSoft.DynamicLinq.Test
├── AnonymousTypeTest.cs
├── App.config
├── ComplexQueriesTests.cs
├── ConstantTests.cs
├── CountTests.cs
├── EntityFrameworkCoreTests.cs
├── EntityFrameworkTests.cs
├── GetCoreContext.cs
├── GroupingTests.cs
├── Helpers
│ └── QueryableAssert.cs
├── HelpersTests.cs
├── InTests.cs
├── PoweredSoft.DynamicLinq.Test.csproj
├── SelectTests.cs
├── ShortcutTests.cs
├── SimpleQueriesTest.cs
├── StringComparision.cs
└── TestData.cs
├── PoweredSoft.DynamicLinq.sln
├── PoweredSoft.DynamicLinq
├── Constants.cs
├── DynamicType
│ ├── DynamicClass.cs
│ └── DynamicClassFactory.cs
├── Extensions
│ ├── EnumerableExtensions.cs
│ └── QueryableExtensions.cs
├── Fluent
│ ├── Group
│ │ └── GroupBuilder.cs
│ ├── OrderBy
│ │ ├── OrderByBuilder.cs
│ │ └── OrderByPart.cs
│ ├── Select
│ │ └── SelectBuilder.cs
│ └── Where
│ │ ├── WhereBuilder.cs
│ │ ├── WhereBuilder.shortcuts.cs
│ │ └── WhereBuilderCondition.cs
├── Helpers
│ ├── AnonymousTypes.cs
│ ├── QueryableHelpers.cs
│ └── TypeHelpers.cs
├── Interfaces
│ └── IQueryBuilder.cs
├── Parser
│ ├── ExpressionParser.cs
│ ├── ExpressionParserPiece.cs
│ ├── ExpressionParserPieceGroup.cs
│ └── ParserExtensions.cs
├── PoweredSoft.DynamicLinq.csproj
├── Properties
│ └── PublishProfiles
│ │ └── FolderProfile.pubxml
└── Resolver
│ └── PathExpressionResolver.cs
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Powered Softwares Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/BlogContext.cs:
--------------------------------------------------------------------------------
1 | using PoweredSoft.DynamicLinq.Dal.Configurations;
2 | using PoweredSoft.DynamicLinq.Dal.Pocos;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Data.Entity;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace PoweredSoft.DynamicLinq.Dal
11 | {
12 |
13 | public class BlogContext : DbContext
14 | {
15 | public DbSet Authors { get; set; }
16 | public DbSet Comments { get; set; }
17 | public DbSet Posts { get; set; }
18 |
19 | static BlogContext()
20 | {
21 | Database.SetInitializer(new DropCreateDatabaseAlways());
22 | }
23 |
24 | public BlogContext()
25 | {
26 |
27 | }
28 |
29 | public BlogContext(string connectionString) : base(connectionString)
30 | {
31 |
32 | }
33 |
34 | protected override void OnModelCreating(DbModelBuilder modelBuilder)
35 | {
36 | base.OnModelCreating(modelBuilder);
37 | modelBuilder.Configurations.Add(new AuthorConfiguration());
38 | modelBuilder.Configurations.Add(new CommentConfiguration());
39 | modelBuilder.Configurations.Add(new PostConfiguration());
40 | modelBuilder.Configurations.Add(new WebsiteConfiguration());
41 | modelBuilder.Configurations.Add(new CommentLikeConfiguration());
42 | modelBuilder.Configurations.Add(new UniqueConfiguration());
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/BlogCoreContext.cs:
--------------------------------------------------------------------------------
1 | using PoweredSoft.DynamicLinq.Dal.Pocos;
2 | using Microsoft.EntityFrameworkCore;
3 | using JetBrains.Annotations;
4 | using System.Diagnostics.CodeAnalysis;
5 |
6 | namespace PoweredSoft.DynamicLinq.Dal
7 | {
8 | public class BlogCoreContext : DbContext
9 | {
10 | public BlogCoreContext([NotNull] DbContextOptions options) : base(options)
11 | {
12 | }
13 |
14 | protected BlogCoreContext()
15 | {
16 | }
17 |
18 | public DbSet Authors { get; set; }
19 | public DbSet Comments { get; set; }
20 | public DbSet Posts { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/Configurations/Configurations.cs:
--------------------------------------------------------------------------------
1 | using PoweredSoft.DynamicLinq.Dal.Pocos;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 | using System.Data.Entity.ModelConfiguration;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace PoweredSoft.DynamicLinq.Dal.Configurations
11 | {
12 | public class UniqueConfiguration : EntityTypeConfiguration
13 | {
14 | public UniqueConfiguration() : this("dbo")
15 | {
16 |
17 | }
18 |
19 | public UniqueConfiguration(string schema)
20 | {
21 | ToTable("Unique", schema);
22 | HasKey(t => t.Id);
23 | Property(t => t.Id).HasColumnName("Id").HasColumnType("bigint").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
24 | Property(t => t.RowNumber).HasColumnType("uniqueidentifier").IsRequired();
25 | Property(t => t.OtherNullableGuid).HasColumnType("uniqueidentifier");
26 | }
27 | }
28 |
29 | public class AuthorConfiguration : EntityTypeConfiguration
30 | {
31 | public AuthorConfiguration() : this("dbo")
32 | {
33 |
34 | }
35 |
36 | public AuthorConfiguration(string schema)
37 | {
38 | ToTable("Author", schema);
39 | HasKey(t => t.Id);
40 | Property(t => t.Id).HasColumnName("Id").HasColumnType("bigint").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
41 | Property(t => t.FirstName).HasColumnType("nvarchar").HasMaxLength(50).IsRequired();
42 | Property(t => t.LastName).HasColumnType("nvarchar").HasMaxLength(50).IsRequired();
43 |
44 | HasOptional(t => t.Website).WithMany(t => t.Authors).HasForeignKey(t => t.WebsiteId).WillCascadeOnDelete(false);
45 | }
46 | }
47 |
48 | public class PostConfiguration : EntityTypeConfiguration
49 | {
50 | public PostConfiguration() : this("dbo")
51 | {
52 |
53 | }
54 |
55 | public PostConfiguration(string schema)
56 | {
57 | ToTable("Post", schema);
58 | HasKey(t => t.Id);
59 | Property(t => t.Id).HasColumnName("Id").HasColumnType("bigint").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
60 | Property(t => t.AuthorId).HasColumnName("AuthorId").HasColumnType("bigint").IsRequired();
61 | Property(t => t.Title).HasColumnName("Title").HasColumnType("nvarchar").HasMaxLength(100).IsRequired();
62 | Property(t => t.Content).HasColumnName("Content").HasColumnType("nvarchar(max)").IsRequired();
63 | Property(t => t.CreateTime).HasColumnName("CreateTime").HasColumnType("datetimeoffset").IsRequired();
64 | Property(t => t.PublishTime).HasColumnName("PublishTime").HasColumnType("datetimeoffset").IsOptional();
65 |
66 | HasRequired(t => t.Author).WithMany(t => t.Posts).HasForeignKey(t => t.AuthorId).WillCascadeOnDelete(false);
67 | }
68 | }
69 |
70 | public class CommentConfiguration : EntityTypeConfiguration
71 | {
72 | public CommentConfiguration() : this("dbo")
73 | {
74 |
75 | }
76 |
77 | public CommentConfiguration(string schema)
78 | {
79 | ToTable("Comment", schema);
80 | HasKey(t => t.Id);
81 | Property(t => t.Id).HasColumnName("Id").HasColumnType("bigint").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
82 | Property(t => t.PostId).HasColumnName("PostId").HasColumnType("bigint").IsRequired();
83 | Property(t => t.DisplayName).HasColumnName("DisplayName").HasColumnType("nvarchar").HasMaxLength(100).IsRequired();
84 | Property(t => t.Email).HasColumnName("Email").HasColumnType("nvarchar").IsOptional();
85 | Property(t => t.CommentText).HasColumnName("CommentText").HasColumnType("nvarchar").HasMaxLength(255).IsOptional();
86 |
87 | HasRequired(t => t.Post).WithMany(t => t.Comments).HasForeignKey(t => t.PostId).WillCascadeOnDelete(false);
88 | }
89 | }
90 |
91 | public class CommentLikeConfiguration : EntityTypeConfiguration
92 | {
93 | public CommentLikeConfiguration() : this("dbo")
94 | {
95 | }
96 |
97 | public CommentLikeConfiguration(string schema)
98 | {
99 | ToTable("CommentLike", schema);
100 | HasKey(t => t.Id);
101 | Property(t => t.Id).HasColumnName("Id").HasColumnType("bigint").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
102 | Property(t => t.CommentId).HasColumnName("CommentId").HasColumnType("bigint").IsRequired();
103 | Property(t => t.CreateTime).HasColumnName("CreateTime").HasColumnType("datetimeoffset").IsRequired();
104 |
105 | HasRequired(t => t.Comment).WithMany(t => t.CommentLikes).HasForeignKey(t => t.CommentId).WillCascadeOnDelete(false);
106 | }
107 | }
108 |
109 | public class WebsiteConfiguration : EntityTypeConfiguration
110 | {
111 | public WebsiteConfiguration() : this("dbo")
112 | {
113 |
114 | }
115 |
116 | public WebsiteConfiguration(string schema)
117 | {
118 | ToTable("Website", schema);
119 | HasKey(t => t.Id);
120 | Property(t => t.Id).HasColumnName("Id").HasColumnType("bigint").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
121 | Property(t => t.Title).HasColumnName("Title").HasColumnType("nvarchar").HasMaxLength(100).IsRequired();
122 | Property(t => t.Url).HasColumnName("Url").HasColumnType("nvarchar").HasMaxLength(255).IsRequired();
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/Pocos/Author.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 PoweredSoft.DynamicLinq.Dal.Pocos
8 | {
9 | public class Author
10 | {
11 | public long Id { get; set; }
12 | public string FirstName { get; set; }
13 | public string LastName { get; set; }
14 | public long? WebsiteId { get; set; }
15 |
16 | public virtual Website Website { get; set; }
17 | public ICollection Posts { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/Pocos/Comment.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 PoweredSoft.DynamicLinq.Dal.Pocos
8 | {
9 | public class Comment
10 | {
11 | public long Id { get; set; }
12 | public long PostId { get; set; }
13 | public string DisplayName { get; set; }
14 | public string Email { get; set; }
15 | public string CommentText { get; set; }
16 | public Post Post { get; set; }
17 | public ICollection CommentLikes { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/Pocos/CommentLike.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 PoweredSoft.DynamicLinq.Dal.Pocos
8 | {
9 | public class CommentLike
10 | {
11 | public long Id { get; set; }
12 | public long CommentId { get; set; }
13 | public DateTimeOffset CreateTime { get; set; }
14 |
15 | public virtual Comment Comment { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/Pocos/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 PoweredSoft.DynamicLinq.Dal.Pocos
8 | {
9 | public class Post
10 | {
11 | public long Id { get; set; }
12 | public long AuthorId { get; set; }
13 | public string Title { get; set; }
14 | public string Content { get; set; }
15 | public DateTimeOffset CreateTime { get; set; }
16 | public DateTimeOffset? PublishTime { get; set; }
17 |
18 | public Author Author { get; set; }
19 | public virtual ICollection Comments { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/Pocos/Uniqe.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 PoweredSoft.DynamicLinq.Dal.Pocos
8 | {
9 | public class Unique
10 | {
11 | public long Id { get; set; }
12 | public Guid RowNumber { get; set; }
13 | public Guid? OtherNullableGuid { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/Pocos/Website.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 PoweredSoft.DynamicLinq.Dal.Pocos
8 | {
9 | public class Website
10 | {
11 | public long Id { get; set; }
12 | public string Url { get; set; }
13 | public string Title { get; set; }
14 |
15 | public ICollection Authors { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/PoweredSoft.DynamicLinq.Dal.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Dal/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.EntityFramework/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.EntityFramework/Extensions/DbContextExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Entity;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using PoweredSoft.DynamicLinq.Fluent;
9 |
10 | namespace PoweredSoft.DynamicLinq.EntityFramework
11 | {
12 | public static class DbContextExtensions
13 | {
14 | public static IQueryable Query(this DbContext context, Type pocoType, Action callback)
15 | {
16 | var set = context.Set(pocoType);
17 | var queryable = set.AsQueryable();
18 | var builder = new WhereBuilder(queryable);
19 | callback(builder);
20 | var result = builder.Build();
21 | return result;
22 | }
23 |
24 | public static IQueryable Query(this DbContext context, Action callback)
25 | where T : class
26 | {
27 | var query = context.Set().AsQueryable();
28 | query = query.Query(callback);
29 | return query;
30 | }
31 |
32 | public static IQueryable Where(this DbContext context, Type pocoType, Action callback)
33 | => context.Query(pocoType, callback);
34 |
35 | public static IQueryable Where(this DbContext context, Action callback)
36 | where T : class => context.Query(callback);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.EntityFramework/PoweredSoft.DynamicLinq.EntityFramework.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1;net461
5 | True
6 | David Lebee
7 | Powered Software Inc.
8 | Entity Framework extensions for Dynamic Linq of PoweredSoft
9 | github
10 | https://github.com/PoweredSoft/DynamicLinq
11 | entity framework ef dynamic linq
12 | https://github.com/PoweredSoft/DynamicLinq
13 | https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&r=g&d=retro
14 | 1.1.0$(VersionSuffix)
15 | EF Integration of DynamicLinq
16 | PoweredSoft.DynamicLinq.EntityFramework
17 | Added Negate & NotContains
18 | False
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.EntityFrameworkCore/Extensions/DbContextExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Microsoft.EntityFrameworkCore;
8 | using PoweredSoft.DynamicLinq.Fluent;
9 |
10 | namespace PoweredSoft.DynamicLinq.EntityFrameworkCore
11 | {
12 | public static class DbContextExtensions
13 | {
14 | private static MethodInfo SetMethod = typeof(DbContext).GetMethod(nameof(DbContext.Set), BindingFlags.Public | BindingFlags.Instance);
15 |
16 | public static IQueryable Query(this DbContext context, Type pocoType, Action callback)
17 | {
18 | var set = SetMethod.MakeGenericMethod(pocoType).Invoke(context, new object[] { });
19 | var queryable = set as IQueryable;
20 | var builder = new WhereBuilder(queryable);
21 | callback(builder);
22 | var result = builder.Build();
23 | return result;
24 | }
25 |
26 | public static IQueryable Query(this DbContext context, Action callback)
27 | where T : class
28 | {
29 | var query = context.Set().AsQueryable();
30 | query = query.Query(callback);
31 | return query;
32 | }
33 |
34 | public static IQueryable Where(this DbContext context, Type pocoType, Action callback)
35 | => context.Query(pocoType, callback);
36 |
37 | public static IQueryable Where(this DbContext context, Action callback)
38 | where T : class => context.Query(callback);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.EntityFrameworkCore/PoweredSoft.DynamicLinq.EntityFrameworkCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | True
6 | David Lebee
7 | Powered Software Inc.
8 | Entity Framework extensions for Dynamic Linq of PoweredSoft
9 | github
10 | https://github.com/PoweredSoft/DynamicLinq
11 | entity framework core efcore ef dynamic linq
12 | https://github.com/PoweredSoft/DynamicLinq
13 | https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&r=g&d=retro
14 | 1.1.0$(VersionSuffix)
15 | EF Integration of DynamicLinq
16 | PoweredSoft.DynamicLinq.EntityFrameworkCore
17 | First Release of efcore extensions
18 | False
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/AnonymousTypeTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using PoweredSoft.DynamicLinq.DynamicType;
5 |
6 | namespace PoweredSoft.DynamicLinq.Test
7 | {
8 | [TestClass]
9 | public class AnonymousTypeTest
10 | {
11 | [TestMethod]
12 | public void TestEqual()
13 | {
14 | var properties = new List<(Type type, string propertyName)>()
15 | {
16 | (typeof(int), "Id"),
17 | (typeof(string), "FirstName"),
18 | (typeof(string), "LastName")
19 | };
20 |
21 | var type = DynamicClassFactory.CreateType(properties);
22 | var instanceA = Activator.CreateInstance(type) as DynamicClass;
23 | var instanceB = Activator.CreateInstance(type) as DynamicClass;
24 |
25 | instanceA.SetDynamicPropertyValue("Id", 1);
26 | instanceA.SetDynamicPropertyValue("FirstName", "David");
27 | instanceA.SetDynamicPropertyValue("LastName", "Lebee");
28 |
29 | instanceB.SetDynamicPropertyValue("Id", 1);
30 | instanceB.SetDynamicPropertyValue("FirstName", "David");
31 | instanceB.SetDynamicPropertyValue("LastName", "Lebee");
32 |
33 | Assert.IsTrue(instanceA.Equals(instanceB));
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/App.config:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/ComplexQueriesTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Data.SqlClient;
5 | using System.Linq;
6 | using System.Linq.Expressions;
7 | using System.Reflection;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using PoweredSoft.DynamicLinq;
11 | using PoweredSoft.DynamicLinq.Dal.Pocos;
12 | using PoweredSoft.DynamicLinq.Fluent;
13 |
14 | namespace PoweredSoft.DynamicLinq.Test
15 | {
16 | [TestClass]
17 | public class ComplexQueriesTests
18 | {
19 | [TestMethod]
20 | public void ComplexQueryBuilder()
21 | {
22 | // subject.
23 | var posts = new List()
24 | {
25 | new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World" },
26 | new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World" },
27 | new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World" },
28 | };
29 |
30 | // the query.
31 | var query = posts.AsQueryable();
32 |
33 | query = query.Query(q =>
34 | {
35 | q.Compare("AuthorId", ConditionOperators.Equal, 1);
36 | q.And(sq =>
37 | {
38 | sq.Compare("Content", ConditionOperators.Equal, "World");
39 | sq.Or("Title", ConditionOperators.Contains, 3);
40 | });
41 | });
42 |
43 | Assert.AreEqual(2, query.Count());
44 | }
45 |
46 | [TestMethod]
47 | public void UsingQueryBuilder()
48 | {
49 | // subject.
50 | var posts = new List()
51 | {
52 | new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World" },
53 | new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World" },
54 | new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World" },
55 | };
56 |
57 | // the query.
58 | var query = posts.AsQueryable();
59 | var queryBuilder = new WhereBuilder(query);
60 |
61 | queryBuilder.Compare("AuthorId", ConditionOperators.Equal, 1);
62 | queryBuilder.And(subQuery =>
63 | {
64 | subQuery.Compare("Content", ConditionOperators.Equal, "World");
65 | subQuery.Or("Title", ConditionOperators.Contains, 3);
66 | });
67 |
68 | query = (IQueryable)queryBuilder.Build();
69 | Assert.AreEqual(2, query.Count());
70 | }
71 |
72 | [TestMethod]
73 | public void TestingSort()
74 | {
75 | // subject.
76 | var posts = new List()
77 | {
78 | new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World" },
79 | new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World" },
80 | new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World" },
81 | };
82 |
83 | // the query.
84 | var query = posts.AsQueryable();
85 | var queryBuilder = new OrderByBuilder(query);
86 |
87 | // add some sorting.
88 | queryBuilder
89 | .OrderByDescending("AuthorId")
90 | .ThenBy("Id");
91 |
92 | query = queryBuilder.Build().Cast();
93 |
94 | var first = query.First();
95 | var second = query.Skip(1).First();
96 |
97 | Assert.IsTrue(first.Id == 3);
98 | Assert.IsTrue(second.Id == 1);
99 | }
100 |
101 | [TestMethod]
102 | public void TestAutomaticNullChecking()
103 | {
104 | var authors = TestData.Authors;
105 |
106 | // the query.
107 | var query = authors.AsQueryable();
108 |
109 | query = query.Query(qb =>
110 | {
111 | qb.NullChecking();
112 | qb.And("Posts.Comments.Email", ConditionOperators.Equal, "john.doe@me.com", collectionHandling: QueryCollectionHandling.Any);
113 | });
114 |
115 | var query2 = query.Where(qb =>
116 | {
117 | qb.NullChecking();
118 | qb.And("Posts.Comments.Email", ConditionOperators.Equal, "john.doe@me.com", collectionHandling: QueryCollectionHandling.Any);
119 | });
120 |
121 | Assert.AreEqual(1, query.Count());
122 | Assert.AreEqual(1, query2.Count());
123 | }
124 |
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/ConstantTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using PoweredSoft.DynamicLinq.Dal.Pocos;
6 |
7 | namespace PoweredSoft.DynamicLinq.Test
8 | {
9 | internal class ConstantTestClass
10 | {
11 | public int Id { get; set; }
12 | public int? ForeignKey { get; set; }
13 | public string Text { get; set; }
14 | }
15 |
16 | [TestClass]
17 | public class ConstantTests
18 | {
19 | internal List Posts { get; set; } = new List()
20 | {
21 | new ConstantTestClass { Id = 1, ForeignKey = null, Text = "Hello" },
22 | new ConstantTestClass { Id = 2, ForeignKey = 1, Text = "Hello 2" },
23 | new ConstantTestClass { Id = 3, ForeignKey = 2, Text = "Hello 3" },
24 | new ConstantTestClass { Id = 4, ForeignKey = null, Text = "Hello 4" },
25 | };
26 |
27 | [TestMethod]
28 | public void LeaveAsIs()
29 | {
30 | try
31 | {
32 | Posts
33 | .AsQueryable()
34 | .Query(t => t.Equal("ForeignKey", 1, QueryConvertStrategy.LeaveAsIs));
35 |
36 | Assert.Fail("Should have thrown an exception");
37 | }
38 | catch
39 | {
40 | }
41 |
42 | Assert.IsTrue(Posts.AsQueryable().Query(t => t.Equal("Id", 1, QueryConvertStrategy.LeaveAsIs)).Any());
43 | }
44 |
45 | [TestMethod]
46 | public void TestGuid()
47 | {
48 | var randomGuidStr = Guid.NewGuid().ToString();
49 | TestData.Uniques.AsQueryable().Query(t => t.Equal("RowNumber", randomGuidStr));
50 | TestData.Uniques.AsQueryable().Query(t => t.Equal("OtherNullableGuid", randomGuidStr));
51 | }
52 |
53 | [TestMethod]
54 | public void SpecifyType()
55 | {
56 | Assert.IsTrue(Posts.AsQueryable().Query(t => t.Equal("ForeignKey", 1, QueryConvertStrategy.SpecifyType)).Any());
57 | Assert.IsTrue(Posts.AsQueryable().Query(t => t.Equal("Id", 1, QueryConvertStrategy.SpecifyType)).Any());
58 |
59 | try
60 | {
61 | Posts.AsQueryable().Query(t => t.Equal("Id", "1", QueryConvertStrategy.SpecifyType));
62 | Assert.Fail("Should have thrown an exception");
63 | }
64 | catch
65 | {
66 |
67 | }
68 | }
69 |
70 | [TestMethod]
71 | public void ConvertConstantToComparedPropertyOrField()
72 | {
73 | Assert.IsTrue(Posts.AsQueryable().Query(t => t.Equal("ForeignKey", 1, QueryConvertStrategy.ConvertConstantToComparedPropertyOrField)).Any());
74 | Assert.IsTrue(Posts.AsQueryable().Query(t => t.Equal("ForeignKey", "1", QueryConvertStrategy.ConvertConstantToComparedPropertyOrField)).Any());
75 | Assert.IsTrue(Posts.AsQueryable().Query(t => t.Equal("Id", 1, QueryConvertStrategy.ConvertConstantToComparedPropertyOrField)).Any());
76 | Assert.IsTrue(Posts.AsQueryable().Query(t => t.Equal("Id", "1", QueryConvertStrategy.ConvertConstantToComparedPropertyOrField)).Any());
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/CountTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace PoweredSoft.DynamicLinq.Test
6 | {
7 | [TestClass]
8 | public class CountTests
9 | {
10 | [TestMethod]
11 | public void Count()
12 | {
13 | var normalSyntax = TestData.Sales.Count();
14 | var nonGenericQueryable = (IQueryable)TestData.Sales.AsQueryable();
15 | var dynamicSyntax = nonGenericQueryable.Count();
16 | Assert.AreEqual(normalSyntax, dynamicSyntax);
17 | }
18 |
19 | [TestMethod]
20 | public void LongCount()
21 | {
22 | var normalSyntax = TestData.Sales.LongCount();
23 | var nonGenericQueryable = (IQueryable)TestData.Sales.AsQueryable();
24 | var dynamicSyntax = nonGenericQueryable.LongCount();
25 | Assert.AreEqual(normalSyntax, dynamicSyntax);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/EntityFrameworkCoreTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using PoweredSoft.DynamicLinq.Dal;
6 | using PoweredSoft.DynamicLinq.Dal.Pocos;
7 | using PoweredSoft.DynamicLinq;
8 | using Microsoft.EntityFrameworkCore;
9 | using PoweredSoft.DynamicLinq.EntityFrameworkCore;
10 | using PoweredSoft.DynamicLinq.Test.Helpers;
11 |
12 | namespace PoweredSoft.DynamicLinq.Test
13 | {
14 | [TestClass]
15 | public class EntityFrameworkCoreTests
16 | {
17 |
18 | private BlogCoreContext GetCoreContext(string testName)
19 | {
20 | var options = new DbContextOptionsBuilder()
21 | .UseInMemoryDatabase(databaseName: testName).Options;
22 | return new BlogCoreContext(options);
23 | }
24 |
25 |
26 | public static void SeedForTests(BlogCoreContext context)
27 | {
28 | context.Authors.Add(new Author
29 | {
30 | FirstName = "David",
31 | LastName = "Lebee",
32 | Posts = new List()
33 | {
34 | new Post()
35 | {
36 | CreateTime = DateTimeOffset.Now,
37 | PublishTime = DateTimeOffset.Now,
38 | Title = "New project",
39 | Content = "Lots of good things coming",
40 | Comments = new List()
41 | {
42 | new Comment()
43 | {
44 | DisplayName = "John Doe",
45 | Email = "john.doe@me.com",
46 | CommentText = "Very interesting",
47 | },
48 | new Comment()
49 | {
50 | DisplayName = "Nice Guy",
51 | Email = "nice.guy@lol.com",
52 | CommentText = "Best of luck!"
53 | }
54 | }
55 | },
56 | new Post()
57 | {
58 | CreateTime = DateTimeOffset.Now,
59 | PublishTime = null,
60 | Title = "The future!",
61 | Content = "Is Near"
62 | }
63 | }
64 | });
65 |
66 | context.Authors.Add(new Author
67 | {
68 | FirstName = "Some",
69 | LastName = "Dude",
70 | Posts = new List()
71 | {
72 | new Post() {
73 | CreateTime = DateTimeOffset.Now,
74 | PublishTime = DateTimeOffset.Now,
75 | Title = "The One",
76 | Content = "And Only"
77 | },
78 | new Post()
79 | {
80 | CreateTime = DateTimeOffset.Now,
81 | PublishTime = DateTimeOffset.Now,
82 | Title = "The Two",
83 | Content = "And Second"
84 | }
85 | }
86 | });
87 |
88 | context.SaveChanges();
89 | }
90 |
91 | [TestMethod]
92 | public void TestSimpleWhere()
93 | {
94 | var context = GetCoreContext(nameof(TestSimpleWhere));
95 | SeedForTests(context);
96 |
97 | var query = context.Authors.AsQueryable();
98 | query = query.Where("FirstName", ConditionOperators.Equal, "David");
99 | var author = query.FirstOrDefault();
100 | Assert.IsNotNull(author);
101 | }
102 | [TestMethod]
103 | public void TestWhereAnd()
104 | {
105 | var context = GetCoreContext(nameof(TestWhereAnd));
106 | SeedForTests(context);
107 |
108 | var query = context.Authors.AsQueryable();
109 | query = query.Query(q => q
110 | .Compare("FirstName", ConditionOperators.Equal, "David")
111 | .And("LastName", ConditionOperators.Equal, "Lebee")
112 | );
113 |
114 | var author = query.FirstOrDefault();
115 | Assert.IsNotNull(author);
116 | }
117 |
118 | [TestMethod]
119 | public void GroupBy()
120 | {
121 | var context = GetCoreContext(nameof(TestWhereOr));
122 | SeedForTests(context);
123 |
124 | var authorsWithFamilyNameCount = context.Authors
125 | .GroupBy(t => new
126 | {
127 | t.LastName,
128 | t.FirstName
129 | }).Select(t => new
130 | {
131 | t.Key,
132 | Count = t.Count()
133 | }).ToList();
134 |
135 | var authorsWithFamilyNameCountDynamic = context.Authors
136 | .GroupBy(t => t.Path("FirstName").Path("LastName"))
137 | .Select(t => t.Key("FirstName", "FirstName").Key("LastName", "LastName").Count("Count"))
138 | .ToDynamicClassList();
139 |
140 | Assert.AreEqual(authorsWithFamilyNameCount.Count, authorsWithFamilyNameCountDynamic.Count);
141 | for(var i = 0; i < authorsWithFamilyNameCount.Count; i++)
142 | {
143 | Assert.AreEqual(authorsWithFamilyNameCount[i].Key.FirstName, authorsWithFamilyNameCountDynamic[i].GetDynamicPropertyValue("FirstName"));
144 | Assert.AreEqual(authorsWithFamilyNameCount[i].Key.LastName, authorsWithFamilyNameCountDynamic[i].GetDynamicPropertyValue("LastName"));
145 | Assert.AreEqual(authorsWithFamilyNameCount[i].Count, authorsWithFamilyNameCountDynamic[i].GetDynamicPropertyValue("Count"));
146 | }
147 | }
148 |
149 |
150 | [TestMethod]
151 | public void TestWhereOr()
152 | {
153 | var context = GetCoreContext(nameof(TestWhereOr));
154 | SeedForTests(context);
155 |
156 | var query = context.Authors.AsQueryable();
157 | query = query.Query(q => q
158 | .Compare("FirstName", ConditionOperators.Equal, "David")
159 | .Or("FirstName", ConditionOperators.Equal, "Some")
160 | );
161 |
162 | var author = query.FirstOrDefault();
163 | Assert.IsNotNull(author);
164 | }
165 |
166 | [TestMethod]
167 | public void TestGoingThroughSimpleNav()
168 | {
169 | var context = GetCoreContext(nameof(TestGoingThroughSimpleNav));
170 | SeedForTests(context);
171 |
172 | var query = context.Posts.AsQueryable();
173 | query = query.Include("Author").Where("Author.FirstName", ConditionOperators.Contains, "David");
174 | var post = query.FirstOrDefault();
175 | Assert.AreEqual("David", post?.Author?.FirstName);
176 | }
177 |
178 | [TestMethod]
179 | public void TestGoingThroughCollectionNav()
180 | {
181 | var context = GetCoreContext(nameof(TestGoingThroughCollectionNav));
182 | SeedForTests(context);
183 |
184 | var query = context.Authors.AsQueryable();
185 | query = query.Where("Posts.Title", ConditionOperators.Contains, "New");
186 | var author = query.FirstOrDefault();
187 |
188 | Assert.AreEqual(author?.FirstName, "David");
189 | }
190 |
191 | [TestMethod]
192 | public void TestGoingThrough2CollectionNav()
193 | {
194 | var context = GetCoreContext(nameof(TestGoingThrough2CollectionNav));
195 | SeedForTests(context);
196 |
197 | var query = context.Authors.AsQueryable();
198 | query = query.Where("Posts.Comments.Email", ConditionOperators.Contains, "@me.com");
199 | var author = query.FirstOrDefault();
200 |
201 | Assert.AreEqual(author?.FirstName, "David");
202 | }
203 |
204 | [TestMethod]
205 | public void TestSort()
206 | {
207 | var context = GetCoreContext(nameof(TestSort));
208 | SeedForTests(context);
209 |
210 | var query = context.Posts.AsQueryable();
211 | var dq = query.OrderBy("Title").ThenByDescending("Content").ToList();
212 | var sq = query.OrderBy(t => t.Title).ThenByDescending(t => t.Content).ToList();
213 |
214 | Assert.AreEqual(dq.Count, sq.Count);
215 | for (var i = 0; i < dq.Count; i++)
216 | Assert.AreEqual(dq[i].Id, sq[i].Id);
217 | }
218 |
219 | [TestMethod]
220 | public void TestContextTypeLessHelper()
221 | {
222 | var context = GetCoreContext(nameof(TestContextTypeLessHelper));
223 | SeedForTests(context);
224 |
225 | var queryable = context.Query(typeof(Author), q => q.Compare("FirstName", ConditionOperators.Equal, "David"));
226 | var result = queryable.ToObjectList();
227 | var first = result.FirstOrDefault() as Author;
228 | Assert.AreEqual(first?.FirstName, "David");
229 | }
230 |
231 | [TestMethod]
232 | public void TestLessAndGreaterThan()
233 | {
234 | var context = GetCoreContext(nameof(TestWhereAnd)); //EF Core
235 | //or new BlogContext(testConnectionString); in EF
236 | SeedForTests(context);
237 |
238 | var query = context.Authors.Query(q => q.LessThan("FirstName", "Mario"));
239 | var first = query.FirstOrDefault();
240 | Assert.AreEqual(first?.FirstName, "David");
241 |
242 | query = context.Authors.Query(q => q.GreaterThan("FirstName", "Mario"));
243 | first = query.FirstOrDefault();
244 | Assert.AreEqual(first?.FirstName, "Some");
245 | }
246 | }
247 | }
248 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/EntityFrameworkTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Entity;
4 | using System.Linq;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using PoweredSoft.DynamicLinq.Dal;
7 | using PoweredSoft.DynamicLinq.Dal.Pocos;
8 | using PoweredSoft.DynamicLinq.EntityFramework;
9 | using PoweredSoft.DynamicLinq;
10 |
11 | namespace PoweredSoft.DynamicLinq.Test
12 | {
13 | [TestClass]
14 | public class EntityFrameworkTests
15 | {
16 | public static string testConnectionString =>
17 | @"Server=(localdb)\mssqllocaldb;Database=EFProviders.InMemory;Trusted_Connection=True;";
18 | //"data source=(local); initial catalog=blogtests;persist security info=True; Integrated Security=SSPI;";
19 |
20 | public static void SeedForTests(BlogContext context)
21 | {
22 | context.Authors.Add(new Author
23 | {
24 | FirstName = "David",
25 | LastName = "Lebee",
26 | Posts = new List()
27 | {
28 | new Post()
29 | {
30 | CreateTime = DateTimeOffset.Now,
31 | PublishTime = DateTimeOffset.Now,
32 | Title = "New project",
33 | Content = "Lots of good things coming",
34 | Comments = new List()
35 | {
36 | new Comment()
37 | {
38 | DisplayName = "John Doe",
39 | Email = "john.doe@me.com",
40 | CommentText = "Very interesting",
41 | },
42 | new Comment()
43 | {
44 | DisplayName = "Nice Guy",
45 | Email = "nice.guy@lol.com",
46 | CommentText = "Best of luck!"
47 | }
48 | }
49 | },
50 | new Post()
51 | {
52 | CreateTime = DateTimeOffset.Now,
53 | PublishTime = null,
54 | Title = "The future!",
55 | Content = "Is Near"
56 | }
57 | }
58 | });
59 |
60 | context.Authors.Add(new Author
61 | {
62 | FirstName = "Some",
63 | LastName = "Dude",
64 | Posts = new List()
65 | {
66 | new Post() {
67 | CreateTime = DateTimeOffset.Now,
68 | PublishTime = DateTimeOffset.Now,
69 | Title = "The One",
70 | Content = "And Only"
71 | },
72 | new Post()
73 | {
74 | CreateTime = DateTimeOffset.Now,
75 | PublishTime = DateTimeOffset.Now,
76 | Title = "The Two",
77 | Content = "And Second"
78 | }
79 | }
80 | });
81 |
82 | context.SaveChanges();
83 | }
84 |
85 |
86 |
87 | [TestMethod]
88 | public void TestSimpleWhere()
89 | {
90 | var context = new BlogContext(testConnectionString);
91 | SeedForTests(context);
92 |
93 | var query = context.Authors.AsQueryable();
94 | query = query.Where("FirstName", ConditionOperators.Equal, "David");
95 | var author = query.FirstOrDefault();
96 | Assert.IsNotNull(author);
97 | }
98 |
99 | [TestMethod]
100 | public void TestWhereAnd()
101 | {
102 | var context = new BlogContext(testConnectionString);
103 | SeedForTests(context);
104 |
105 | var query = context.Authors.AsQueryable();
106 | query = query.Query(q => q
107 | .Compare("FirstName", ConditionOperators.Equal, "David")
108 | .And("LastName", ConditionOperators.Equal, "Lebee")
109 | );
110 |
111 | var author = query.FirstOrDefault();
112 | Assert.IsNotNull(author);
113 | }
114 |
115 | [TestMethod]
116 | public void TestWhereOr()
117 | {
118 | var context = new BlogContext(testConnectionString);
119 | SeedForTests(context);
120 |
121 | var query = context.Authors.AsQueryable();
122 | query = query.Query(q => q
123 | .Compare("FirstName", ConditionOperators.Equal, "David")
124 | .Or("FirstName", ConditionOperators.Equal, "Some")
125 | );
126 |
127 | var author = query.FirstOrDefault();
128 | Assert.IsNotNull(author);
129 | }
130 |
131 | [TestMethod]
132 | public void TestGoingThroughSimpleNav()
133 | {
134 | var context = new BlogContext(testConnectionString);
135 | SeedForTests(context);
136 |
137 | var query = context.Posts.AsQueryable();
138 | query = query.Include("Author").Where("Author.FirstName", ConditionOperators.Contains, "David");
139 | var post = query.FirstOrDefault();
140 | Assert.AreEqual("David", post?.Author?.FirstName);
141 | }
142 |
143 | [TestMethod]
144 | public void TestGoingThroughCollectionNav()
145 | {
146 | var context = new BlogContext(testConnectionString);
147 | SeedForTests(context);
148 |
149 | var query = context.Authors.AsQueryable();
150 | query = query.Where("Posts.Title", ConditionOperators.Contains, "New");
151 | var author = query.FirstOrDefault();
152 |
153 | Assert.AreEqual(author?.FirstName, "David");
154 | }
155 |
156 | [TestMethod]
157 | public void TestGoingThrough2CollectionNav()
158 | {
159 | var context = new BlogContext(testConnectionString);
160 | SeedForTests(context);
161 |
162 | var query = context.Authors.AsQueryable();
163 | query = query.Where("Posts.Comments.Email", ConditionOperators.Contains, "@me.com");
164 | var author = query.FirstOrDefault();
165 |
166 | Assert.AreEqual(author?.FirstName, "David");
167 | }
168 |
169 | [TestMethod]
170 | public void TestSort()
171 | {
172 | var context = new BlogContext(testConnectionString);
173 | SeedForTests(context);
174 |
175 | var query = context.Posts.AsQueryable();
176 | var dq = query.OrderBy("Title").ThenByDescending("Content").ToList();
177 | var sq = query.OrderBy(t => t.Title).ThenByDescending(t => t.Content).ToList();
178 |
179 | Assert.AreEqual(dq.Count, sq.Count);
180 | for (var i = 0; i < dq.Count; i++)
181 | Assert.AreEqual(dq[i].Id, sq[i].Id);
182 | }
183 |
184 | [TestMethod]
185 | public void TestContextTypeLessHelper()
186 | {
187 | var context = new BlogContext(testConnectionString);
188 | SeedForTests(context);
189 |
190 | var queryable = context.Query(typeof(Author), q => q.Compare("FirstName", ConditionOperators.Equal, "David"));
191 | var result = queryable.ToListAsync().Result;
192 | var first = result.FirstOrDefault() as Author;
193 | Assert.AreEqual(first?.FirstName, "David");
194 | }
195 |
196 | [TestMethod]
197 | public void TestLessAndGreaterThan()
198 | {
199 | var context = new BlogContext(testConnectionString);
200 | SeedForTests(context);
201 |
202 | var query = context.Authors.Query(q => q.LessThan("FirstName", "Mario"));
203 | var first = query.FirstOrDefault();
204 | Assert.AreEqual(first?.FirstName, "David");
205 |
206 | query = context.Authors.Query(q => q.GreaterThan("FirstName", "Mario"));
207 | first = query.FirstOrDefault();
208 | Assert.AreEqual(first?.FirstName, "Some");
209 | }
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/GetCoreContext.cs:
--------------------------------------------------------------------------------
1 | namespace PoweredSoft.DynamicLinq.Test
2 | {
3 | internal class GetCoreContext
4 | {
5 | private string v;
6 |
7 | public GetCoreContext(string v)
8 | {
9 | this.v = v;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/GroupingTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PoweredSoft.DynamicLinq;
8 | using PoweredSoft.DynamicLinq.Dal;
9 | using System.Diagnostics;
10 | using PoweredSoft.DynamicLinq.Test.Helpers;
11 | using System.Collections;
12 | using PoweredSoft.DynamicLinq.Dal.Pocos;
13 |
14 | namespace PoweredSoft.DynamicLinq.Test
15 | {
16 | internal class TestStructureCompare : IEqualityComparer
17 | {
18 | public bool Equals(TestStructure x, TestStructure y)
19 | {
20 | return x?.ClientId == y?.ClientId;
21 | }
22 |
23 | public int GetHashCode(TestStructure obj)
24 | {
25 | return obj.ClientId;
26 | }
27 | }
28 |
29 | internal class TestStructure
30 | {
31 | public int ClientId { get; set; }
32 | }
33 |
34 | [TestClass]
35 | public class GroupingTests
36 | {
37 | [TestMethod]
38 | public void TestEmptyGroup()
39 | {
40 | var subject = TestData.Sales;
41 |
42 | var normalSyntax = subject
43 | .GroupBy(t => true)
44 | .Select(t => new
45 | {
46 | NetSalesSum = t.Sum(t2 => t2.NetSales),
47 | NetSalesAvg = t.Average(t2 => t2.NetSales)
48 | })
49 | .First();
50 |
51 | var dynamicSyntax = subject
52 | .EmptyGroupBy(typeof(MockSale))
53 | .Select(sb =>
54 | {
55 | sb.Sum("NetSales", "NetSalesSum");
56 | sb.Average("NetSales", "NetSalesAvg");
57 | })
58 | .ToDynamicClassList()
59 | .First();
60 |
61 | Assert.AreEqual(normalSyntax.NetSalesAvg, dynamicSyntax.GetDynamicPropertyValue("NetSalesAvg"));
62 | Assert.AreEqual(normalSyntax.NetSalesSum, dynamicSyntax.GetDynamicPropertyValue("NetSalesSum"));
63 | }
64 |
65 | [TestMethod]
66 | public void WantedSyntax()
67 | {
68 | var normalSyntax = TestData.Sales
69 | .GroupBy(t => new { t.ClientId })
70 | .Select(t => new
71 | {
72 | TheClientId = t.Key.ClientId,
73 | Count = t.Count(),
74 | LongCount = t.LongCount(),
75 | NetSales = t.Sum(t2 => t2.NetSales),
76 | TaxAverage = t.Average(t2 => t2.Tax),
77 | Sales = t.ToList(),
78 | MaxNetSales = t.Max(t2 => t2.NetSales),
79 | MinNetSales = t.Min(t2 => t2.NetSales),
80 | First = t.First(),
81 | Last = t.Last(),
82 | FirstOrDefault = t.FirstOrDefault(),
83 | LastOrDefault = t.LastOrDefault()
84 | })
85 | .ToList();
86 |
87 | var dynamicSyntax = TestData.Sales
88 | .AsQueryable()
89 | .GroupBy(t => t.Path("ClientId"))
90 | .Select(t =>
91 | {
92 | t.Key("TheClientId", "ClientId");
93 | t.Count("Count");
94 | t.LongCount("LongCount");
95 | t.Sum("NetSales");
96 | t.Average("Tax", "TaxAverage");
97 | t.Max("NetSales", "MaxNetSales");
98 | t.Min("NetSales", "MinNetSales");
99 | t.First("First");
100 | t.Last("Last");
101 | t.FirstOrDefault("FirstOrDefault");
102 | t.LastOrDefault("LastOrDefault");
103 | t.ToList("Sales");
104 | })
105 | .ToDynamicClassList();
106 |
107 | Assert.AreEqual(normalSyntax.Count, dynamicSyntax.Count);
108 | for(var i = 0; i < normalSyntax.Count; i++)
109 | {
110 | var left = normalSyntax[i];
111 | var right = dynamicSyntax[i];
112 |
113 | Assert.AreEqual(left.TheClientId, right.GetDynamicPropertyValue("TheClientId"));
114 | Assert.AreEqual(left.Count, right.GetDynamicPropertyValue("Count"));
115 | Assert.AreEqual(left.LongCount, right.GetDynamicPropertyValue("LongCount"));
116 | Assert.AreEqual(left.TaxAverage, right.GetDynamicPropertyValue("TaxAverage"));
117 | Assert.AreEqual(left.MinNetSales, right.GetDynamicPropertyValue("MinNetSales"));
118 | Assert.AreEqual(left.MaxNetSales, right.GetDynamicPropertyValue("MaxNetSales"));
119 |
120 | Assert.AreEqual(left.First, right.GetDynamicPropertyValue("First"));
121 | Assert.AreEqual(left.FirstOrDefault, right.GetDynamicPropertyValue("FirstOrDefault"));
122 | Assert.AreEqual(left.Last, right.GetDynamicPropertyValue("Last"));
123 | Assert.AreEqual(left.LastOrDefault, right.GetDynamicPropertyValue("LastOrDefault"));
124 |
125 | QueryableAssert.AreEqual(left.Sales.AsQueryable(), right.GetDynamicPropertyValue>("Sales").AsQueryable());
126 | }
127 | }
128 |
129 | [TestMethod]
130 | public void TestingSelectBuilderAggregateFluent()
131 | {
132 | var normalSyntax = TestData.Sales
133 | .GroupBy(t => new { t.ClientId })
134 | .Select(t => new
135 | {
136 | TheClientId = t.Key.ClientId,
137 | Count = t.Count(),
138 | LongCount = t.LongCount(),
139 | NetSales = t.Sum(t2 => t2.NetSales),
140 | TaxAverage = t.Average(t2 => t2.Tax),
141 | Sales = t.ToList()
142 | })
143 | .ToList();
144 |
145 | var dynamicSyntax = TestData.Sales
146 | .AsQueryable()
147 | .GroupBy(t => t.Path("ClientId"))
148 | .Select(t =>
149 | {
150 | t.Aggregate("Key.ClientId", SelectTypes.Key, "TheClientId");
151 | // should not have to specify a path, but a property is a must
152 | t.Aggregate(null, SelectTypes.Count, "Count");
153 | // support both ways it can use path to guess property so testing this too
154 | t.Aggregate("LongCount", SelectTypes.LongCount);
155 | t.Aggregate("NetSales", SelectTypes.Sum);
156 | t.Aggregate("Tax", SelectTypes.Average, "TaxAverage");
157 | t.ToList("Sales");
158 | })
159 | .ToDynamicClassList();
160 |
161 | Assert.AreEqual(normalSyntax.Count, dynamicSyntax.Count);
162 | for (var i = 0; i < normalSyntax.Count; i++)
163 | {
164 | var left = normalSyntax[i];
165 | var right = dynamicSyntax[i];
166 |
167 | Assert.AreEqual(left.TheClientId, right.GetDynamicPropertyValue("TheClientId"));
168 | Assert.AreEqual(left.Count, right.GetDynamicPropertyValue("Count"));
169 | Assert.AreEqual(left.LongCount, right.GetDynamicPropertyValue("LongCount"));
170 | Assert.AreEqual(left.TaxAverage, right.GetDynamicPropertyValue("TaxAverage"));
171 | QueryableAssert.AreEqual(left.Sales.AsQueryable(), right.GetDynamicPropertyValue>("Sales").AsQueryable());
172 | }
173 | }
174 |
175 | [TestMethod]
176 | public void GroupWithoutNullCheckComplex()
177 | {
178 | var limitResult = TestData.Authors.Where(t => t.Posts != null).AsQueryable();
179 |
180 | var posts = limitResult
181 | .GroupBy(t => new
182 | {
183 | Titles = t.Posts.Select(t2 => t2.Title)
184 | })
185 | .Select(t => new
186 | {
187 | Titles = t.Key.Titles,
188 | Data = t.ToList()
189 | })
190 | .ToList();
191 |
192 | var posts2 = limitResult
193 | .GroupBy(gb => gb.Path("Posts.Title", "Titles"))
194 | .Select(sb =>
195 | {
196 | sb.Key("Titles");
197 | sb.ToList("Data");
198 | })
199 | .ToDynamicClassList();
200 |
201 | Assert.AreEqual(posts.Count, posts2.Count);
202 | for(var i = 0; i < posts.Count; i++)
203 | {
204 | var expected = posts[0];
205 | var actual = posts2[0];
206 |
207 | var titles = actual.GetDynamicPropertyValue("Titles") as ICollection;
208 |
209 | CollectionAssert.AreEqual(expected.Titles as ICollection, titles);
210 | }
211 | }
212 |
213 | [TestMethod]
214 | public void GroupWithNullCheckComplex()
215 | {
216 | var limitResult = TestData.Authors.AsQueryable();
217 |
218 | var posts = limitResult
219 | .GroupBy(t => new
220 | {
221 | Titles = t.Posts == null ? new List() : t.Posts.Select(t2 => t2.Title)
222 | })
223 | .Select(t => new
224 | {
225 | Titles = t.Key.Titles,
226 | Data = t.ToList()
227 | })
228 | .ToList();
229 |
230 | var tempQueryable = limitResult
231 | .GroupBy(gb => gb.NullChecking().Path("Posts.Title", "Titles"));
232 |
233 |
234 | var posts2 = tempQueryable
235 | .Select(sb =>
236 | {
237 | sb.Key("Titles");
238 | sb.ToList("Data");
239 | })
240 | .ToDynamicClassList();
241 |
242 | Assert.AreEqual(posts.Count, posts2.Count);
243 | for (var i = 0; i < posts.Count; i++)
244 | {
245 | var expected = posts[0];
246 | var actual = posts2[0];
247 |
248 | var titles = actual.GetDynamicPropertyValue("Titles") as ICollection;
249 |
250 | CollectionAssert.AreEqual(expected.Titles as ICollection, titles);
251 | }
252 | }
253 |
254 | [TestMethod]
255 | public void GroupByToListWithPath()
256 | {
257 | var limitResult = TestData.Posts.Where(t => t.Author != null);
258 |
259 | var expected = limitResult.GroupBy(t => new
260 | {
261 | AuthorFirstName = t.Author.FirstName
262 | })
263 | .Select(t => new
264 | {
265 | Key = t.Key.AuthorFirstName,
266 | Contents = t.Select(t2 => t2.Content).ToList()
267 | })
268 | .ToList();
269 |
270 | var actualQuery = limitResult
271 | .GroupBy(t => t.Path("Author.FirstName", "AuthorFirstName"))
272 | .Select(t =>
273 | {
274 | t.Key("Key", "AuthorFirstName");
275 | t.ToList("Content", "Contents", SelectCollectionHandling.LeaveAsIs);
276 | });
277 |
278 | var actual = actualQuery.ToDynamicClassList();
279 |
280 | Assert.AreEqual(expected.Count, actual.Count);
281 | for(var i = 0; i < expected.Count; i++)
282 | {
283 | var itExpected = expected[i];
284 | var itActual = actual[i];
285 |
286 |
287 | Assert.AreEqual(itExpected.Key, itActual.GetDynamicPropertyValue("Key"));
288 | CollectionAssert.AreEqual(itExpected.Contents, itActual.GetDynamicPropertyValue("Contents") as ICollection);
289 | }
290 | }
291 |
292 | [TestMethod]
293 | public void GroupByToListWithPathWithNullCheckingWithFlattening()
294 | {
295 | var limitResult = TestData.Authors;
296 |
297 | var expected = limitResult.GroupBy(t => new
298 | {
299 | AuthorFirstName = t.FirstName
300 | })
301 | .Select(t => new
302 | {
303 | Key = t.Key.AuthorFirstName,
304 | Contents = t.SelectMany(t2 => t2.Posts == null ? new List() : t2.Posts.Select(t3 => t3.Content)).ToList()
305 | })
306 | .ToList();
307 |
308 | var actualQuery = limitResult
309 | .GroupBy(t => t.NullChecking().Path("FirstName", "AuthorFirstName"))
310 | .Select(t =>
311 | {
312 | t.NullChecking();
313 | t.Key("Key", "AuthorFirstName");
314 | t.ToList("Posts.Content", "Contents", SelectCollectionHandling.Flatten);
315 | });
316 |
317 | var actual = actualQuery.ToDynamicClassList();
318 |
319 | Assert.AreEqual(expected.Count, actual.Count);
320 | for (var i = 0; i < expected.Count; i++)
321 | {
322 | var itExpected = expected[i];
323 | var itActual = actual[i];
324 |
325 |
326 | Assert.AreEqual(itExpected.Key, itActual.GetDynamicPropertyValue("Key"));
327 | CollectionAssert.AreEqual(itExpected.Contents, itActual.GetDynamicPropertyValue("Contents") as ICollection);
328 | }
329 | }
330 |
331 | }
332 | }
333 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/Helpers/QueryableAssert.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PoweredSoft.DynamicLinq.Test.Helpers
9 | {
10 | public static class QueryableAssert
11 | {
12 | private static bool _sameList(IQueryable a, IQueryable b)
13 | where T : class
14 | {
15 | if (a.Count() != b.Count())
16 | return false;
17 |
18 | var listA = a.ToList();
19 | var listB = b.ToList();
20 | for (var i = 0; i < listA.Count; i++)
21 | {
22 | if (listA.ElementAt(i) != listB.ElementAt(i))
23 | return false;
24 | }
25 |
26 | return true;
27 | }
28 |
29 | public static void AreEqual(IQueryable a, IQueryable b)
30 | where T : class
31 | {
32 | Assert.IsTrue(_sameList(a, b));
33 | }
34 |
35 | public static void AreNotEqual(IQueryable a, IQueryable b)
36 | where T : class
37 | {
38 | Assert.IsFalse(_sameList(a, b));
39 | }
40 |
41 | public static void AreEqual(IQueryable a, IQueryable b, string message)
42 | where T : class
43 | {
44 | Assert.IsTrue(_sameList(a, b), message);
45 | }
46 |
47 | public static void AreNotEqual(IQueryable a, IQueryable b, string message)
48 | where T : class
49 | {
50 | Assert.IsFalse(_sameList(a, b), message);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/HelpersTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using PoweredSoft.DynamicLinq.Dal.Pocos;
6 | using PoweredSoft.DynamicLinq.Helpers;
7 |
8 | namespace PoweredSoft.DynamicLinq.Test
9 | {
10 | class Foo
11 | {
12 |
13 | }
14 |
15 | class ListOfFoo : List
16 | {
17 |
18 | }
19 |
20 | [TestClass]
21 | public class HelpersTests
22 | {
23 |
24 | [TestMethod]
25 | public void TestInheritanceOfListAsGenericEnumerableType()
26 | {
27 | var shouldBeTrue = QueryableHelpers.IsGenericEnumerable(typeof(ListOfFoo));
28 | Assert.IsTrue(shouldBeTrue);
29 | var type = QueryableHelpers.GetTypeOfEnumerable(typeof(ListOfFoo), true);
30 | Assert.IsTrue(type == typeof(Foo));
31 | }
32 |
33 | [TestMethod]
34 | public void TestCreateFilterExpression()
35 | {
36 | var authors = new List()
37 | {
38 | new Author
39 | {
40 | Id = 1,
41 | FirstName = "David",
42 | LastName = "Lebee",
43 | Posts = new List
44 | {
45 | new Post
46 | {
47 | Id = 1,
48 | AuthorId = 1,
49 | Title = "Match",
50 | Content = "ABC",
51 | Comments = new List()
52 | {
53 | new Comment()
54 | {
55 | Id = 1,
56 | DisplayName = "John Doe",
57 | CommentText = "!@#$!@#!@#",
58 | Email = "John.doe@me.com"
59 | }
60 | }
61 | },
62 | new Post
63 | {
64 | Id = 2,
65 | AuthorId = 1,
66 | Title = "Match",
67 | Content = "ABC",
68 | Comments = new List()
69 | }
70 | }
71 | },
72 | new Author
73 | {
74 | Id = 2,
75 | FirstName = "Chuck",
76 | LastName = "Norris",
77 | Posts = new List
78 | {
79 | new Post
80 | {
81 | Id = 3,
82 | AuthorId = 2,
83 | Title = "Match",
84 | Content = "ASD",
85 | Comments = new List()
86 | },
87 | new Post
88 | {
89 | Id = 4,
90 | AuthorId = 2,
91 | Title = "DontMatch",
92 | Content = "ASD",
93 | Comments = new List()
94 | }
95 | }
96 | }
97 | };
98 |
99 | // the query.
100 | var query = authors.AsQueryable();
101 |
102 | var allExpression = QueryableHelpers.CreateConditionExpression("Posts.Title", ConditionOperators.Equal, "Match", QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling.All);
103 | var anyExpression = QueryableHelpers.CreateConditionExpression("Posts.Title", ConditionOperators.Equal, "Match", QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling.Any);
104 | var anyExpression2 = QueryableHelpers.CreateConditionExpression("Posts.Comments.Email", ConditionOperators.Equal, "John.doe@me.com", QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling.Any);
105 | Assert.AreEqual(1, query.Count(allExpression));
106 | Assert.AreEqual(2, query.Count(anyExpression));
107 | Assert.AreEqual(1, query.Count(anyExpression2));
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/InTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using PoweredSoft.DynamicLinq;
6 | using PoweredSoft.DynamicLinq.Dal.Pocos;
7 | using PoweredSoft.DynamicLinq.Test.Helpers;
8 |
9 | namespace PoweredSoft.DynamicLinq.Test
10 | {
11 | [TestClass]
12 | public class InTests
13 | {
14 | [TestMethod]
15 | public void In()
16 | {
17 | IQueryable a, b;
18 | var ageGroup = new List() { 28, 27, 50 };
19 | a = TestData.Persons.AsQueryable().Query(t => t.In("Age", ageGroup));
20 | b = TestData.Persons.AsQueryable().Where(t => ageGroup.Contains(t.Age));
21 | QueryableAssert.AreEqual(a, b);
22 | }
23 |
24 | [TestMethod]
25 | public void NotIn()
26 | {
27 | IQueryable a, b;
28 | var ageGroup = new List() { 50, 58 };
29 | a = TestData.Persons.AsQueryable().Query(t => t.NotIn("Age", ageGroup));
30 | b = TestData.Persons.AsQueryable().Where(t => !ageGroup.Contains(t.Age));
31 | QueryableAssert.AreEqual(a, b);
32 | }
33 |
34 | [TestMethod]
35 | public void InString()
36 | {
37 | IQueryable a, b;
38 | var group = new List() { "David", "Michaela" };
39 | a = TestData.Persons.AsQueryable().Query(t => t.In("FirstName", group));
40 | b = TestData.Persons.AsQueryable().Where(t => group.Contains(t.FirstName));
41 | QueryableAssert.AreEqual(a, b);
42 | }
43 |
44 | [TestMethod]
45 | public void DiffTypeListConversion()
46 | {
47 | IQueryable a, b;
48 | var ageGroup = new List() { "28", "27", "50" };
49 | var ageGroupInt = ageGroup.Select(t => Convert.ToInt32(t)).ToList();
50 |
51 | a = TestData.Persons.AsQueryable().Query(t => t.In("Age", ageGroup));
52 | b = TestData.Persons.AsQueryable().Where(t => ageGroupInt.Contains(t.Age));
53 | QueryableAssert.AreEqual(a, b);
54 | }
55 |
56 | [TestMethod]
57 | public void MixingInWithCollectionPaths()
58 | {
59 | var titles = new List() { "Match" };
60 | var a = TestData.Authors.AsQueryable().Query(t => t.NullChecking(true).In("Posts.Title", titles));
61 | var b = TestData.Authors.AsQueryable().Where(t => t.Posts != null && t.Posts.Any(t2 => titles.Contains(t2.Title)));
62 | QueryableAssert.AreEqual(a, b);
63 | }
64 |
65 | [TestMethod]
66 | public void MixingInComplexPaths()
67 | {
68 | var authorsFirstNames = new List() { "David", "Pablo" };
69 | var a = TestData.Posts.AsQueryable().Query(t => t.In("Author.FirstName", authorsFirstNames));
70 | var b = TestData.Posts.AsQueryable().Where(t => authorsFirstNames.Contains(t.Author.FirstName));
71 | QueryableAssert.AreEqual(a, b);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/PoweredSoft.DynamicLinq.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/SelectTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using PoweredSoft.DynamicLinq.Dal.Pocos;
3 | using PoweredSoft.DynamicLinq.Test.Helpers;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace PoweredSoft.DynamicLinq.Test
11 | {
12 | public class Mock
13 | {
14 | public int Id { get; set; }
15 | public int ForeignId { get; set; }
16 | public decimal Total { get; set; }
17 |
18 | public List Bs { get; set; } = new List();
19 | }
20 |
21 | public class MockB
22 | {
23 | public List FirstNames { get; set; }
24 | }
25 |
26 | public class MockPerson
27 | {
28 | public string Name { get; set; }
29 | public MockListOfPhone Phones { get; set; }
30 | }
31 |
32 | public class MockPhone
33 | {
34 | public string Number { get; set; }
35 | }
36 |
37 | public class MockListOfPhone : List
38 | {
39 |
40 | }
41 |
42 | [TestClass]
43 | public class SelectTests
44 | {
45 | [TestMethod]
46 | public void TestSelectWithInheritedList()
47 | {
48 | var list = new List()
49 | {
50 | new MockPerson
51 | {
52 | Name = "David Lebee",
53 | Phones = new MockListOfPhone
54 | {
55 | new MockPhone
56 | {
57 | Number = "0000000000"
58 | }
59 | }
60 | },
61 | new MockPerson
62 | {
63 | Name = "Yubing Liang",
64 | Phones = new MockListOfPhone
65 | {
66 | new MockPhone
67 | {
68 | Number = "1111111111"
69 | }
70 | }
71 | }
72 | };
73 |
74 | var names = list.AsQueryable()
75 | .Where(t => t.Equal("Phones.Number", "1111111111"))
76 | .Select(t =>
77 | {
78 | t.Path("Name");
79 | t.FirstOrDefault("Phones.Number", "Number", SelectCollectionHandling.Flatten);
80 | })
81 | .ToDynamicClassList();
82 |
83 | Assert.IsTrue(names.Count() == 1);
84 | var firstPerson = names.First();
85 | Assert.AreEqual("Yubing Liang", firstPerson.GetDynamicPropertyValue("Name"));
86 | Assert.AreEqual("1111111111", firstPerson.GetDynamicPropertyValue("Number"));
87 | }
88 |
89 | [TestMethod]
90 | public void TestSelect()
91 | {
92 | var list = new List()
93 | {
94 | new Mock{
95 | Id = 1,
96 | ForeignId = 1,
97 | Total = 100,
98 | Bs = new List() {
99 | new MockB { FirstNames = new List{"David", "John" } }
100 | }
101 | },
102 | };
103 |
104 | var regularSyntaxA = list
105 | .AsQueryable()
106 | .Select(t => new
107 | {
108 | Id = t.Id,
109 | FirstNames = t.Bs.SelectMany(t2 => t2.FirstNames).ToList(),
110 | FirstNamesLists = t.Bs.Select(t2 => t2.FirstNames).ToList(),
111 | FirstFirstName = t.Bs.SelectMany(t2 => t2.FirstNames).First(),
112 | FirstOrDefaultFirstName = t.Bs.SelectMany(t2 => t2.FirstNames).FirstOrDefault(),
113 | LastFirstName = t.Bs.SelectMany(t2 => t2.FirstNames).Last(),
114 | LastOrDefaultFirstName = t.Bs.SelectMany(t2 => t2.FirstNames).LastOrDefault(),
115 |
116 | FirstFirstNameList = t.Bs.Select(t2 => t2.FirstNames).First(),
117 | FirstOrDefaultFirstNameList = t.Bs.Select(t2 => t2.FirstNames).FirstOrDefault(),
118 | LastFirstNameList = t.Bs.Select(t2 => t2.FirstNames).Last(),
119 | LastOrDefaultFirstNameList = t.Bs.Select(t2 => t2.FirstNames).LastOrDefault()
120 | });
121 |
122 | var regularSyntax = regularSyntaxA.ToList();
123 |
124 | var dynamicSyntax = list
125 | .AsQueryable()
126 | .Select(t =>
127 | {
128 | t.Path("Id");
129 | t.ToList("Bs.FirstNames", "FirstNames", SelectCollectionHandling.Flatten);
130 | t.ToList("Bs.FirstNames", "FirstNamesLists", SelectCollectionHandling.LeaveAsIs);
131 | t.First("Bs.FirstNames", "FirstFirstName", SelectCollectionHandling.Flatten);
132 | t.FirstOrDefault("Bs.FirstNames", "FirstOrDefaultFirstName", SelectCollectionHandling.Flatten);
133 | t.Last("Bs.FirstNames", "LastFirstName", SelectCollectionHandling.Flatten);
134 | t.LastOrDefault("Bs.FirstNames", "LastOrDefaultFirstName", SelectCollectionHandling.Flatten);
135 |
136 | t.First("Bs.FirstNames", "FirstFirstNameList", SelectCollectionHandling.LeaveAsIs);
137 | t.FirstOrDefault("Bs.FirstNames", "FirstOrDefaultFirstNameList", SelectCollectionHandling.LeaveAsIs);
138 | t.Last("Bs.FirstNames", "LastFirstNameList", SelectCollectionHandling.LeaveAsIs);
139 | t.LastOrDefault("Bs.FirstNames", "LastOrDefaultFirstNameList", SelectCollectionHandling.LeaveAsIs);
140 | })
141 | .ToDynamicClassList();
142 |
143 | Assert.AreEqual(regularSyntax.Count, dynamicSyntax.Count);
144 | for(var i = 0; i < regularSyntax.Count; i++)
145 | {
146 | Assert.AreEqual(regularSyntax[i].Id, dynamicSyntax[i].GetDynamicPropertyValue("Id"));
147 | Assert.AreEqual(regularSyntax[i].FirstFirstName, dynamicSyntax[i].GetDynamicPropertyValue("FirstFirstName"));
148 | Assert.AreEqual(regularSyntax[i].FirstOrDefaultFirstName, dynamicSyntax[i].GetDynamicPropertyValue("FirstOrDefaultFirstName"));
149 | Assert.AreEqual(regularSyntax[i].LastFirstName, dynamicSyntax[i].GetDynamicPropertyValue("LastFirstName"));
150 | Assert.AreEqual(regularSyntax[i].LastOrDefaultFirstName, dynamicSyntax[i].GetDynamicPropertyValue("LastOrDefaultFirstName"));
151 |
152 | CollectionAssert.AreEqual(regularSyntax[i].FirstFirstNameList, dynamicSyntax[i].GetDynamicPropertyValue>("FirstFirstNameList"));
153 | CollectionAssert.AreEqual(regularSyntax[i].FirstOrDefaultFirstNameList, dynamicSyntax[i].GetDynamicPropertyValue>("FirstOrDefaultFirstNameList"));
154 | CollectionAssert.AreEqual(regularSyntax[i].LastFirstNameList, dynamicSyntax[i].GetDynamicPropertyValue>("LastFirstNameList"));
155 | CollectionAssert.AreEqual(regularSyntax[i].LastOrDefaultFirstNameList, dynamicSyntax[i].GetDynamicPropertyValue>("LastOrDefaultFirstNameList"));
156 |
157 |
158 | QueryableAssert.AreEqual(regularSyntax[i].FirstNames.AsQueryable(), dynamicSyntax[i].GetDynamicPropertyValue>("FirstNames").AsQueryable());
159 |
160 |
161 |
162 |
163 | var left = regularSyntax[i].FirstNamesLists;
164 | var right = dynamicSyntax[i].GetDynamicPropertyValue>>("FirstNamesLists");
165 | Assert.AreEqual(left.Count, right.Count);
166 | for(var j = 0; j < left.Count; j++)
167 | QueryableAssert.AreEqual(left[j].AsQueryable(), right[j].AsQueryable());
168 | }
169 | }
170 |
171 | [TestMethod]
172 | public void SelectNullChecking()
173 | {
174 | var query = TestData.Authors.AsQueryable();
175 |
176 |
177 | var qs = query.Select(t => new
178 | {
179 | CommentLikes = t.Posts == null ?
180 | new List() :
181 | t.Posts.Where(t2 => t2.Comments != null).SelectMany(t2 => t2.Comments.Where(t3 => t3.CommentLikes != null).SelectMany(t3 => t3.CommentLikes)).ToList()
182 | });
183 |
184 | var a = qs.ToList();
185 |
186 | var querySelect = query.Select(t =>
187 | {
188 | t.NullChecking(true);
189 | t.ToList("Posts.Comments.CommentLikes", selectCollectionHandling: SelectCollectionHandling.Flatten);
190 | });
191 |
192 | var b = querySelect.ToDynamicClassList();
193 |
194 | Assert.AreEqual(a.Count, b.Count);
195 | for(var i = 0; i < a.Count; i++)
196 | {
197 | var left = a[i];
198 | var right = b[i];
199 |
200 | var leftCommentLikes = left.CommentLikes;
201 | var rightCommentLikes = right.GetDynamicPropertyValue>("CommentLikes");
202 | QueryableAssert.AreEqual(leftCommentLikes.AsQueryable(), rightCommentLikes.AsQueryable());
203 | }
204 | }
205 |
206 | [TestMethod]
207 | public void SelectNullChecking2()
208 | {
209 | var query = TestData.Likes.AsQueryable();
210 |
211 | var qs = query.Select(t => new
212 | {
213 | Post = t.Comment == null || t.Comment.Post == null ? null : t.Comment.Post,
214 | Texts = (t.Comment == null || t.Comment.Post == null || t.Comment.Post.Comments == null ? new List() : t.Comment.Post.Comments.Select(t2 => t2.CommentText)).ToList()
215 | });
216 |
217 | var a = qs.ToList();
218 |
219 | var querySelect = query.Select(t =>
220 | {
221 | t.NullChecking(true);
222 | // this needs to be fixed.
223 | t.Path("Comment.CommentText", "CommentText2");
224 | //t.PathToList("Comment.Post.Comments.CommentText", selectCollectionHandling: SelectCollectionHandling.Flatten);
225 | });
226 |
227 | var b = querySelect.ToDynamicClassList();
228 | }
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/ShortcutTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using PoweredSoft.DynamicLinq;
6 | using PoweredSoft.DynamicLinq.Test.Helpers;
7 |
8 | namespace PoweredSoft.DynamicLinq.Test
9 | {
10 | [TestClass]
11 | public class ShortcutTests
12 | {
13 | internal List Persons = new List
14 | {
15 | new MockPersonObject { FirstName = "David", LastName = "Lebee", Age = 28 },
16 | new MockPersonObject { FirstName = "Michaela", LastName = "Vickar", Age = 27 },
17 | new MockPersonObject { FirstName = "John", LastName = "Doe", Age = 28 },
18 | new MockPersonObject { FirstName = "Chuck", LastName = "Norris", Age = 50 },
19 | new MockPersonObject { FirstName = "Michael", LastName = "Jackson", Age = 58 }
20 | };
21 |
22 |
23 | [TestMethod]
24 | public void Equal()
25 | {
26 | // test simple
27 | var q1 = Persons.AsQueryable().Query(t => t.Equal("FirstName", "David"));
28 | var q1b = Persons.AsQueryable().Where(t => t.FirstName == "David");
29 | QueryableAssert.AreEqual(q1, q1b);
30 |
31 | // test and
32 | var q2 = Persons.AsQueryable().Query(t => t.Equal("FirstName", "David").AndEqual("LastName", "Lebee"));
33 | var q2b = Persons.AsQueryable().Where(t => t.FirstName == "David" && t.LastName == "Lebee");
34 | QueryableAssert.AreEqual(q2, q2b);
35 |
36 |
37 | // test or
38 | var q3 = Persons.AsQueryable().Query(t => t.Equal("FirstName", "David").OrEqual("FirstName", "Michaela"));
39 | var q3b = Persons.AsQueryable().Where(t => t.FirstName == "David" || t.FirstName == "Michaela");
40 | QueryableAssert.AreEqual(q3, q3b);
41 | }
42 |
43 | [TestMethod]
44 | public void NotEqual()
45 | {
46 | // test simple
47 | var q1 = Persons.AsQueryable().Query(t => t.NotEqual("FirstName", "David"));
48 | var q1b = Persons.AsQueryable().Where(t => t.FirstName != "David");
49 | QueryableAssert.AreEqual(q1, q1b);
50 |
51 | // test and
52 | var q2 = Persons.AsQueryable().Query(t => t.NotEqual("FirstName", "David").AndNotEqual("FirstName", "Michaela"));
53 | var q2b = Persons.AsQueryable().Where(t => t.FirstName != "David" && t.FirstName != "Michaela");
54 | QueryableAssert.AreEqual(q2, q2b);
55 |
56 | // test or
57 | var q3 = Persons.AsQueryable().Query(t => t.NotEqual("FirstName", "David").OrNotEqual("LastName", "Lebee"));
58 | var q3b = Persons.AsQueryable().Where(t => t.FirstName != "David" || t.LastName != "Lebee");
59 | QueryableAssert.AreEqual(q3, q3b);
60 | }
61 |
62 | [TestMethod]
63 | public void GreatThan()
64 | {
65 | var q1 = Persons.AsQueryable().Query(t => t.GreaterThan("Age", 28));
66 | var q1b = Persons.AsQueryable().Where(t => t.Age > 28);
67 | QueryableAssert.AreEqual(q1, q1b);
68 |
69 | var q2 = Persons.AsQueryable().Query(t => t.GreaterThan("Age", 28).AndGreaterThan("Age", 50));
70 | var q2b = Persons.AsQueryable().Where(t => t.Age > 28 && t.Age > 50);
71 | QueryableAssert.AreEqual(q2, q2b);
72 |
73 | var q3 = Persons.AsQueryable().Query(t => t.GreaterThan("Age", 28).OrGreaterThan("Age", 50));
74 | var q3b = Persons.AsQueryable().Where(t => t.Age > 28 || t.Age > 50);
75 | QueryableAssert.AreEqual(q3, q3b);
76 | }
77 |
78 | [TestMethod]
79 | public void GreatThanOrEqual()
80 | {
81 | var q1 = Persons.AsQueryable().Query(t => t.GreaterThanOrEqual("Age", 28));
82 | var q1b = Persons.AsQueryable().Where(t => t.Age >= 28);
83 | QueryableAssert.AreEqual(q1, q1b);
84 |
85 | var q2 = Persons.AsQueryable().Query(t => t.GreaterThanOrEqual("Age", 28).AndGreaterThanOrEqual("Age", 50));
86 | var q2b = Persons.AsQueryable().Where(t => t.Age >= 28 && t.Age >= 50);
87 | QueryableAssert.AreEqual(q2, q2b);
88 |
89 | var q3 = Persons.AsQueryable().Query(t => t.GreaterThanOrEqual("Age", 28).OrGreaterThanOrEqual("Age", 50));
90 | var q3b = Persons.AsQueryable().Where(t => t.Age >= 28 || t.Age >= 50);
91 | QueryableAssert.AreEqual(q3, q3b);
92 | }
93 |
94 | [TestMethod]
95 | public void LessThan()
96 | {
97 | var q1 = Persons.AsQueryable().Query(t => t.LessThan("Age", 50));
98 | var q1b = Persons.AsQueryable().Where(t => t.Age < 50);
99 | QueryableAssert.AreEqual(q1, q1b);
100 |
101 | var q2 = Persons.AsQueryable().Query(t => t.LessThan("Age", 28).AndLessThan("Age", 50));
102 | var q2b = Persons.AsQueryable().Where(t => t.Age < 28 && t.Age < 50);
103 | QueryableAssert.AreEqual(q2, q2b);
104 |
105 | var q3 = Persons.AsQueryable().Query(t => t.LessThan("Age", 28).OrLessThan("Age", 50));
106 | var q3b = Persons.AsQueryable().Where(t => t.Age < 28 || t.Age < 50);
107 | QueryableAssert.AreEqual(q3, q3b);
108 | }
109 |
110 | [TestMethod]
111 | public void LessThanOrEqual()
112 | {
113 | var q1 = Persons.AsQueryable().Query(t => t.LessThanOrEqual("Age", 50));
114 | var q1b = Persons.AsQueryable().Where(t => t.Age <= 50);
115 | QueryableAssert.AreEqual(q1, q1b);
116 |
117 | var q2 = Persons.AsQueryable().Query(t => t.LessThanOrEqual("Age", 28).AndLessThanOrEqual("Age", 50));
118 | var q2b = Persons.AsQueryable().Where(t => t.Age <= 28 && t.Age <= 50);
119 | QueryableAssert.AreEqual(q2, q2b);
120 |
121 | var q3 = Persons.AsQueryable().Query(t => t.LessThanOrEqual("Age", 28).OrLessThanOrEqual("Age", 50));
122 | var q3b = Persons.AsQueryable().Where(t => t.Age <= 28 || t.Age <= 50);
123 | QueryableAssert.AreEqual(q3, q3b);
124 | }
125 |
126 | [TestMethod]
127 | public void StartsWith()
128 | {
129 | var q1 = Persons.AsQueryable().Query(t => t.StartsWith("FirstName", "Mi"));
130 | var q1b = Persons.AsQueryable().Where(t => t.FirstName.StartsWith("Mi"));
131 | QueryableAssert.AreEqual(q1, q1b);
132 |
133 | var q2 = Persons.AsQueryable().Query(t => t.StartsWith("FirstName", "Mi").AndStartsWith("LastName", "Vi"));
134 | var q2b = Persons.AsQueryable().Where(t => t.FirstName.StartsWith("Mi") && t.LastName.StartsWith("Vi"));
135 | QueryableAssert.AreEqual(q2, q2b);
136 |
137 | var q3 = Persons.AsQueryable().Query(t => t.StartsWith("FirstName", "Mi").OrStartsWith("FirstName", "Da"));
138 | var q3b = Persons.AsQueryable().Where(t => t.FirstName.StartsWith("Mi") || t.FirstName.StartsWith("Da"));
139 | QueryableAssert.AreEqual(q3, q3b);
140 | }
141 |
142 | [TestMethod]
143 | public void EndsWith()
144 | {
145 | var q1 = Persons.AsQueryable().Query(t => t.EndsWith("LastName", "ee"));
146 | var q1b = Persons.AsQueryable().Where(t => t.LastName.EndsWith("ee"));
147 | QueryableAssert.AreEqual(q1, q1b);
148 |
149 | var q2 = Persons.AsQueryable().Query(t => t.EndsWith("LastName", "ee").AndEndsWith("FirstName", "vid"));
150 | var q2b = Persons.AsQueryable().Where(t => t.LastName.EndsWith("ee") && t.FirstName.EndsWith("vid"));
151 | QueryableAssert.AreEqual(q2, q2b);
152 |
153 | var q3 = Persons.AsQueryable().Query(t => t.EndsWith("LastName", "ee").OrEndsWith("LastName", "ar"));
154 | var q3b = Persons.AsQueryable().Where(t => t.LastName.EndsWith("ee") || t.LastName.EndsWith("ar"));
155 | QueryableAssert.AreEqual(q3, q3b);
156 | }
157 |
158 | [TestMethod]
159 | public void Contains()
160 | {
161 | var q1 = Persons.AsQueryable().Query(t => t.Contains("LastName", "ee"));
162 | var q1b = Persons.AsQueryable().Where(t => t.LastName.Contains("ee"));
163 | QueryableAssert.AreEqual(q1, q1b);
164 |
165 | var q2 = Persons.AsQueryable().Query(t => t.Contains("LastName", "ee").AndContains("FirstName", "vid"));
166 | var q2b = Persons.AsQueryable().Where(t => t.LastName.Contains("ee") && t.FirstName.Contains("vid"));
167 | QueryableAssert.AreEqual(q2, q2b);
168 |
169 | var q3 = Persons.AsQueryable().Query(t => t.Contains("LastName", "ee").OrContains("LastName", "ar"));
170 | var q3b = Persons.AsQueryable().Where(t => t.LastName.Contains("ee") || t.LastName.Contains("ar"));
171 | QueryableAssert.AreEqual(q3, q3b);
172 | }
173 |
174 | [TestMethod]
175 | public void NotContains()
176 | {
177 | var q1 = Persons.AsQueryable().Query(t => t.Contains("LastName", "ee", negate: true));
178 | var q1b = Persons.AsQueryable().Where(t => !t.LastName.Contains("ee"));
179 | QueryableAssert.AreEqual(q1, q1b);
180 | }
181 |
182 | [TestMethod]
183 | public void NotContains2()
184 | {
185 | var q1 = Persons.AsQueryable().Query(t => t.NotContains("LastName", "ee"));
186 | var q1b = Persons.AsQueryable().Where(t => !t.LastName.Contains("ee"));
187 | QueryableAssert.AreEqual(q1, q1b);
188 |
189 | var q2 = Persons.AsQueryable().Query(t => t.NotContains("LastName", "ee").AndNotContains("FirstName", "vid"));
190 | var q2b = Persons.AsQueryable().Where(t => !t.LastName.Contains("ee") && !t.FirstName.Contains("vid"));
191 | QueryableAssert.AreEqual(q2, q2b);
192 |
193 | var q3 = Persons.AsQueryable().Query(t => t.NotContains("LastName", "ee").OrNotContains("LastName", "ar"));
194 | var q3b = Persons.AsQueryable().Where(t => !t.LastName.Contains("ee") || !t.LastName.Contains("ar"));
195 | QueryableAssert.AreEqual(q3, q3b);
196 | }
197 |
198 | [TestMethod]
199 | public void ContainsAndNotContains()
200 | {
201 | var q1 = Persons.AsQueryable().Query(t => t.Contains("LastName", "s").AndNotContains("LastName", "r"));
202 | var q1b = Persons.AsQueryable().Where(t => t.LastName.Contains("s") && !t.LastName.Contains("r"));
203 | QueryableAssert.AreEqual(q1, q1b);
204 | }
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/SimpleQueriesTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using PoweredSoft.DynamicLinq.Dal.Pocos;
7 | using PoweredSoft.DynamicLinq;
8 |
9 | namespace PoweredSoft.DynamicLinq.Test
10 | {
11 | [TestClass]
12 | public class SimpleQueryTests
13 | {
14 | [TestMethod]
15 | public void Equal()
16 | {
17 | // subject.
18 | var authors = new List()
19 | {
20 | new Author { Id = long.MaxValue, FirstName = "David", LastName = "Lebee" }
21 | };
22 |
23 | // the query.
24 | var query = authors.AsQueryable();
25 |
26 | // simple where.
27 | var newQuery = query.Where("FirstName", ConditionOperators.Equal, "David");
28 |
29 | // must match.
30 | Assert.IsTrue(newQuery.Any(), "Must have at least one author that matches");
31 | }
32 |
33 | [TestMethod]
34 | public void EqualLowerCase()
35 | {
36 | // subject.
37 | var authors = new List()
38 | {
39 | new Author { Id = long.MaxValue, FirstName = "David", LastName = "Lebee" }
40 | };
41 |
42 | // the query.
43 | var query = authors.AsQueryable();
44 |
45 | // simple where.
46 | var newQuery = query.Where("FirstName.ToLower()", ConditionOperators.Equal, "david");
47 |
48 | // must match.
49 | Assert.IsTrue(newQuery.Any(), "Must have at least one author that matches");
50 | }
51 |
52 | [TestMethod]
53 | public void EqualLowerCaseNullCheck()
54 | {
55 | // subject.
56 | var authors = new List()
57 | {
58 | new Author { Id = long.MaxValue, FirstName = null, LastName = "Lebee" },
59 | new Author { Id = long.MaxValue, FirstName = "David", LastName = "Lebee" },
60 | };
61 |
62 | // the query.
63 | var query = authors.AsQueryable();
64 |
65 | // simple where.
66 | var newQuery = query.Where(wb =>
67 | {
68 | wb.Equal("FirstName.ToLower()", "david").NullChecking(true);
69 | });
70 |
71 | // must match.
72 | Assert.IsTrue(newQuery.Any(), "Must have at least one author that matches");
73 | }
74 |
75 | [TestMethod]
76 | public void DoubleMethodCheck()
77 | {
78 | // subject.
79 | var authors = new List()
80 | {
81 | new Author { Id = long.MaxValue, FirstName = "David ", LastName = "Lebee" },
82 | };
83 |
84 | // the query.
85 | var query = authors.AsQueryable();
86 |
87 | // simple where.
88 | var newQuery = query.Where(wb =>
89 | {
90 | wb.Equal("FirstName.Trim().ToLower()", "david").NullChecking(true);
91 | });
92 |
93 | // must match.
94 | Assert.IsTrue(newQuery.Any(), "Must have at least one author that matches");
95 | }
96 |
97 | [TestMethod]
98 | public void Contains()
99 | {
100 | // subject.
101 | var authors = new List()
102 | {
103 | new Author { Id = long.MaxValue, FirstName = "David", LastName = "Lebee" }
104 | };
105 |
106 | // the query.
107 | var query = authors.AsQueryable();
108 |
109 | // simple where.
110 | var newQuery = query.Where("FirstName", ConditionOperators.Contains, "Da");
111 |
112 | // must match.
113 | Assert.IsTrue(newQuery.Any(), "Must have at least one author that matches");
114 | }
115 |
116 | [TestMethod]
117 | public void StartsWith()
118 | {
119 | // subject.
120 | var authors = new List()
121 | {
122 | new Author { Id = long.MaxValue, FirstName = "David", LastName = "Lebee" }
123 | };
124 |
125 | // the query.
126 | var query = authors.AsQueryable();
127 |
128 | // simple where.
129 | var newQuery = query.Where("FirstName", ConditionOperators.StartsWith, "Da");
130 |
131 | // must match.
132 | Assert.IsTrue(newQuery.Any(), "Must have at least one author that matches");
133 | }
134 |
135 | [TestMethod]
136 | public void EndsWith()
137 | {
138 | // subject.
139 | var authors = new List()
140 | {
141 | new Author { Id = long.MaxValue, FirstName = "David", LastName = "Lebee" }
142 | };
143 |
144 | // the query.
145 | var query = authors.AsQueryable();
146 |
147 | // simple where.
148 | var newQuery = query.Where("FirstName", ConditionOperators.EndsWith, "Da");
149 |
150 | // must match.
151 | Assert.IsFalse(newQuery.Any(), "Not suppose to find any matches");
152 | }
153 |
154 | [TestMethod]
155 | public void LessThen()
156 | {
157 | // subject.
158 | var posts = new List()
159 | {
160 | new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World" },
161 | new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World" },
162 | new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World" },
163 | };
164 |
165 | // the query.
166 | var query = posts.AsQueryable();
167 |
168 | // simple where.
169 | var newQuery = query.Where("AuthorId", ConditionOperators.LessThan, 2);
170 |
171 | // must match.
172 | Assert.AreEqual(2, newQuery.Count());
173 | }
174 |
175 | [TestMethod]
176 | public void GreaterThanOrEqual()
177 | {
178 | // subject.
179 | var posts = new List()
180 | {
181 | new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World" },
182 | new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World" },
183 | new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World" },
184 | };
185 |
186 | // the query.
187 | var query = posts.AsQueryable();
188 |
189 | // simple where.
190 | var newQuery = query.Where("AuthorId", ConditionOperators.GreaterThanOrEqual, 2);
191 |
192 | // must match.
193 | Assert.AreEqual(1, newQuery.Count());
194 | }
195 |
196 | [TestMethod]
197 | public void TestingSort()
198 | {
199 | // subject.
200 | var posts = new List()
201 | {
202 | new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World"},
203 | new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World"},
204 | new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World"},
205 | };
206 |
207 | // the query.
208 | var query = posts.AsQueryable();
209 | query = query.OrderByDescending("AuthorId");
210 | query = query.ThenBy("Id");
211 |
212 | var first = query.First();
213 | var second = query.Skip(1).First();
214 |
215 | Assert.IsTrue(first.Id == 3);
216 | Assert.IsTrue(second.Id == 1);
217 | }
218 |
219 | [TestMethod]
220 | public void TestingSort2()
221 | {
222 | // subject.
223 | var posts = new List()
224 | {
225 | new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World", Comments = new List { } },
226 | new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World", Comments = new List { } },
227 | new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World", Comments = new List { } },
228 | };
229 |
230 | // the query.
231 | var query = posts.AsQueryable();
232 |
233 | // just testing that the expressionm can be created, some drivers support seleting in collections.
234 | var query2 = query.OrderByDescending("Comments");
235 | var query3 = query.OrderByDescending("Comments.PostId");
236 | }
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/StringComparision.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using PoweredSoft.DynamicLinq;
6 | using PoweredSoft.DynamicLinq.Test.Helpers;
7 |
8 | namespace PoweredSoft.DynamicLinq.Test
9 | {
10 | [TestClass]
11 | public class StringComparisionTests
12 | {
13 | internal List Persons => TestData.Persons;
14 |
15 | [TestMethod]
16 | public void Equal()
17 | {
18 | IQueryable a, b;
19 |
20 | // case sensitive.
21 | a = Persons.AsQueryable().Query(t => t.Equal("FirstName", "David", stringComparision: null));
22 | b = Persons.AsQueryable().Where(t => t.FirstName == "David");
23 | QueryableAssert.AreEqual(a, b, "CaseSensitive");
24 |
25 | // not case sensitive
26 | a = Persons.AsQueryable().Query(t => t.Equal("FirstName", "DAVID", stringComparision: StringComparison.OrdinalIgnoreCase));
27 | b = Persons.AsQueryable().Where(t => t.FirstName.Equals("DAVID", StringComparison.OrdinalIgnoreCase));
28 | QueryableAssert.AreEqual(a, b, "CaseInsensitive");
29 | }
30 |
31 | [TestMethod]
32 | public void NotEqual()
33 | {
34 | IQueryable a, b;
35 |
36 | // case sensitive.
37 | a = Persons.AsQueryable().Query(t => t.NotEqual("FirstName", "David", stringComparision: null));
38 | b = Persons.AsQueryable().Where(t => t.FirstName != "David");
39 | QueryableAssert.AreEqual(a, b, "CaseSensitive");
40 |
41 | // not case sensitive
42 | a = Persons.AsQueryable().Query(t => t.NotEqual("FirstName", "DAVID", stringComparision: StringComparison.OrdinalIgnoreCase));
43 | b = Persons.AsQueryable().Where(t => !t.FirstName.Equals("DAVID", StringComparison.OrdinalIgnoreCase));
44 | QueryableAssert.AreEqual(a, b, "CaseInsensitive");
45 | }
46 |
47 | [TestMethod]
48 | public void Contains()
49 | {
50 | IQueryable a, b;
51 |
52 | // case sensitive.
53 | a = Persons.AsQueryable().Query(t => t.Contains("FirstName", "vi", stringComparision: null));
54 | b = Persons.AsQueryable().Where(t => t.FirstName.Contains("vi"));
55 | QueryableAssert.AreEqual(a, b, "CaseSensitive");
56 |
57 | // not case sensitive
58 | a = Persons.AsQueryable().Query(t => t.Contains("FirstName", "VI", stringComparision: StringComparison.OrdinalIgnoreCase));
59 | b = Persons.AsQueryable().Where(t => t.FirstName.IndexOf("VI", StringComparison.OrdinalIgnoreCase) > -1);
60 | QueryableAssert.AreEqual(a, b, "CaseInsensitive");
61 | }
62 |
63 | [TestMethod]
64 | public void NotContains()
65 | {
66 | IQueryable a, b;
67 |
68 | // case sensitive.
69 | a = Persons.AsQueryable().Query(t => t.NotContains("FirstName", "vi", stringComparision: null));
70 | b = Persons.AsQueryable().Where(t => !t.FirstName.Contains("vi"));
71 | QueryableAssert.AreEqual(a, b, "CaseSensitive");
72 |
73 | // not case sensitive
74 | a = Persons.AsQueryable().Query(t => t.NotContains("FirstName", "VI", stringComparision: StringComparison.OrdinalIgnoreCase));
75 | b = Persons.AsQueryable().Where(t => t.FirstName.IndexOf("VI", StringComparison.OrdinalIgnoreCase) == -1);
76 | QueryableAssert.AreEqual(a, b, "CaseInsensitive");
77 | }
78 |
79 | [TestMethod]
80 | public void NegateNotContains()
81 | {
82 | IQueryable a, b;
83 |
84 | // case sensitive.
85 | a = Persons.AsQueryable().Query(t => t.NotContains("FirstName", "vi", stringComparision: null, negate: true));
86 | b = Persons.AsQueryable().Where(t => !!t.FirstName.Contains("vi"));
87 | QueryableAssert.AreEqual(a, b, "CaseSensitive");
88 |
89 | // not case sensitive
90 | a = Persons.AsQueryable().Query(t => t.NotContains("FirstName", "VI", stringComparision: StringComparison.OrdinalIgnoreCase, negate: true));
91 | b = Persons.AsQueryable().Where(t => !(t.FirstName.IndexOf("VI", StringComparison.OrdinalIgnoreCase) == -1));
92 | QueryableAssert.AreEqual(a, b, "CaseInsensitive");
93 | }
94 |
95 | [TestMethod]
96 | public void StartsWith()
97 | {
98 | IQueryable a, b;
99 |
100 | // case sensitive.
101 | a = Persons.AsQueryable().Query(t => t.StartsWith("FirstName", "Da", stringComparision: null));
102 | b = Persons.AsQueryable().Where(t => t.FirstName.StartsWith("Da"));
103 | QueryableAssert.AreEqual(a, b, "CaseSensitive");
104 |
105 | // not case sensitive
106 | a = Persons.AsQueryable().Query(t => t.StartsWith("FirstName", "DA", stringComparision: StringComparison.OrdinalIgnoreCase));
107 | b = Persons.AsQueryable().Where(t => t.FirstName.StartsWith("DA", StringComparison.OrdinalIgnoreCase));
108 | QueryableAssert.AreEqual(a, b, "CaseInsensitive");
109 | }
110 |
111 | [TestMethod]
112 | public void EndsWith()
113 | {
114 | IQueryable a, b;
115 |
116 | // case sensitive.
117 | a = Persons.AsQueryable().Query(t => t.EndsWith("FirstName", "vid", stringComparision: null));
118 | b = Persons.AsQueryable().Where(t => t.FirstName.EndsWith("vid"));
119 | QueryableAssert.AreEqual(a, b, "CaseSensitive");
120 |
121 | // not case sensitive
122 | a = Persons.AsQueryable().Query(t => t.EndsWith("FirstName", "VID", stringComparision: StringComparison.OrdinalIgnoreCase));
123 | b = Persons.AsQueryable().Where(t => t.FirstName.EndsWith("VID", StringComparison.OrdinalIgnoreCase));
124 | QueryableAssert.AreEqual(a, b, "CaseInsensitive");
125 | }
126 |
127 | [DataTestMethod]
128 | [DataRow("Denis")]
129 | [DataRow("Ann")]
130 | [DataRow("Tony")]
131 | public void LessThan(string firstName)
132 | {
133 | IQueryable a, b;
134 |
135 | a = Persons.AsQueryable().Query(t => t.LessThan("FirstName", firstName));
136 | b = Persons.AsQueryable().Where(t => t.FirstName.CompareTo(firstName) < 0);
137 | QueryableAssert.AreEqual(a, b);
138 | }
139 |
140 | [DataTestMethod]
141 | [DataRow("Denis")]
142 | [DataRow("Ann")]
143 | [DataRow("Tony")]
144 | public void LessThanOrEqual(string firstName)
145 | {
146 | IQueryable a, b;
147 |
148 | a = Persons.AsQueryable().Query(t => t.LessThanOrEqual("FirstName", firstName));
149 | b = Persons.AsQueryable().Where(t => t.FirstName.CompareTo(firstName) <= 0);
150 | QueryableAssert.AreEqual(a, b);
151 | }
152 |
153 | [DataTestMethod]
154 | [DataRow("Denis")]
155 | [DataRow("Ann")]
156 | [DataRow("Tony")]
157 | public void GreaterThan(string firstName)
158 | {
159 | IQueryable a, b;
160 |
161 | a = Persons.AsQueryable().Query(t => t.GreaterThan("FirstName", firstName));
162 | b = Persons.AsQueryable().Where(t => t.FirstName.CompareTo(firstName) > 0);
163 | QueryableAssert.AreEqual(a, b);
164 | }
165 |
166 | [DataTestMethod]
167 | [DataRow("Denis")]
168 | [DataRow("Ann")]
169 | [DataRow("Tony")]
170 | public void GreaterThanOrEqual(string firstName)
171 | {
172 | IQueryable a, b;
173 |
174 | a = Persons.AsQueryable().Query(t => t.GreaterThanOrEqual("FirstName", firstName));
175 | b = Persons.AsQueryable().Where(t => t.FirstName.CompareTo(firstName) >= 0);
176 | QueryableAssert.AreEqual(a, b);
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.Test/TestData.cs:
--------------------------------------------------------------------------------
1 | using PoweredSoft.DynamicLinq.Dal.Pocos;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PoweredSoft.DynamicLinq.Test
9 | {
10 | internal class MockPersonObject
11 | {
12 | public string FirstName { get; set; }
13 |
14 | public string LastName { get; set; }
15 |
16 | public int Age { get; set; }
17 | }
18 |
19 | internal class MockSale
20 | {
21 | public long Id { get; set; }
22 | public int ClientId { get; set; }
23 | public MockClient Client { get; set; }
24 | public decimal GrossSales { get; set; }
25 | public decimal NetSales { get; set; }
26 | public decimal Tax { get; set; }
27 | }
28 |
29 | internal class MockClient
30 | {
31 | public long Id { get; set; }
32 | public string Name { get; set; }
33 | }
34 |
35 | internal static class TestData
36 | {
37 | static readonly internal List Uniques = new List
38 | {
39 | new Unique { Id = 1, RowNumber = Guid.NewGuid(), OtherNullableGuid = null } ,
40 | new Unique { Id = 2, RowNumber = Guid.NewGuid(), OtherNullableGuid = Guid.NewGuid() }
41 | };
42 |
43 | static readonly internal List Persons = new List
44 | {
45 | new MockPersonObject { FirstName = "David", LastName = "Lebee", Age = 28 },
46 | new MockPersonObject { FirstName = "Michaela", LastName = "Vickar", Age = 27 },
47 | new MockPersonObject { FirstName = "John", LastName = "Doe", Age = 28 },
48 | new MockPersonObject { FirstName = "Chuck", LastName = "Norris", Age = 50 },
49 | new MockPersonObject { FirstName = "Michael", LastName = "Jackson", Age = 58 }
50 | };
51 |
52 | static readonly internal List Clients = new List
53 | {
54 | new MockClient { Id = 1, Name = "ACME INC."},
55 | new MockClient { Id = 2, Name = "MSLINK" },
56 | new MockClient { Id = 3, Name = "COOL GUYS TBD"},
57 | new MockClient { Id = 4, Name = "SOME LLC YEAH!" }
58 | };
59 |
60 | static readonly internal List Sales = new List
61 | {
62 | new MockSale { Id = 1, ClientId = 1, Client = Clients.First(t => t.Id == 1), GrossSales = 1000M, NetSales = 890.0M, Tax = 20M },
63 | new MockSale { Id = 2, ClientId = 1, Client = Clients.First(t => t.Id == 1), GrossSales = 1100M, NetSales = 180.0M, Tax = 0M },
64 | new MockSale { Id = 3, ClientId = 2, Client = Clients.First(t => t.Id == 2), GrossSales = 1200M, NetSales = 920.0M, Tax = 3M },
65 | new MockSale { Id = 4, ClientId = 2, Client = Clients.First(t => t.Id == 2), GrossSales = 1330M, NetSales = 800.0M, Tax = 120M },
66 | new MockSale { Id = 5, ClientId = 1, Client = Clients.First(t => t.Id == 1), GrossSales = 1400M, NetSales = 990.0M, Tax = 20M },
67 | new MockSale { Id = 6, ClientId = 3, Client = Clients.First(t => t.Id == 3), GrossSales = 1500M, NetSales = 290.0M, Tax = 200M },
68 | new MockSale { Id = 7, ClientId = 3, Client = Clients.First(t => t.Id == 3), GrossSales = 1600M, NetSales = 230.0M, Tax = 240M },
69 | new MockSale { Id = 8, ClientId = 3, Client = Clients.First(t => t.Id == 3), GrossSales = 1700M, NetSales = 330.0M, Tax = 210M },
70 | new MockSale { Id = 9, ClientId = 1, Client = Clients.First(t => t.Id == 1), GrossSales = 1800M, NetSales = 890.0M, Tax = 290M },
71 | new MockSale { Id = 10, ClientId = 4, Client = Clients.First(t => t.Id == 4), GrossSales = 1900M, NetSales = 490.0M, Tax = 270M }
72 | };
73 |
74 | static readonly internal List Posts = new List()
75 | {
76 | new Post
77 | {
78 | Id = 1,
79 | Author = new Author()
80 | {
81 | Id = 1,
82 | FirstName = "David",
83 | LastName = "Lebee"
84 | },
85 | AuthorId = 1,
86 | CreateTime = DateTime.Now,
87 | Title = "Match",
88 | Content = "ABC",
89 | },
90 | new Post
91 | {
92 | Id = 2,
93 | Author = new Author()
94 | {
95 | Id = 1,
96 | FirstName = "David",
97 | LastName = "Lebee"
98 | },
99 | AuthorId = 1,
100 | CreateTime = DateTime.Now,
101 | Title = "Match 2",
102 | Content = "ABC 2",
103 | },
104 | new Post
105 | {
106 | Id = 3,
107 | Author = new Author()
108 | {
109 | Id = 2,
110 | FirstName = "John",
111 | LastName = "Doe"
112 | },
113 | AuthorId = 3,
114 | CreateTime = DateTime.Now,
115 | Title = "Match 3",
116 | Content = "ABC 3",
117 | },
118 | };
119 |
120 | static readonly internal List Likes = new List()
121 | {
122 | new CommentLike
123 | {
124 | Id = 1,
125 | CommentId = 1,
126 | Comment = new Comment
127 | {
128 | Email = "john@doe.ca",
129 | CommentText = "bla bla",
130 | Post = new Post
131 | {
132 | Content = "ASDFSADF"
133 | }
134 | }
135 | },
136 | new CommentLike
137 | {
138 | Id = 2,
139 | CommentId = 2
140 | }
141 | };
142 |
143 | static readonly internal List Authors = new List()
144 | {
145 | new Author
146 | {
147 | Id = 1,
148 | FirstName = "David",
149 | LastName = "Lebee",
150 | Posts = new List
151 | {
152 | new Post
153 | {
154 | Id = 1,
155 | AuthorId = 1,
156 | Title = "Match",
157 | Content = "ABC",
158 | Comments = new List()
159 | {
160 | new Comment()
161 | {
162 | Id = 1,
163 | DisplayName = "John Doe",
164 | CommentText = "!@#$!@#!@#",
165 | Email = "john.doe@me.com",
166 | CommentLikes = new List()
167 | {
168 | new CommentLike()
169 | {
170 | Id = 1,
171 | CommentId = 1,
172 | CreateTime = DateTimeOffset.Now
173 | },
174 | new CommentLike()
175 | {
176 | Id = 2,
177 | CommentId = 1,
178 | CreateTime = DateTimeOffset.Now
179 | },
180 | }
181 | }
182 | }
183 | },
184 | new Post
185 | {
186 | Id = 2,
187 | AuthorId = 1,
188 | Title = "Match",
189 | Content = "ABC"
190 | }
191 | }
192 | },
193 | new Author
194 | {
195 | Id = 2,
196 | FirstName = "Chuck",
197 | LastName = "Norris",
198 | Posts = new List
199 | {
200 | new Post
201 | {
202 | Id = 3,
203 | AuthorId = 2,
204 | Title = "Match",
205 | Content = "ASD"
206 | },
207 | new Post
208 | {
209 | Id = 4,
210 | AuthorId = 2,
211 | Title = "DontMatch",
212 | Content = "ASD"
213 | }
214 | }
215 | },
216 | new Author
217 | {
218 | Id = 3,
219 | FirstName = "Mark",
220 | LastName = "Ronson"
221 | }
222 | };
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29503.13
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.DynamicLinq", "PoweredSoft.DynamicLinq\PoweredSoft.DynamicLinq.csproj", "{5BB7E50F-8B40-4512-88DC-4B3BD89C9A5E}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.DynamicLinq.Test", "PoweredSoft.DynamicLinq.Test\PoweredSoft.DynamicLinq.Test.csproj", "{6F5C80F0-9045-4098-913F-7BDAD135E6DD}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.DynamicLinq.Dal", "PoweredSoft.DynamicLinq.Dal\PoweredSoft.DynamicLinq.Dal.csproj", "{C16927E7-1358-4B9D-BDD7-149E505DE6CC}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.DynamicLinq.EntityFramework", "PoweredSoft.DynamicLinq.EntityFramework\PoweredSoft.DynamicLinq.EntityFramework.csproj", "{82DADDB0-4A69-4E19-82AD-E73ABC8F1B4A}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{77B4027B-ECB0-4ED1-8646-025AC4146CE2}"
15 | ProjectSection(SolutionItems) = preProject
16 | LICENSE = LICENSE
17 | README.md = README.md
18 | EndProjectSection
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PoweredSoft.DynamicLinq.EntityFrameworkCore", "PoweredSoft.DynamicLinq.EntityFrameworkCore\PoweredSoft.DynamicLinq.EntityFrameworkCore.csproj", "{BBF5805B-560C-474B-885B-9202281B42F7}"
21 | EndProject
22 | Global
23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
24 | Debug|Any CPU = Debug|Any CPU
25 | Release|Any CPU = Release|Any CPU
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {5BB7E50F-8B40-4512-88DC-4B3BD89C9A5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {5BB7E50F-8B40-4512-88DC-4B3BD89C9A5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {5BB7E50F-8B40-4512-88DC-4B3BD89C9A5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {5BB7E50F-8B40-4512-88DC-4B3BD89C9A5E}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {6F5C80F0-9045-4098-913F-7BDAD135E6DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {6F5C80F0-9045-4098-913F-7BDAD135E6DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {6F5C80F0-9045-4098-913F-7BDAD135E6DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {6F5C80F0-9045-4098-913F-7BDAD135E6DD}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {C16927E7-1358-4B9D-BDD7-149E505DE6CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {C16927E7-1358-4B9D-BDD7-149E505DE6CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {C16927E7-1358-4B9D-BDD7-149E505DE6CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {C16927E7-1358-4B9D-BDD7-149E505DE6CC}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {82DADDB0-4A69-4E19-82AD-E73ABC8F1B4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {82DADDB0-4A69-4E19-82AD-E73ABC8F1B4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {82DADDB0-4A69-4E19-82AD-E73ABC8F1B4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {82DADDB0-4A69-4E19-82AD-E73ABC8F1B4A}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {BBF5805B-560C-474B-885B-9202281B42F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {BBF5805B-560C-474B-885B-9202281B42F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {BBF5805B-560C-474B-885B-9202281B42F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {BBF5805B-560C-474B-885B-9202281B42F7}.Release|Any CPU.Build.0 = Release|Any CPU
48 | EndGlobalSection
49 | GlobalSection(SolutionProperties) = preSolution
50 | HideSolutionNode = FALSE
51 | EndGlobalSection
52 | GlobalSection(ExtensibilityGlobals) = postSolution
53 | SolutionGuid = {EBCBC23C-D682-4818-A7AA-4142BF6989C2}
54 | EndGlobalSection
55 | EndGlobal
56 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq/Constants.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PoweredSoft.DynamicLinq
9 | {
10 | public enum ConditionOperators
11 | {
12 | Equal,
13 | NotEqual,
14 | GreaterThan,
15 | GreaterThanOrEqual,
16 | LessThan,
17 | LessThanOrEqual,
18 | Contains,
19 | NotContains,
20 | StartsWith,
21 | EndsWith,
22 | In,
23 | NotIn
24 | }
25 |
26 | public enum QueryConvertStrategy
27 | {
28 | LeaveAsIs,
29 | ConvertConstantToComparedPropertyOrField,
30 | SpecifyType
31 | }
32 |
33 | public enum QueryCollectionHandling
34 | {
35 | Any,
36 | All
37 | }
38 |
39 | public enum QueryOrderByDirection
40 | {
41 | Ascending,
42 | Descending
43 | }
44 |
45 | public enum SelectTypes
46 | {
47 | Key,
48 | Count,
49 | LongCount,
50 | Sum,
51 | Average,
52 | ToList,
53 | Path,
54 | Min,
55 | Max,
56 | LastOrDefault,
57 | FirstOrDefault,
58 | Last,
59 | First,
60 | }
61 |
62 | public enum SelectCollectionHandling
63 | {
64 | LeaveAsIs,
65 | Flatten
66 | }
67 |
68 | internal static class Constants
69 | {
70 | internal static readonly MethodInfo GroupByMethod = typeof(Queryable).GetMethods().First(t => t.Name == "GroupBy");
71 | internal static readonly MethodInfo GroupByMethodWithEqualityComparer = typeof(Queryable).GetMethods().First(t => t.Name == "GroupBy" && t.GetParameters().Any(t2 => t2.Name == "comparer"));
72 | internal static readonly MethodInfo StringEqualWithComparisation = typeof(string).GetMethod("Equals", new Type[] { typeof(string), typeof(StringComparison) });
73 | internal static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
74 | internal static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
75 | internal static readonly MethodInfo StartsWithMethodWithComparisation = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string), typeof(StringComparison) });
76 | internal static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
77 | internal static readonly MethodInfo EndsWithMethodWithComparisation = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string), typeof(StringComparison) });
78 | internal static readonly MethodInfo IndexOfMethod = typeof(string).GetMethod("IndexOf", new Type[] { typeof(string), typeof(StringComparison) });
79 | internal static readonly MethodInfo AnyMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(t => t.Name == "Any" && t.GetParameters().Count() == 2);
80 | internal static readonly MethodInfo AllMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(t => t.Name == "All" && t.GetParameters().Count() == 2);
81 | internal static readonly MethodInfo CompareToMethod = typeof(string).GetMethod("CompareTo", new Type[] { typeof(string) });
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/PoweredSoft.DynamicLinq/DynamicType/DynamicClass.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Dynamic;
3 | using System.Reflection;
4 |
5 | namespace PoweredSoft.DynamicLinq
6 | {
7 | ///
8 | /// https://github.com/StefH/System.Linq.Dynamic.Core/blob/master/src/System.Linq.Dynamic.Core/DynamicClass.cs
9 | ///
10 | public abstract class DynamicClass : DynamicObject
11 | {
12 | private Dictionary _propertiesDictionary;
13 |
14 | private Dictionary Properties
15 | {
16 | get
17 | {
18 | if (_propertiesDictionary == null)
19 | {
20 | _propertiesDictionary = new Dictionary();
21 |
22 | foreach (PropertyInfo pi in GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
23 | {
24 | int parameters = pi.GetIndexParameters().Length;
25 | if (parameters > 0)
26 | {
27 | // The property is an indexer, skip this.
28 | continue;
29 | }
30 |
31 | _propertiesDictionary.Add(pi.Name, pi.GetValue(this, null));
32 | }
33 | }
34 |
35 | return _propertiesDictionary;
36 | }
37 | }
38 |
39 | ///
40 | /// Gets the dynamic property by name.
41 | ///
42 | /// The type.
43 | /// Name of the property.
44 | /// T
45 | public T GetDynamicPropertyValue(string propertyName)
46 | {
47 | var type = GetType();
48 | var propInfo = type.GetProperty(propertyName);
49 |
50 | return (T)propInfo.GetValue(this, null);
51 | }
52 |
53 | ///
54 | /// Gets the dynamic property value by name.
55 | ///
56 | /// Name of the property.
57 | /// value
58 | public object GetDynamicPropertyValue(string propertyName)
59 | {
60 | return GetDynamicPropertyValue