├── .gitignore
├── CatFactory.EntityFrameworkCore.Tests
├── CatFactory.EntityFrameworkCore.Tests.csproj
├── MockTests.cs
├── Models
│ └── CollegeDatabase.cs
├── NamingConventionTests.cs
├── ProjectCreationTests.cs
├── ProjectSelectionTests.cs
├── ScaffoldingEventHandlersTests.cs
├── ScaffoldingTests.cs
└── ValueConversion.cs
├── CatFactory.EntityFrameworkCore.sln
├── CatFactory.EntityFrameworkCore
├── AuditEntity.cs
├── AuthorInfo.cs
├── CatFactory.EntityFrameworkCore.csproj
├── ConstraintExtensions.cs
├── DataLayerExtensions.cs
├── DatabaseExtensions.cs
├── DbObjectExtensions.cs
├── Definitions
│ ├── AuditEntityInterfaceDefinition.cs
│ ├── DataContractClassDefinition.cs
│ ├── DbContextClassDefinition.cs
│ ├── DbContextQueryExtensionsClassDefinition.cs
│ ├── EntityClassDefinition.cs
│ ├── EntityConfigurationClassDefinition.cs
│ ├── EntityInterfaceDefinition.cs
│ ├── Extensions
│ │ ├── AuditEntityInterfaceBuilder.cs
│ │ ├── DataContractClassBuilder.cs
│ │ ├── DbContextClassBuilder.cs
│ │ ├── DbContextQueryExtensionsClassBuilder.cs
│ │ ├── EntityClassBuilder.cs
│ │ ├── EntityConfigurationClassBuilder.cs
│ │ ├── EntityInterfaceBuilder.cs
│ │ ├── PagingExtensionsClassBuilder.cs
│ │ ├── QueryModelClassBuilder.cs
│ │ ├── RepositoryBaseClassBuilder.cs
│ │ ├── RepositoryClassBuilder.cs
│ │ └── RepositoryInterfaceBuilder.cs
│ ├── PagingExtensionsClassDefinition.cs
│ ├── QueryModelClassDefinition.cs
│ ├── RepositoryClassDefinition.cs
│ └── RepositoryInterfaceDefinition.cs
├── DomainExtensions.cs
├── EntityFrameworkCoreProject.cs
├── EntityFrameworkCoreProjectDomainExtensions.cs
├── EntityFrameworkCoreProjectLayersExtensions.cs
├── EntityFrameworkCoreProjectNamespaces.cs
├── EntityFrameworkCoreProjectRepositoriesExtensions.cs
├── EntityFrameworkCoreProjectSelectionExtensions.cs
├── EntityFrameworkCoreProjectSettings.cs
├── EntityFrameworkCoreVersion.cs
├── EntityLayerExtensions.cs
├── IDotNetClassDefinitionExtensions.cs
└── ProjectFeatureExtensions.cs
├── LICENSE
├── README.md
└── build.bat
/.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 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.Tests/CatFactory.EntityFrameworkCore.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | latest
6 | 1701;1702;NU1701
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.Tests/MockTests.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.EntityFrameworkCore.Tests.Models;
2 | using Xunit;
3 |
4 | namespace CatFactory.EntityFrameworkCore.Tests
5 | {
6 | public class MockTests
7 | {
8 | [Fact]
9 | public void ProjectScaffoldingForMockDb()
10 | {
11 | // Create instance of EF Core Project
12 | var project = EntityFrameworkCoreProject
13 | .CreateForV2x("College.Mock", Databases.College, @"C:\Temp\CatFactory.EntityFrameworkCore\College.Mock");
14 |
15 | // Apply settings for EF Core project
16 | project.GlobalSelection(settings => settings.ForceOverwrite = true);
17 |
18 | // Build features for project, group all entities by schema into a feature
19 | project.BuildFeatures();
20 |
21 | // Scaffolding =^^=
22 | project
23 | .ScaffoldEntityLayer()
24 | .ScaffoldDataLayer()
25 | ;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.Tests/Models/CollegeDatabase.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using CatFactory.ObjectRelationalMapping;
3 | using CatFactory.SqlServer;
4 |
5 | namespace CatFactory.EntityFrameworkCore.Tests.Models
6 | {
7 | public static partial class Databases
8 | {
9 | public static Database College
10 | => new Database
11 | {
12 | Name = "college",
13 | DefaultSchema = "dbo",
14 | DatabaseTypeMaps = new SqlServerDatabaseFactory().DatabaseTypeMaps.ToList(),
15 | Tables =
16 | {
17 | new Table
18 | {
19 | Schema = "dbo",
20 | Name = "student",
21 | Columns =
22 | {
23 | new Column { Name = "student_id", Type = "int" },
24 | new Column { Name = "first_name", Type = "varchar", Length = 25 },
25 | new Column { Name = "middle_name", Type = "varchar", Length = 25, Nullable = true },
26 | new Column { Name = "last_name", Type = "varchar", Length = 25 },
27 | new Column { Name = "birth_date", Type = "datetime" },
28 | new Column { Name = "gender", Type = "varchar", Length = 1 }
29 | },
30 | Identity = new Identity("student_id", 1, 1)
31 | },
32 | new Table
33 | {
34 | Schema = "dbo",
35 | Name = "teacher",
36 | Columns =
37 | {
38 | new Column { Name = "teacher_id", Type = "int" },
39 | new Column { Name = "first_name", Type = "varchar", Length = 25 },
40 | new Column { Name = "middle_name", Type = "varchar", Length = 25, Nullable = true },
41 | new Column { Name = "last_name", Type = "varchar", Length = 25 },
42 | new Column { Name = "birth_date", Type = "datetime" },
43 | new Column { Name = "gender", Type = "varchar", Length = 1 }
44 | },
45 | Identity = new Identity("teacher_id", 1, 1)
46 | },
47 | new Table
48 | {
49 | Schema = "dbo",
50 | Name = "course",
51 | Columns =
52 | {
53 | new Column { Name = "course_id", Type = "int" },
54 | new Column { Name = "course_name", Type = "varchar", Length = 25 },
55 | new Column { Name = "course_description", Type = "varchar", Nullable = true }
56 | },
57 | Identity = new Identity("course_id", 1, 1)
58 | },
59 | new Table
60 | {
61 | Schema = "dbo",
62 | Name = "course_student",
63 | Columns =
64 | {
65 | new Column { Name = "course_student_id", Type = "int" },
66 | new Column { Name = "course_id", Type = "int" },
67 | new Column { Name = "student_id", Type = "int" },
68 | },
69 | Identity = new Identity("course_student_id", 1, 1)
70 | }
71 | }
72 | }
73 | .AddDbObjectsFromTables()
74 | .AddDbObjectsFromViews()
75 | .SetPrimaryKeyForTables()
76 | .LinkTables()
77 | ;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.Tests/NamingConventionTests.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.ObjectRelationalMapping;
2 | using Xunit;
3 |
4 | namespace CatFactory.EntityFrameworkCore.Tests
5 | {
6 | public class NamingConventionTests
7 | {
8 | [Fact]
9 | public void CheckEntityConfigurationName()
10 | {
11 | // Arrange
12 | var efCoreProject = new EntityFrameworkCoreProject();
13 |
14 | // Act and Assert
15 | Assert.True("OrderConfiguration" == efCoreProject.GetEntityConfigurationName(new Table { Name = "Order" }));
16 | Assert.True("OrdersQryConfiguration" == efCoreProject.GetEntityConfigurationName(new View { Name = "Orders Qry" }));
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.Tests/ProjectCreationTests.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Tests
4 | {
5 | public class ProjectCreationTests
6 | {
7 | [Fact]
8 | public void DefineProjectForV2x()
9 | {
10 | var project = EntityFrameworkCoreProject.CreateForV2x("OnlineStore", new ObjectRelationalMapping.Database(), "");
11 |
12 | Assert.True(project.Version <= EntityFrameworkCoreVersion.Version_2_2);
13 | }
14 |
15 | [Fact]
16 | public void DefineProjectForV3x()
17 | {
18 | var project = EntityFrameworkCoreProject.CreateForV3x("OnlineStore", new ObjectRelationalMapping.Database(), "");
19 |
20 | Assert.True(project.Version >= EntityFrameworkCoreVersion.Version_3_0);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.Tests/ProjectSelectionTests.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using CatFactory.SqlServer;
3 | using Xunit;
4 |
5 | namespace CatFactory.EntityFrameworkCore.Tests
6 | {
7 | public class ProjectSelectionTests
8 | {
9 | [Fact]
10 | public async Task ProjectSelectionScopeAsync()
11 | {
12 | // Arrange
13 |
14 | // Import database
15 | var database = await SqlServerDatabaseFactory
16 | .ImportAsync("server=(local); database=OnlineStore; integrated security=yes; TrustServerCertificate=True;", "dbo.sysdiagrams");
17 |
18 | // Create instance of Entity Framework Core project
19 | var project = EntityFrameworkCoreProject
20 | .CreateForV2x("OnlineStore", database, @"C:\Temp\CatFactory.EntityFrameworkCore\OnlineStore");
21 |
22 | // Act
23 |
24 | // Apply settings for Entity Framework Core project
25 | project.GlobalSelection(settings =>
26 | {
27 | settings.ForceOverwrite = true;
28 | settings.ConcurrencyToken = "Timestamp";
29 | settings.AuditEntity = new AuditEntity
30 | {
31 | CreationUserColumnName = "CreationUser",
32 | CreationDateTimeColumnName = "CreationDateTime",
33 | LastUpdateUserColumnName = "LastUpdateUser",
34 | LastUpdateDateTimeColumnName = "LastUpdateDateTime"
35 | };
36 | });
37 |
38 | project.Selection("Sales.OrderHeader", settings => settings.EntitiesWithDataContracts = true);
39 |
40 | var orderHeader = database.FindTable("Sales.OrderHeader");
41 |
42 | var selectionForOrder = project.GetSelection(orderHeader);
43 |
44 | // Assert
45 |
46 | Assert.True(project.Selections.Count == 2);
47 |
48 | Assert.True(project.GlobalSelection().Settings.EntitiesWithDataContracts == false);
49 | Assert.True(selectionForOrder.Settings.EntitiesWithDataContracts == true);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.Tests/ScaffoldingEventHandlersTests.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using CatFactory.EntityFrameworkCore.Definitions;
3 | using CatFactory.SqlServer;
4 | using Xunit;
5 |
6 | namespace CatFactory.EntityFrameworkCore.Tests
7 | {
8 | public class ScaffoldingEventHandlersTests
9 | {
10 | [Fact]
11 | public async Task ScaffoldingWithEventHandlersForOnlineStoreDbAsync()
12 | {
13 | // Create database factory
14 | var databaseFactory = new SqlServerDatabaseFactory
15 | {
16 | DatabaseImportSettings = new DatabaseImportSettings
17 | {
18 | ConnectionString = "server=(local); database=OnlineStore; integrated security=yes; TrustServerCertificate=True;"
19 | }
20 | };
21 |
22 | // Import database
23 | var database = await databaseFactory.ImportAsync();
24 |
25 | // Create instance of Entity Framework Core project
26 | var project = EntityFrameworkCoreProject
27 | .CreateForV2x("ScaffoldingEventHandlers.OnlineStore.Core", database, @"C:\Temp\CatFactory.EntityFrameworkCore\ScaffoldingEventHandlers.OnlineStore.Core");
28 |
29 | // Apply settings for Entity Framework Core project
30 | project.GlobalSelection(settings => settings.ForceOverwrite = true);
31 |
32 | project.ScaffoldingDefinition += (sender, args) =>
33 | {
34 | if (args.CodeBuilder.ObjectDefinition is EntityClassDefinition entityDef)
35 | {
36 | foreach (var prop in entityDef.Properties)
37 | {
38 | if (prop.Type == "string")
39 | prop.Type = "string?";
40 | }
41 | }
42 | else if (args.CodeBuilder.ObjectDefinition is DbContextClassDefinition dbContextDef)
43 | {
44 | dbContextDef.Documentation.Summary = "foo bar zaz";
45 |
46 | foreach (var prop in dbContextDef.Properties)
47 | {
48 | // todo: Add
49 | prop.InitializationValue = "null";
50 | }
51 | }
52 | };
53 |
54 | project.ScaffoldedDefinition += (sender, args) =>
55 | {
56 | // Check if file exists
57 | };
58 |
59 | // Build features for project, group all entities by schema into a feature
60 | project.BuildFeatures();
61 |
62 | // Scaffolding =^^=
63 | project
64 | .ScaffoldDomain()
65 | ;
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.Tests/ScaffoldingTests.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using CatFactory.SqlServer;
3 | using Xunit;
4 |
5 | namespace CatFactory.EntityFrameworkCore.Tests
6 | {
7 | public class ScaffoldingTests
8 | {
9 | [Fact]
10 | public async Task ScaffoldingDomainProjectForOnlineStoreDbAsync()
11 | {
12 | // Create database factory
13 | var databaseFactory = new SqlServerDatabaseFactory
14 | {
15 | DatabaseImportSettings = new DatabaseImportSettings
16 | {
17 | ConnectionString = "server=(local); database=OnlineStore; integrated security=yes; TrustServerCertificate=True;",
18 | Exclusions =
19 | {
20 | "dbo.sysdiagrams"
21 | }
22 | }
23 | };
24 |
25 | // Import database
26 | var database = await databaseFactory.ImportAsync();
27 |
28 | // Create instance of Entity Framework Core project
29 | var project = EntityFrameworkCoreProject
30 | .CreateForV2x("OnlineStore.Domain", database, @"C:\Temp\CatFactory.EntityFrameworkCore\OnlineStore.Domain");
31 |
32 | // Apply settings for Entity Framework Core project
33 | project.GlobalSelection(settings =>
34 | {
35 | settings.ForceOverwrite = true;
36 | settings.ConcurrencyToken = "Timestamp";
37 | settings.AuditEntity = new AuditEntity
38 | {
39 | CreationUserColumnName = "CreationUser",
40 | CreationDateTimeColumnName = "CreationDateTime",
41 | LastUpdateUserColumnName = "LastUpdateUser",
42 | LastUpdateDateTimeColumnName = "LastUpdateDateTime"
43 | };
44 |
45 | settings.AddConfigurationForUniquesInFluentAPI = true;
46 | settings.AddConfigurationForForeignKeysInFluentAPI = true;
47 | settings.DeclareNavigationProperties = true;
48 | });
49 |
50 | project.Selection("Sales.OrderHeader", settings =>
51 | {
52 | settings.EntitiesWithDataContracts = true;
53 | settings.AddConfigurationForForeignKeysInFluentAPI = true;
54 | settings.DeclareNavigationProperties = true;
55 | });
56 |
57 | // Build features for project, group all entities by schema into a feature
58 | project.BuildFeatures();
59 |
60 | // Scaffolding =^^=
61 | project
62 | .ScaffoldDomain()
63 | ;
64 | }
65 |
66 | [Fact]
67 | public async Task ScaffoldingProjectWithRepositoriesForOnlineStoreDbAsync()
68 | {
69 | // Create database factory
70 | var databaseFactory = new SqlServerDatabaseFactory
71 | {
72 | DatabaseImportSettings = new DatabaseImportSettings
73 | {
74 | ConnectionString = "server=(local); database=OnlineStore; integrated security=yes; TrustServerCertificate=True;",
75 | ImportTableFunctions = true,
76 | Exclusions =
77 | {
78 | "dbo.sysdiagrams",
79 | "dbo.fn_diagramobjects"
80 | }
81 | }
82 | };
83 |
84 | // Import database
85 | var database = await databaseFactory.ImportAsync();
86 |
87 | // Create instance of Entity Framework Core project
88 | var project = EntityFrameworkCoreProject
89 | .CreateForV2x("OnlineStore.Core", database, @"C:\Temp\CatFactory.EntityFrameworkCore\OnlineStore.Core");
90 |
91 | // Apply settings for Entity Framework Core project
92 | project.GlobalSelection(settings =>
93 | {
94 | settings.ForceOverwrite = true;
95 | settings.ConcurrencyToken = "Timestamp";
96 | settings.AuditEntity = new AuditEntity
97 | {
98 | CreationUserColumnName = "CreationUser",
99 | CreationDateTimeColumnName = "CreationDateTime",
100 | LastUpdateUserColumnName = "LastUpdateUser",
101 | LastUpdateDateTimeColumnName = "LastUpdateDateTime"
102 | };
103 |
104 | settings.AddConfigurationForUniquesInFluentAPI = true;
105 | settings.AddConfigurationForForeignKeysInFluentAPI = true;
106 | settings.DeclareNavigationProperties = true;
107 | });
108 |
109 | project.Selection("Sales.OrderHeader", settings =>
110 | {
111 | settings.EntitiesWithDataContracts = true;
112 | settings.AddConfigurationForForeignKeysInFluentAPI = true;
113 | settings.DeclareNavigationProperties = true;
114 | });
115 |
116 | // Build features for project, group all entities by schema into a feature
117 | project.BuildFeatures();
118 |
119 | // Scaffolding =^^=
120 | project
121 | .ScaffoldEntityLayer()
122 | .ScaffoldDataLayer()
123 | ;
124 | }
125 |
126 | [Fact]
127 | public async Task ScaffoldingProjectWithDataAnnotationsForOnlineStoreDbAsync()
128 | {
129 | // Import database
130 | var database = await SqlServerDatabaseFactory
131 | .ImportAsync("server=(local); database=OnlineStore; integrated security=yes; TrustServerCertificate=True;", "dbo.sysdiagrams");
132 |
133 | // Create instance of Entity Framework Core Project
134 | var project = EntityFrameworkCoreProject
135 | .CreateForV2x("OnlineStoreWithDataAnnotations.Core", database, @"C:\Temp\CatFactory.EntityFrameworkCore\OnlineStoreWithDataAnnotations.Core");
136 |
137 | // Apply settings for Entity Framework Core project
138 | project.GlobalSelection(settings =>
139 | {
140 | settings.ForceOverwrite = true;
141 | settings.UseDataAnnotations = true;
142 | settings.ConcurrencyToken = "Timestamp";
143 | settings.AuditEntity = new AuditEntity
144 | {
145 | CreationUserColumnName = "CreationUser",
146 | CreationDateTimeColumnName = "CreationDateTime",
147 | LastUpdateUserColumnName = "LastUpdateUser",
148 | LastUpdateDateTimeColumnName = "LastUpdateDateTime"
149 | };
150 | settings.DeclareNavigationProperties = true;
151 | });
152 |
153 | project.Selection("Sales.OrderHeader", settings => settings.EntitiesWithDataContracts = true);
154 |
155 | // Build features for project, group all entities by schema into a feature
156 | project.BuildFeatures();
157 |
158 | // Scaffolding =^^=
159 | project
160 | .ScaffoldEntityLayer()
161 | .ScaffoldDataLayer()
162 | ;
163 | }
164 |
165 | [Fact]
166 | public async Task ScaffoldingProjectForNorthwindDbAsync()
167 | {
168 | // Import database
169 | var factory = new SqlServerDatabaseFactory
170 | {
171 | DatabaseImportSettings = new DatabaseImportSettings
172 | {
173 | ConnectionString = "server=(local); database=Northwind; integrated security=yes; TrustServerCertificate=True;",
174 | ImportScalarFunctions = true,
175 | ImportTableFunctions = true,
176 | ImportStoredProcedures = true,
177 | Exclusions =
178 | {
179 | "dbo.sysdiagrams",
180 | "dbo.sp_alterdiagram",
181 | "dbo.sp_creatediagram",
182 | "dbo.sp_dropdiagram",
183 | "dbo.sp_helpdiagramdefinition",
184 | "dbo.sp_helpdiagrams",
185 | "dbo.sp_renamediagram",
186 | "dbo.sp_upgraddiagrams",
187 | "dbo.fn_diagramobjects"
188 | }
189 | }
190 | };
191 |
192 | var database = await factory.ImportAsync();
193 |
194 | // Create instance of Entity Framework Core Project
195 | var project = EntityFrameworkCoreProject
196 | .CreateForV2x("Northwind.Core", database, @"C:\Temp\CatFactory.EntityFrameworkCore\Northwind.Core");
197 |
198 | // Apply settings for Entity Framework Core project
199 | project.GlobalSelection(settings =>
200 | {
201 | settings.ForceOverwrite = true;
202 | settings.DeclareNavigationProperties = true;
203 | });
204 |
205 | project.Selection("dbo.Orders", settings => settings.EntitiesWithDataContracts = true);
206 |
207 | // Build features for project, group all entities by schema into a feature
208 | project.BuildFeatures();
209 |
210 | // Scaffolding =^^=
211 | project
212 | .ScaffoldEntityLayer()
213 | .ScaffoldDataLayer()
214 | ;
215 | }
216 |
217 | [Fact]
218 | public async Task ScaffoldingProjectForAdventureWorksDbAsync()
219 | {
220 | // Create instance of factory for SQL Server
221 | var databaseFactory = new SqlServerDatabaseFactory
222 | {
223 | DatabaseImportSettings = new DatabaseImportSettings
224 | {
225 | ConnectionString = "server=(local); database=AdventureWorks2017; integrated security=yes; TrustServerCertificate=True;",
226 | ImportScalarFunctions = true,
227 | ImportTableFunctions = true,
228 | Exclusions =
229 | {
230 | "dbo.sysdiagrams",
231 | "Production.Document",
232 | "Production.ProductDocument"
233 | },
234 | ExclusionTypes =
235 | {
236 | "hierarchyid",
237 | "geography"
238 | }
239 | }
240 | };
241 |
242 | // Import database
243 | var database = await databaseFactory.ImportAsync();
244 |
245 | // Create instance of Entity Framework Core Project
246 | var project = EntityFrameworkCoreProject
247 | .CreateForV2x("AdventureWorks", database, @"C:\Temp\CatFactory.EntityFrameworkCore\AdventureWorks.Core");
248 |
249 | // Apply settings for Entity Framework Core project
250 | project.GlobalSelection(settings =>
251 | {
252 | settings.ForceOverwrite = true;
253 | settings.DeclareNavigationProperties = true;
254 |
255 | settings.AddConfigurationForForeignKeysInFluentAPI = true;
256 | });
257 |
258 | // Build features for project, group all entities by schema into a feature
259 | project.BuildFeatures();
260 |
261 | // Scaffolding =^^=
262 | project
263 | .ScaffoldEntityLayer()
264 | .ScaffoldDataLayer()
265 | ;
266 | }
267 |
268 | [Fact]
269 | public async Task ScaffoldingProjectForWideWorldImportersDbAsync()
270 | {
271 | // Create database factory
272 | var databaseFactory = new SqlServerDatabaseFactory
273 | {
274 | DatabaseImportSettings = new DatabaseImportSettings
275 | {
276 | ConnectionString = "server=(local); database=WideWorldImporters; integrated security=yes; TrustServerCertificate=True;",
277 | ImportTableFunctions = true,
278 | Exclusions =
279 | {
280 | "dbo.sysdiagrams",
281 | "dbo.fn_diagramobjects"
282 | }
283 | }
284 | };
285 |
286 | // Import database
287 | var database = await databaseFactory.ImportAsync();
288 |
289 | // Create instance of Entity Framework Core project
290 | var project = EntityFrameworkCoreProject
291 | .CreateForV2x("WideWorldImporters.Core", database, @"C:\Temp\CatFactory.EntityFrameworkCore\WideWorldImporters.Core");
292 |
293 | // Apply settings for Entity Framework Core project
294 | project.GlobalSelection(settings => settings.ForceOverwrite = true);
295 |
296 | // Build features for project, group all entities by schema into a feature
297 | project.BuildFeatures();
298 |
299 | // Scaffolding =^^=
300 | project
301 | .ScaffoldEntityLayer()
302 | .ScaffoldDataLayer()
303 | ;
304 | }
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.Tests/ValueConversion.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.CodeFactory;
2 | using CatFactory.NetCore.ObjectOrientedProgramming;
3 | using CatFactory.ObjectOrientedProgramming;
4 |
5 | namespace CatFactory.EntityFrameworkCore
6 | {
7 | public static class ValueConversion
8 | {
9 | public static EntityFrameworkCoreProject ScaffoldValueConversion(this EntityFrameworkCoreProject project)
10 | {
11 | var boolToStringConverters = new CSharpClassDefinition
12 | {
13 | Namespaces =
14 | {
15 | "Microsoft.EntityFrameworkCore.Storage.ValueConversion"
16 | },
17 | Namespace = "ValueConversion",
18 | AccessModifier = AccessModifier.Public,
19 | IsStatic = true,
20 | Name = "BoolToStringConverters",
21 | Fields =
22 | {
23 | new FieldDefinition
24 | {
25 | AccessModifier = AccessModifier.Private,
26 | IsStatic = true,
27 | IsReadOnly = true,
28 | Type = "BoolToStringConverter",
29 | Name = "bYN",
30 | Value = "new BoolToStringConverter(\"N\", \"Y\")"
31 | }
32 | }
33 | };
34 |
35 | CSharpCodeBuilder.CreateFiles(project.OutputDirectory, project.GetDataLayerDirectory("ValueConversion"), true, boolToStringConverters);
36 |
37 | return project;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.2037
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CatFactory.EntityFrameworkCore", "CatFactory.EntityFrameworkCore\CatFactory.EntityFrameworkCore.csproj", "{5D163B1F-7324-4270-B0B4-348AEEB9FED2}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CatFactory.EntityFrameworkCore.Tests", "CatFactory.EntityFrameworkCore.Tests\CatFactory.EntityFrameworkCore.Tests.csproj", "{3ABABDE9-C9E6-494F-85BA-92557A284CEC}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {5D163B1F-7324-4270-B0B4-348AEEB9FED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {5D163B1F-7324-4270-B0B4-348AEEB9FED2}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {5D163B1F-7324-4270-B0B4-348AEEB9FED2}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {5D163B1F-7324-4270-B0B4-348AEEB9FED2}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {3ABABDE9-C9E6-494F-85BA-92557A284CEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {3ABABDE9-C9E6-494F-85BA-92557A284CEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {3ABABDE9-C9E6-494F-85BA-92557A284CEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {3ABABDE9-C9E6-494F-85BA-92557A284CEC}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {FD0FA40A-6265-442C-9583-981D6A274503}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/AuditEntity.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace CatFactory.EntityFrameworkCore
4 | {
5 | public class AuditEntity
6 | {
7 | public AuditEntity()
8 | {
9 | }
10 |
11 | public string CreationUserColumnName { get; set; }
12 |
13 | public string CreationDateTimeColumnName { get; set; }
14 |
15 | public string LastUpdateUserColumnName { get; set; }
16 |
17 | public string LastUpdateDateTimeColumnName { get; set; }
18 |
19 | public IEnumerable Names
20 | => new string[]
21 | {
22 | CreationUserColumnName,
23 | CreationDateTimeColumnName,
24 | LastUpdateUserColumnName,
25 | LastUpdateDateTimeColumnName
26 | };
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/AuthorInfo.cs:
--------------------------------------------------------------------------------
1 | namespace CatFactory.EntityFrameworkCore
2 | {
3 | public class AuthorInfo
4 | {
5 | public string CompanyName { get; set; }
6 |
7 | public string Name { get; set; }
8 |
9 | public string Email { get; set; }
10 |
11 | public string WebSite { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/CatFactory.EntityFrameworkCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | latest
6 | 1.0.0-beta-aurora-build00
7 | H. Herzl
8 | Herzl Corp.
9 | CatFactory Package for Entity Framework Core
10 | git
11 | https://github.com/hherzl/CatFactory.EntityFrameworkCore
12 | Entity Framework Core; ORM; Scaffolding
13 |
14 | 1.0.0-beta-aurora-build00 Version:
15 |
16 | Fix issue 27 https://github.com/hherzl/CatFactory.EntityFrameworkCore/issues/27
17 |
18 | Quick start:
19 |
20 | https://www.codeproject.com/Articles/1160615/Scaffolding-Entity-Framework-Core-with-CatFactory
21 |
22 | https://github.com/hherzl/CatFactory.EntityFrameworkCore
23 | Apache-2.0
24 | true
25 | true
26 | snupkg
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/ConstraintExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using CatFactory.ObjectOrientedProgramming;
4 | using CatFactory.ObjectRelationalMapping;
5 |
6 | namespace CatFactory.EntityFrameworkCore
7 | {
8 | public static class ConstraintExtensions
9 | {
10 | public static PropertyDefinition GetParentNavigationProperty(this ForeignKey foreignKey, ITable table, EntityFrameworkCoreProject project)
11 | {
12 | var propertyType = "";
13 |
14 | if (table.HasSameEnclosingName())
15 | {
16 | propertyType = string.Join(".", (new string[]
17 | {
18 | project.ProjectNamespaces.EntityLayer,
19 | project.Database.HasDefaultSchema(table) ? string.Empty : table.Schema, project.GetEntityName(table)
20 | }).Where(item => !string.IsNullOrEmpty(item)));
21 | }
22 | else
23 | {
24 | propertyType = project.GetEntityName(table);
25 | }
26 |
27 | var selection = project.GetSelection(table);
28 |
29 | return new PropertyDefinition(propertyType, $"{project.GetEntityName(table)}Fk")
30 | {
31 | AccessModifier = AccessModifier.Public,
32 | IsVirtual = selection.Settings.DeclareNavigationPropertiesAsVirtual,
33 | Attributes = selection.Settings.UseDataAnnotations ? new List
34 | {
35 | new MetadataAttribute("ForeignKey", $"\"{string.Join(",", foreignKey.Key)}\"")
36 | } : null
37 | };
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/DataLayerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using CatFactory.EntityFrameworkCore.Definitions.Extensions;
3 | using CatFactory.Markdown;
4 | using CatFactory.NetCore.ObjectOrientedProgramming;
5 | using CatFactory.ObjectRelationalMapping;
6 |
7 | namespace CatFactory.EntityFrameworkCore
8 | {
9 | public static class DataLayerExtensions
10 | {
11 | public static EntityFrameworkCoreProject ScaffoldDataLayer(this EntityFrameworkCoreProject project)
12 | {
13 | ScaffoldConfigurations(project);
14 | ScaffoldDbContext(project);
15 | ScaffoldDataContracts(project);
16 | ScaffoldDataRepositories(project);
17 | ScaffoldMdReadMe(project);
18 |
19 | return project;
20 | }
21 |
22 | internal static void ScaffoldConfigurations(EntityFrameworkCoreProject project)
23 | {
24 | var projectSelection = project.GlobalSelection();
25 |
26 | if (!projectSelection.Settings.UseDataAnnotations)
27 | {
28 | foreach (var table in project.Database.Tables)
29 | {
30 | var definition = project.GetEntityConfigurationClassDefinition(table, false);
31 |
32 | project.Scaffold(definition, project.GetDataLayerConfigurationsDirectory(), project.Database.HasDefaultSchema(table) ? "" : table.Schema);
33 | }
34 |
35 | foreach (var view in project.Database.Views)
36 | {
37 | var definition = project.GetEntityConfigurationClassDefinition(view, false);
38 |
39 | project.Scaffold(definition, project.GetDataLayerConfigurationsDirectory(), project.Database.HasDefaultSchema(view) ? "" : view.Schema);
40 | }
41 | }
42 | }
43 |
44 | internal static void ScaffoldDbContext(EntityFrameworkCoreProject project)
45 | {
46 | var projectSelection = project.GlobalSelection();
47 |
48 | project.Scaffold(project.GetDbContextClassDefinition(projectSelection, false), project.GetDataLayerDirectory());
49 | }
50 |
51 | internal static void ScaffoldRepositoryInterface(EntityFrameworkCoreProject project)
52 | {
53 | project.Scaffold(project.GetRepositoryInterfaceDefinition(), project.GetDataLayerContractsDirectory());
54 | }
55 |
56 | internal static void ScaffoldBaseRepositoryClassDefinition(EntityFrameworkCoreProject project)
57 | {
58 | project.Scaffold(project.GetRepositoryBaseClassDefinition(), project.GetDataLayerRepositoriesDirectory());
59 | }
60 |
61 | internal static void ScaffoldRepositoryExtensionsClassDefinition(EntityFrameworkCoreProject project)
62 | {
63 | project.Scaffold(project.GetPagingExtensionsClassDefinition(false), project.GetDataLayerRepositoriesDirectory());
64 | }
65 |
66 | internal static void ScaffoldDataContracts(EntityFrameworkCoreProject project)
67 | {
68 | foreach (var table in project.Database.Tables)
69 | {
70 | var selection = project.GetSelection(table);
71 |
72 | if (!selection.Settings.EntitiesWithDataContracts)
73 | continue;
74 |
75 | project.Scaffold(project.GetDataContractClassDefinition(table, false), project.GetDataLayerDataContractsDirectory());
76 | }
77 | }
78 |
79 | internal static void ScaffoldDataRepositories(EntityFrameworkCoreProject project)
80 | {
81 | var projectSelection = project.GlobalSelection();
82 |
83 | if (!string.IsNullOrEmpty(projectSelection.Settings.ConcurrencyToken))
84 | {
85 | projectSelection.Settings.InsertExclusions.Add(projectSelection.Settings.ConcurrencyToken);
86 | projectSelection.Settings.UpdateExclusions.Add(projectSelection.Settings.ConcurrencyToken);
87 | }
88 |
89 | ScaffoldRepositoryInterface(project);
90 | ScaffoldBaseRepositoryClassDefinition(project);
91 | ScaffoldRepositoryExtensionsClassDefinition(project);
92 |
93 | foreach (var projectFeature in project.Features)
94 | {
95 | var repositoryClassDefinition = projectFeature.GetRepositoryClassDefinition();
96 |
97 | project.Scaffold(repositoryClassDefinition, project.GetDataLayerRepositoriesDirectory());
98 |
99 | var repositoryInterfaceDefinition = repositoryClassDefinition.RefactInterface();
100 |
101 | repositoryInterfaceDefinition.Namespace = project.GetDataLayerContractsNamespace();
102 | repositoryInterfaceDefinition.Implements.Add("IRepository");
103 |
104 | project.Scaffold(repositoryInterfaceDefinition, project.GetDataLayerContractsDirectory());
105 | }
106 | }
107 |
108 | internal static void ScaffoldMdReadMe(this EntityFrameworkCoreProject project)
109 | {
110 | var readMe = new MdDocument();
111 |
112 | readMe.H1("CatFactory ==^^==: Scaffolding Made Easy");
113 |
114 | readMe.WriteLine("How to use this code on your ASP.NET Core Application:");
115 |
116 | readMe.OrderedList(
117 | "Install EntityFrameworkCore.SqlServer package",
118 | "Register the DbContext and Repositories in ConfigureServices method (Startup class)"
119 | );
120 |
121 | readMe.H2("Install package");
122 |
123 | readMe.WriteLine("You can install the NuGet packages in Visual Studio or Windows Command Line, for more info:");
124 |
125 | readMe.WriteLine(
126 | Md.Link("Install and manage packages with the Package Manager Console in Visual Studio (PowerShell)", "https://docs.microsoft.com/en-us/nuget/consume-packages/install-use-packages-powershell")
127 | );
128 |
129 | readMe.WriteLine(
130 | Md.Link(".NET Core CLI", "https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package")
131 | );
132 |
133 | readMe.H2("Register DbContext and Repositories");
134 |
135 | readMe.WriteLine("Add the following code lines in {0} method (Startup class):", Md.Bold("ConfigureServices"));
136 | readMe.WriteLine(" services.AddDbContext<{0}>(options => options.UseSqlServer(\"ConnectionString\"));", project.GetDbContextName(project.Database));
137 | readMe.WriteLine(" services.AddScope<{0}, {1}>()", "IDboRepository", "DboRepository");
138 |
139 | readMe.WriteLine("Happy scaffolding!");
140 |
141 | var codeProjectLink = Md.Link("Scaffolding Entity Framework Core with CatFactory", "https://www.codeproject.com/Articles/1160615/Scaffolding-Entity-Framework-Core-with-CatFactory");
142 |
143 | readMe.WriteLine("You can check the guide for this package in: {0}", codeProjectLink);
144 |
145 | var gitHubRepositoryLink = Md.Link("GitHub repository", "https://github.com/hherzl/CatFactory.EntityFrameworkCore");
146 |
147 | readMe.WriteLine("Also you can check the source code on {0}", gitHubRepositoryLink);
148 |
149 | readMe.WriteLine("CatFactory Development Team ==^^==");
150 |
151 | File.WriteAllText(Path.Combine(project.OutputDirectory, "CatFactory.EntityFrameworkCore.ReadMe.MD"), readMe.ToString());
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/DatabaseExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CatFactory.ObjectRelationalMapping;
3 | using CatFactory.ObjectRelationalMapping.Programmability;
4 |
5 | namespace CatFactory.EntityFrameworkCore
6 | {
7 | public static class DatabaseExtensions
8 | {
9 | public static List GetScalarFunctions(this Database database)
10 | {
11 | var importBag = database.ImportBag as IDictionary;
12 |
13 | if (importBag.ContainsKey("ScalarFunctions"))
14 | {
15 | if (importBag["ScalarFunctions"] is List scalarFunctions)
16 | return scalarFunctions;
17 | }
18 |
19 | return new List();
20 | }
21 |
22 | public static List GetTableFunctions(this Database database)
23 | {
24 | var importBag = database.ImportBag as IDictionary;
25 |
26 | if (importBag.ContainsKey("TableFunctions"))
27 | {
28 | if (importBag["TableFunctions"] is List tableFunctions)
29 | return tableFunctions;
30 | }
31 |
32 | return new List();
33 | }
34 |
35 | public static List GetStoredProcedures(this Database database)
36 | {
37 | var importBag = database.ImportBag as IDictionary;
38 |
39 | if (importBag.ContainsKey("StoredProcedures"))
40 | {
41 | if (importBag["StoredProcedures"] is List storedProcedures)
42 | return storedProcedures;
43 | }
44 |
45 | return new List();
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/DbObjectExtensions.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.ObjectRelationalMapping;
2 |
3 | namespace CatFactory.EntityFrameworkCore
4 | {
5 | public static class DbObjectExtensions
6 | {
7 | public static string GetFullName(this Database db, IDbObject dbObject)
8 | => db.NamingConvention.GetObjectName(dbObject.Schema, dbObject.Name);
9 |
10 | public static string GetFullColumnName(this ITable table, Column column)
11 | => string.Join(".", new string[] { table.Schema, table.Name, column.Name });
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/AuditEntityInterfaceDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class AuditEntityInterfaceDefinition : CSharpInterfaceDefinition
6 | {
7 | public AuditEntityInterfaceDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/DataContractClassDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class DataContractClassDefinition : CSharpClassDefinition
6 | {
7 | public DataContractClassDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/DbContextClassDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class DbContextClassDefinition : CSharpClassDefinition
6 | {
7 | public DbContextClassDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/DbContextQueryExtensionsClassDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class DbContextQueryExtensionsClassDefinition : CSharpClassDefinition
6 | {
7 | public DbContextQueryExtensionsClassDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/EntityClassDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class EntityClassDefinition : CSharpClassDefinition
6 | {
7 | public EntityClassDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/EntityConfigurationClassDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class EntityConfigurationClassDefinition : CSharpClassDefinition
6 | {
7 | public EntityConfigurationClassDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/EntityInterfaceDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class EntityInterfaceDefinition : CSharpInterfaceDefinition
6 | {
7 | public EntityInterfaceDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/AuditEntityInterfaceBuilder.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
4 | {
5 | public static class AuditEntityInterfaceBuilder
6 | {
7 | public static AuditEntityInterfaceDefinition GetAuditEntityInterfaceDefinition(this EntityFrameworkCoreProject project, bool isDomainDrivenDesign)
8 | => new AuditEntityInterfaceDefinition
9 | {
10 | Namespaces =
11 | {
12 | "System"
13 | },
14 | Namespace = isDomainDrivenDesign ? project.GetDomainModelsNamespace() : project.GetEntityLayerNamespace(),
15 | AccessModifier = AccessModifier.Public,
16 | Name = "IAuditEntity",
17 | Implements =
18 | {
19 | "IEntity"
20 | },
21 | Properties =
22 | {
23 | new PropertyDefinition("string", "CreationUser"),
24 | new PropertyDefinition("DateTime?", "CreationDateTime"),
25 | new PropertyDefinition("string", "LastUpdateUser"),
26 | new PropertyDefinition("DateTime?", "LastUpdateDateTime")
27 | }
28 | };
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/DataContractClassBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using CatFactory.NetCore;
3 | using CatFactory.NetCore.ObjectOrientedProgramming;
4 | using CatFactory.ObjectOrientedProgramming;
5 | using CatFactory.ObjectRelationalMapping;
6 |
7 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
8 | {
9 | public static class DataContractClassBuilder
10 | {
11 | public static DataContractClassDefinition GetDataContractClassDefinition(this EntityFrameworkCoreProject project, ITable table, bool isDomainDrivenDesign)
12 | {
13 | var definition = new DataContractClassDefinition
14 | {
15 | Namespaces =
16 | {
17 | "System"
18 | },
19 | Namespace = isDomainDrivenDesign ? project.GetDomainQueryModelsNamespace() : project.GetDataLayerDataContractsNamespace(),
20 | AccessModifier = AccessModifier.Public,
21 | Name = project.GetDataContractName(table),
22 | DbObject = table
23 | };
24 |
25 | foreach (var column in table.Columns)
26 | {
27 | definition.Properties.Add(new PropertyDefinition(AccessModifier.Public, project.Database.ResolveDatabaseType(column), project.GetPropertyName(table, column))
28 | {
29 | IsAutomatic = true
30 | });
31 | }
32 |
33 | foreach (var foreignKey in table.ForeignKeys)
34 | {
35 | var foreignTable = project.Database.FindTable(foreignKey.References);
36 |
37 | if (foreignTable == null)
38 | continue;
39 |
40 | var foreignKeyAlias = NamingConvention.GetCamelCase(project.GetEntityName(foreignTable));
41 |
42 | foreach (var column in foreignTable?.GetColumnsWithNoPrimaryKey())
43 | {
44 | var col = (Column)column;
45 |
46 | var propertyName = project.GetPropertyName(foreignTable, col);
47 |
48 | var target = string.Format("{0}{1}", project.GetEntityName(foreignTable), propertyName);
49 |
50 | if (definition.Properties.Count(item => item.Name == propertyName) == 0)
51 | definition.Properties.Add(new PropertyDefinition(AccessModifier.Public, project.Database.ResolveDatabaseType(col), target)
52 | {
53 | IsAutomatic = true
54 | });
55 | }
56 | }
57 |
58 | definition.SimplifyDataTypes();
59 |
60 | return definition;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/DbContextClassBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using CatFactory.CodeFactory;
4 | using CatFactory.CodeFactory.Scaffolding;
5 | using CatFactory.Collections;
6 | using CatFactory.NetCore;
7 | using CatFactory.NetCore.ObjectOrientedProgramming;
8 | using CatFactory.ObjectOrientedProgramming;
9 | using CatFactory.ObjectRelationalMapping;
10 |
11 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
12 | {
13 | public static class DbContextClassBuilder
14 | {
15 | public static DbContextClassDefinition GetDbContextClassDefinition(this EntityFrameworkCoreProject project, ProjectSelection projectSelection, bool isDomainDrivenDesign)
16 | {
17 | var definition = new DbContextClassDefinition
18 | {
19 | Namespaces =
20 | {
21 | "System",
22 | "Microsoft.EntityFrameworkCore",
23 | isDomainDrivenDesign ? project.GetDomainModelsNamespace() : project.GetEntityLayerNamespace()
24 | },
25 | Namespace = isDomainDrivenDesign ? project.Name : project.GetDataLayerNamespace(),
26 | AccessModifier = AccessModifier.Public,
27 | Name = project.GetDbContextName(project.Database),
28 | BaseClass = "DbContext"
29 | };
30 |
31 | if (projectSelection.Settings.UseApplyConfigurationsFromAssemblyMethod)
32 | definition.Namespaces.Add("System.Reflection");
33 |
34 | if (isDomainDrivenDesign)
35 | {
36 | if (!projectSelection.Settings.UseDataAnnotations)
37 | definition.Namespaces.Add(project.GetDomainConfigurationsNamespace());
38 | }
39 | else
40 | {
41 | if (!projectSelection.Settings.UseDataAnnotations)
42 | definition.Namespaces.Add(project.GetDataLayerConfigurationsNamespace());
43 | }
44 |
45 | definition.Constructors.Add(new ClassConstructorDefinition
46 | {
47 | AccessModifier = AccessModifier.Public,
48 | Parameters =
49 | {
50 | new ParameterDefinition(string.Format("DbContextOptions<{0}>", definition.Name), "options")
51 | },
52 | Invocation = "base(options)"
53 | });
54 |
55 | definition.Methods.Add(GetOnModelCreatingMethod(project));
56 |
57 | foreach (var table in project.Database.Tables)
58 | {
59 | if (isDomainDrivenDesign)
60 | {
61 | if (!project.Database.HasDefaultSchema(table))
62 | definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(table.Schema));
63 | }
64 | else
65 | {
66 | if (!project.Database.HasDefaultSchema(table))
67 | definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(table.Schema));
68 | }
69 |
70 | var existingViews = project.Database.Views.Count(item => item.Name == table.Name);
71 |
72 | var genericTypeName = existingViews == 0 ? project.GetEntityName(table) : project.GetFullEntityName(table);
73 | var name = existingViews == 0 ? project.GetDbSetPropertyName(table, projectSelection.Settings.PluralizeDbSetPropertyNames) : project.GetFullDbSetPropertyName(table);
74 |
75 | definition.Properties.Add(new PropertyDefinition(AccessModifier.Public, string.Format("DbSet<{0}>", genericTypeName), name) { IsAutomatic = true });
76 | }
77 |
78 | foreach (var view in project.Database.Views)
79 | {
80 | if (isDomainDrivenDesign)
81 | {
82 | if (!project.Database.HasDefaultSchema(view))
83 | definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(view.Schema));
84 | }
85 | else
86 | {
87 | if (!project.Database.HasDefaultSchema(view))
88 | definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(view.Schema));
89 | }
90 |
91 | var existingTables = project.Database.Tables.Count(item => item.Name == view.Name);
92 |
93 | var genericTypeName = existingTables == 0 ? project.GetEntityName(view) : project.GetFullEntityName(view);
94 | var name = existingTables == 0 ? project.GetDbSetPropertyName(view, projectSelection.Settings.PluralizeDbSetPropertyNames) : project.GetFullDbSetPropertyName(view);
95 |
96 | definition.Properties.Add(new PropertyDefinition(AccessModifier.Public, string.Format("DbSet<{0}>", genericTypeName), name) { IsAutomatic = true });
97 | }
98 |
99 | foreach (var table in project.Database.Tables)
100 | {
101 | if (isDomainDrivenDesign)
102 | {
103 | if (!projectSelection.Settings.UseDataAnnotations && !project.Database.HasDefaultSchema(table))
104 | definition.Namespaces.AddUnique(project.GetDomainConfigurationsNamespace(table.Schema));
105 | }
106 | else
107 | {
108 | if (!projectSelection.Settings.UseDataAnnotations && !project.Database.HasDefaultSchema(table))
109 | definition.Namespaces.AddUnique(project.GetDataLayerConfigurationsNamespace(table.Schema));
110 | }
111 | }
112 |
113 | foreach (var view in project.Database.Views)
114 | {
115 | if (isDomainDrivenDesign)
116 | {
117 | if (!projectSelection.Settings.UseDataAnnotations && !project.Database.HasDefaultSchema(view))
118 | definition.Namespaces.AddUnique(project.GetDomainConfigurationsNamespace(view.Schema));
119 | }
120 | else
121 | {
122 | if (!projectSelection.Settings.UseDataAnnotations && !project.Database.HasDefaultSchema(view))
123 | definition.Namespaces.AddUnique(project.GetDataLayerConfigurationsNamespace(view.Schema));
124 | }
125 | }
126 |
127 | var scalarFunctions = project.Database.GetScalarFunctions();
128 |
129 | foreach (var scalarFunction in scalarFunctions)
130 | {
131 | var parameterType = string.Empty;
132 |
133 | if (project.Database.HasTypeMappedToClr(scalarFunction.Parameters[0]))
134 | {
135 | var clrType = project.Database.GetClrMapForType(scalarFunction.Parameters[0]);
136 |
137 | parameterType = clrType.AllowClrNullable ? string.Format("{0}?", clrType.GetClrType().Name) : clrType.GetClrType().Name;
138 | }
139 | else
140 | {
141 | parameterType = "object";
142 | }
143 |
144 | var method = new MethodDefinition
145 | {
146 | Attributes =
147 | {
148 | new MetadataAttribute("DbFunction")
149 | {
150 | Sets =
151 | {
152 | new MetadataAttributeSet(project.Version >= EntityFrameworkCoreVersion.Version_3_0 ? "Name" : "FunctionName", string.Format("\"{0}\"", scalarFunction.Name)),
153 | new MetadataAttributeSet("Schema", string.Format("\"{0}\"", scalarFunction.Schema))
154 | }
155 | }
156 | },
157 | AccessModifier = AccessModifier.Public,
158 | IsStatic = true,
159 | Type = parameterType,
160 | Name = project.GetScalarFunctionMethodName(scalarFunction),
161 | Lines =
162 | {
163 | new CodeLine("throw new Exception();")
164 | }
165 | };
166 |
167 | var parameters = scalarFunction.Parameters.Where(item => !string.IsNullOrEmpty(item.Name)).ToList();
168 |
169 | foreach (var parameter in parameters)
170 | {
171 | var propertyType = project.Database.ResolveDatabaseType(parameter);
172 |
173 | method.Parameters.Add(new ParameterDefinition(parameterType, project.CodeNamingConvention.GetParameterName(parameter.Name)));
174 | }
175 |
176 | definition.Methods.Add(method);
177 | }
178 |
179 | if (projectSelection.Settings.SimplifyDataTypes)
180 | definition.SimplifyDataTypes();
181 |
182 | return definition;
183 | }
184 |
185 | private static MethodDefinition GetOnModelCreatingMethod(EntityFrameworkCoreProject project)
186 | {
187 | var lines = new List();
188 |
189 | var selection = project.GlobalSelection();
190 |
191 | if (selection.Settings.UseDataAnnotations)
192 | {
193 | var primaryKeys = project
194 | .Database
195 | .Tables
196 | .Where(item => item.PrimaryKey != null)
197 | .Select(item => item.GetColumnsFromConstraint(item.PrimaryKey).Select(key => key.Name).First())
198 | .ToList();
199 |
200 | foreach (var view in project.Database.Views)
201 | {
202 | var result = view.Columns.Where(item => primaryKeys.Contains(item.Name)).ToList();
203 |
204 | var exp = "modelBuilder.Entity<{0}>().HasKey(e => new {{ {1} }});";
205 | var properties = string.Join(", ", view.Columns.Select(item => string.Format("e.{0}", project.GetPropertyName(view, item))));
206 |
207 | if (result.Count == 0)
208 | {
209 | lines.Add(new CodeLine(exp, project.GetEntityName(view), properties));
210 | lines.Add(new EmptyLine());
211 | }
212 | else
213 | {
214 | properties = string.Join(", ", result.Select(item => string.Format("e.{0}", project.GetPropertyName(view, item))));
215 |
216 | lines.Add(new CodeLine(exp, project.GetEntityName(view), properties));
217 | lines.Add(new EmptyLine());
218 | }
219 | }
220 | }
221 | else
222 | {
223 | if (selection.Settings.UseApplyConfigurationsFromAssemblyMethod)
224 | {
225 | lines.Add(new CommentLine(" Apply all configurations from assembly"));
226 | lines.Add(new EmptyLine());
227 |
228 | lines.Add(new CodeLine("modelBuilder"));
229 | lines.Add(new CodeLine(1, ".ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly())"));
230 | lines.Add(new CodeLine(1, ";"));
231 | lines.Add(new EmptyLine());
232 | }
233 | else
234 | {
235 | var schemas = project.Database.DbObjects.Select(item => item.Schema).Distinct().OrderBy(item => item);
236 |
237 | if (project.Database.Tables.Count > 0)
238 | {
239 | lines.Add(new CommentLine(" Apply all configurations for tables"));
240 | lines.Add(new EmptyLine());
241 |
242 | foreach (var schema in schemas)
243 | {
244 | var tables = project.Database.FindTablesBySchema(schema).ToList();
245 |
246 | if (tables.Count == 0)
247 | continue;
248 |
249 | lines.Add(new CommentLine(" Schema '{0}'", schema));
250 |
251 | lines.Add(new CodeLine("modelBuilder"));
252 |
253 | foreach (var table in tables)
254 | {
255 | var existingViews = project.Database.Views.Count(item => item.Name == table.Name);
256 |
257 | var genericTypeName = existingViews == 0 ? project.GetEntityName(table) : project.GetFullEntityName(table);
258 | var name = existingViews == 0 ? project.GetEntityConfigurationName(table) : project.GetFullEntityConfigurationName(table);
259 |
260 | lines.Add(new CodeLine(1, ".ApplyConfiguration(new {0}())", name));
261 | }
262 |
263 | lines.Add(new CodeLine(";"));
264 | lines.Add(new EmptyLine());
265 | }
266 | }
267 |
268 | if (project.Database.Views.Count > 0)
269 | {
270 | lines.Add(new CommentLine(" Apply all configurations for views"));
271 | lines.Add(new EmptyLine());
272 |
273 | foreach (var schema in schemas)
274 | {
275 | var views = project.Database.FindViewsBySchema(schema).ToList();
276 |
277 | if (views.Count == 0)
278 | continue;
279 |
280 | lines.Add(new CommentLine(" Schema '{0}'", schema));
281 |
282 | lines.Add(new CodeLine("modelBuilder"));
283 |
284 | foreach (var view in views)
285 | {
286 | var existingTables = project.Database.Tables.Count(item => item.Name == view.Name);
287 |
288 | var genericTypeName = existingTables == 0 ? project.GetEntityName(view) : project.GetFullEntityName(view);
289 | var name = existingTables == 0 ? project.GetEntityConfigurationName(view) : project.GetFullEntityConfigurationName(view);
290 |
291 | lines.Add(new CodeLine(1, ".ApplyConfiguration(new {0}())", name));
292 | }
293 |
294 | lines.Add(new CodeLine(";"));
295 | lines.Add(new EmptyLine());
296 | }
297 | }
298 | }
299 |
300 | var tableFunctions = project.Database.GetTableFunctions();
301 |
302 | if (tableFunctions.Count > 0)
303 | {
304 | lines.Add(new CommentLine(" Register query types for table functions"));
305 | lines.Add(new EmptyLine());
306 |
307 | foreach (var view in tableFunctions)
308 | {
309 | lines.Add(new CodeLine("modelBuilder.Query<{0}>();", project.GetEntityResultName(view)));
310 | }
311 |
312 | lines.Add(new EmptyLine());
313 | }
314 |
315 | var storedProcedures = project.Database.GetStoredProcedures();
316 |
317 | if (storedProcedures.Count > 0)
318 | {
319 | lines.Add(new CommentLine(" Register query types for stored procedures"));
320 | lines.Add(new EmptyLine());
321 |
322 | foreach (var view in storedProcedures)
323 | {
324 | lines.Add(new CodeLine("modelBuilder.Query<{0}>();", project.GetEntityResultName(view)));
325 | }
326 |
327 | lines.Add(new EmptyLine());
328 | }
329 | }
330 |
331 | lines.Add(new CodeLine("base.OnModelCreating(modelBuilder);"));
332 |
333 | return new MethodDefinition
334 | {
335 | AccessModifier = AccessModifier.Protected,
336 | IsOverride = true,
337 | Type = "void",
338 | Name = "OnModelCreating",
339 | Parameters =
340 | {
341 | new ParameterDefinition("ModelBuilder", "modelBuilder")
342 | },
343 | Lines = lines
344 | };
345 | }
346 | }
347 | }
348 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/DbContextQueryExtensionsClassBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using CatFactory.CodeFactory;
5 | using CatFactory.CodeFactory.Scaffolding;
6 | using CatFactory.Collections;
7 | using CatFactory.NetCore;
8 | using CatFactory.NetCore.CodeFactory;
9 | using CatFactory.NetCore.ObjectOrientedProgramming;
10 | using CatFactory.ObjectOrientedProgramming;
11 | using CatFactory.ObjectRelationalMapping;
12 |
13 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
14 | {
15 | public static class DbContextQueryExtensionsClassBuilder
16 | {
17 | public static DbContextQueryExtensionsClassDefinition GetDbContextQueryExtensionsClassDefinition(this ProjectFeature projectFeature)
18 | {
19 | var project = projectFeature.GetEntityFrameworkCoreProject();
20 |
21 | var definition = new DbContextQueryExtensionsClassDefinition
22 | {
23 | Namespaces =
24 | {
25 | "System",
26 | "System.Collections.Generic",
27 | "System.Linq",
28 | "System.Threading.Tasks",
29 | "Microsoft.EntityFrameworkCore",
30 | project.GetDomainModelsNamespace()
31 | },
32 | Namespace = project.Name,
33 | AccessModifier = AccessModifier.Public,
34 | IsStatic = true,
35 | Name = projectFeature.GetQueryExtensionsClassName()
36 | };
37 |
38 | foreach (var table in projectFeature.GetTables())
39 | {
40 | var selection = projectFeature.GetEntityFrameworkCoreProject().GetSelection(table);
41 |
42 | if (!project.Database.HasDefaultSchema(table))
43 | definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(table.Schema));
44 |
45 | if (selection.Settings.EntitiesWithDataContracts)
46 | {
47 | definition.Namespaces.AddUnique(project.GetDomainQueryModelsNamespace());
48 | }
49 |
50 | definition.AddGetAllMethod(projectFeature, selection, table);
51 |
52 | if (table.PrimaryKey != null)
53 | definition.Methods.Add(GetGetMethod(projectFeature, selection, table));
54 |
55 | foreach (var unique in table.Uniques)
56 | {
57 | definition.Methods.Add(GetGetByUniqueMethods(projectFeature, table, unique));
58 | }
59 |
60 | if (selection.Settings.SimplifyDataTypes)
61 | definition.SimplifyDataTypes();
62 | }
63 |
64 | return definition;
65 | }
66 |
67 | private static void AddGetAllMethod(this CSharpClassDefinition definition, ProjectFeature projectFeature, ProjectSelection projectSelection, ITable table)
68 | {
69 | var project = projectFeature.GetEntityFrameworkCoreProject();
70 |
71 | var returnType = string.Empty;
72 |
73 | var lines = new List();
74 |
75 | if (projectSelection.Settings.EntitiesWithDataContracts)
76 | {
77 | returnType = project.GetQueryModelName(table);
78 |
79 | var dataContractPropertiesSets = new[]
80 | {
81 | new
82 | {
83 | IsForeign = false,
84 | Type = string.Empty,
85 | Nullable = false,
86 | ObjectSource = string.Empty,
87 | PropertySource = string.Empty,
88 | Target = string.Empty
89 | }
90 | }.ToList();
91 |
92 | var entityAlias = NamingConvention.GetCamelCase(project.GetEntityName(table));
93 |
94 | foreach (var column in table.Columns)
95 | {
96 | var propertyName = project.GetPropertyName(table, column);
97 |
98 | dataContractPropertiesSets.Add(new
99 | {
100 | IsForeign = false,
101 | column.Type,
102 | column.Nullable,
103 | ObjectSource = entityAlias,
104 | PropertySource = propertyName,
105 | Target = propertyName
106 | });
107 | }
108 |
109 | foreach (var foreignKey in table.ForeignKeys)
110 | {
111 | var foreignTable = projectFeature.Project.Database.FindTable(foreignKey.References);
112 |
113 | if (foreignTable == null)
114 | continue;
115 |
116 | var foreignKeyAlias = NamingConvention.GetCamelCase(project.GetEntityName(foreignTable));
117 |
118 | foreach (var column in foreignTable?.GetColumnsWithNoPrimaryKey())
119 | {
120 | var col = (Column)column;
121 |
122 | var propertyName = project.GetPropertyName(foreignTable, col);
123 |
124 | if (dataContractPropertiesSets.Where(item => string.Format("{0}.{1}", item.ObjectSource, item.PropertySource) == string.Format("{0}.{1}", entityAlias, propertyName)).Count() == 0)
125 | {
126 | var target = string.Format("{0}{1}", project.GetEntityName(foreignTable), propertyName);
127 |
128 | dataContractPropertiesSets.Add(new
129 | {
130 | IsForeign = true,
131 | column.Type,
132 | column.Nullable,
133 | ObjectSource = foreignKeyAlias,
134 | PropertySource = propertyName,
135 | Target = target
136 | });
137 | }
138 | }
139 | }
140 |
141 | lines.Add(new CommentLine(" Get query from DbSet"));
142 | lines.Add(new CodeLine("var query = from {0} in dbContext.{1}", entityAlias, project.GetDbSetPropertyName(table, projectSelection.Settings.PluralizeDbSetPropertyNames)));
143 |
144 | foreach (var foreignKey in table.ForeignKeys)
145 | {
146 | var foreignTable = projectFeature.Project.Database.FindTable(foreignKey.References);
147 |
148 | if (foreignTable == null)
149 | continue;
150 |
151 | var foreignKeyEntityName = project.GetDbSetPropertyName(foreignTable, projectSelection.Settings.PluralizeDbSetPropertyNames);
152 |
153 | var foreignKeyAlias = NamingConvention.GetCamelCase(project.GetEntityName(foreignTable));
154 |
155 | if (projectFeature.Project.Database.HasDefaultSchema(foreignTable))
156 | definition.Namespaces.AddUnique(project.GetDomainModelsNamespace());
157 | else
158 | definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(foreignTable.Schema));
159 |
160 | if (foreignKey.Key.Count == 0)
161 | {
162 | lines.Add(new PreprocessorDirectiveLine(1, " There isn't definition for key in foreign key '{0}' in your current database", foreignKey.References));
163 | }
164 | else if (foreignKey.Key.Count == 1)
165 | {
166 | if (foreignTable == null)
167 | {
168 | lines.Add(LineHelper.Warning(" There isn't definition for '{0}' in your current database", foreignKey.References));
169 | }
170 | else
171 | {
172 | var column = table.Columns.FirstOrDefault(item => item.Name == foreignKey.Key.First());
173 |
174 | var x = project.CodeNamingConvention.GetPropertyName(foreignKey.Key.First());
175 | var y = project.CodeNamingConvention.GetPropertyName(foreignTable.PrimaryKey.Key.First());
176 |
177 | if (column.Nullable)
178 | {
179 | lines.Add(new CodeLine(1, "join {0}Join in dbContext.{1} on {2}.{3} equals {0}Join.{4} into {0}Temp", foreignKeyAlias, foreignKeyEntityName, entityAlias, x, y));
180 | lines.Add(new CodeLine(2, "from {0} in {0}Temp.DefaultIfEmpty()", foreignKeyAlias, entityAlias, x, y));
181 | }
182 | else
183 | {
184 | lines.Add(new CodeLine(1, "join {0} in dbContext.{1} on {2}.{3} equals {0}.{4}", foreignKeyAlias, foreignKeyEntityName, entityAlias, x, y));
185 | }
186 | }
187 | }
188 | else
189 | {
190 | lines.Add(LineHelper.Warning(" Add logic for foreign key with multiple key"));
191 | }
192 | }
193 |
194 | lines.Add(new CodeLine(1, "select new {0}", returnType));
195 | lines.Add(new CodeLine(1, "{"));
196 |
197 | for (var i = 0; i < dataContractPropertiesSets.Count; i++)
198 | {
199 | var property = dataContractPropertiesSets[i];
200 |
201 | if (string.IsNullOrEmpty(property.ObjectSource) && string.IsNullOrEmpty(property.Target))
202 | continue;
203 |
204 | if (property.IsForeign)
205 | {
206 | // todo: Add extension method to retrieve database type map by name
207 |
208 | var dbTypeMap = projectFeature.Project.Database.DatabaseTypeMaps.FirstOrDefault(item => item.DatabaseType == property.Type);
209 |
210 | if (dbTypeMap == null)
211 | throw new ObjectRelationMappingException(string.Format("There isn't mapping for '{0}' type", property.Type));
212 |
213 | var clrType = dbTypeMap.GetClrType();
214 |
215 | if (clrType.FullName == typeof(byte[]).FullName)
216 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(byte[]) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
217 | else if (clrType.FullName == typeof(bool).FullName)
218 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(bool?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
219 | else if (clrType.FullName == typeof(string).FullName)
220 | lines.Add(new CodeLine(2, "{0} = {1} == null ? string.Empty : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
221 | else if (clrType.FullName == typeof(DateTime).FullName)
222 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(DateTime?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
223 | else if (clrType.FullName == typeof(TimeSpan).FullName)
224 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(TimeSpan?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
225 | else if (clrType.FullName == typeof(byte).FullName)
226 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(byte?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
227 | else if (clrType.FullName == typeof(short).FullName)
228 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(short?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
229 | else if (clrType.FullName == typeof(int).FullName)
230 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(int?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
231 | else if (clrType.FullName == typeof(long).FullName)
232 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(long?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
233 | else if (clrType.FullName == typeof(decimal).FullName)
234 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(decimal?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
235 | else if (clrType.FullName == typeof(double).FullName)
236 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(double?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
237 | else if (clrType.FullName == typeof(float).FullName)
238 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(float?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
239 | else if (clrType.FullName == typeof(Guid).FullName)
240 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(Guid?) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
241 | else
242 | lines.Add(new CodeLine(2, "{0} = {1} == null ? default(object) : {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
243 | }
244 | else
245 | {
246 | lines.Add(new CodeLine(2, "{0} = {1}.{2},", property.Target, property.ObjectSource, property.PropertySource));
247 | }
248 | }
249 |
250 | lines.Add(new CodeLine(1, "};"));
251 | lines.Add(new EmptyLine());
252 | }
253 | else
254 | {
255 | returnType = project.GetEntityName(table);
256 |
257 | var existingViews = project.Database.Views.Count(item => item.Name == table.Name);
258 |
259 | returnType = existingViews == 0 ? project.GetEntityName(table) : project.GetFullEntityName(table);
260 |
261 | var dbSetName = existingViews == 0 ? project.GetDbSetPropertyName(table, projectSelection.Settings.PluralizeDbSetPropertyNames) : project.GetFullDbSetPropertyName(table);
262 |
263 | lines.Add(new CommentLine(" Get query from DbSet"));
264 | lines.Add(new CodeLine("var query = dbContext.{0}.AsQueryable();", dbSetName));
265 |
266 | lines.Add(new EmptyLine());
267 | }
268 |
269 | var parameters = new List
270 | {
271 | new ParameterDefinition(project.GetDbContextName(project.Database), "dbContext")
272 | };
273 |
274 | if (table.ForeignKeys.Count == 0)
275 | {
276 | lines.Add(new CodeLine("return query;"));
277 | }
278 | else
279 | {
280 | for (var i = 0; i < table.ForeignKeys.Count; i++)
281 | {
282 | var foreignKey = table.ForeignKeys[i];
283 |
284 | if (foreignKey.Key.Count == 1)
285 | {
286 | var column = table.Columns.First(item => item.Name == foreignKey.Key.First());
287 |
288 | var parameterName = project.GetParameterName(column);
289 |
290 | parameters.Add(new ParameterDefinition(projectFeature.Project.Database.ResolveDatabaseType(column), parameterName, "null"));
291 |
292 | if (projectFeature.Project.Database.ColumnIsDateTime(column))
293 | {
294 | lines.Add(new CommentLine(" Filter by: '{0}'", column.Name));
295 | lines.Add(new CodeLine("if ({0}.HasValue)", parameterName));
296 | lines.Add(new CodeLine(1, "query = query.Where(item => item.{0} == {1});", project.GetPropertyName(table, column), parameterName));
297 | lines.Add(new EmptyLine());
298 | }
299 | else if (projectFeature.Project.Database.ColumnIsNumber(column))
300 | {
301 | lines.Add(new CommentLine(" Filter by: '{0}'", column.Name));
302 | lines.Add(new CodeLine("if ({0}.HasValue)", parameterName));
303 | lines.Add(new CodeLine(1, "query = query.Where(item => item.{0} == {1});", project.GetPropertyName(table, column), parameterName));
304 | lines.Add(new EmptyLine());
305 | }
306 | else if (projectFeature.Project.Database.ColumnIsString(column))
307 | {
308 | lines.Add(new CommentLine(" Filter by: '{0}'", column.Name));
309 | lines.Add(new CodeLine("if (!string.IsNullOrEmpty({0}))", parameterName));
310 | lines.Add(new CodeLine(1, "query = query.Where(item => item.{0} == {1});", project.GetPropertyName(table, column), parameterName));
311 | lines.Add(new EmptyLine());
312 | }
313 | else
314 | {
315 | lines.Add(new CommentLine(" Filter by: '{0}'", column.Name));
316 | lines.Add(new CodeLine("if ({0} != null)", parameterName));
317 | lines.Add(new CodeLine(1, "query = query.Where(item => item.{0} == {1});", project.GetPropertyName(table, column), parameterName));
318 | lines.Add(new EmptyLine());
319 | }
320 | }
321 | else
322 | {
323 | lines.Add(LineHelper.Warning("Add logic for foreign key with multiple key"));
324 | }
325 | }
326 |
327 | lines.Add(new CodeLine("return query;"));
328 | }
329 |
330 | definition.Methods.Add(new MethodDefinition
331 | {
332 | AccessModifier = AccessModifier.Public,
333 | IsStatic = true,
334 | Type = string.Format("IQueryable<{0}>", returnType),
335 | Name = project.GetGetAllExtensionMethodName(table),
336 | IsExtension = true,
337 | Parameters = parameters,
338 | Lines = lines
339 | });
340 | }
341 |
342 | private static MethodDefinition GetGetMethod(ProjectFeature projectFeature, ProjectSelection projectSelection, ITable table)
343 | {
344 | var project = projectFeature.GetEntityFrameworkCoreProject();
345 |
346 | var expression = string.Empty;
347 |
348 | if (table.Identity == null)
349 | expression = string.Format("item => {0}", string.Join(" && ", table.PrimaryKey.Key.Select(item => string.Format("item.{0} == entity.{0}", project.CodeNamingConvention.GetPropertyName(item)))));
350 | else
351 | expression = string.Format("item => item.{0} == entity.{0}", project.CodeNamingConvention.GetPropertyName(table.Identity.Name));
352 |
353 | var existingViews = project.Database.Views.Count(item => item.Name == table.Name);
354 |
355 | var genericTypeName = existingViews == 0 ? project.GetEntityName(table) : project.GetFullEntityName(table);
356 | var dbSetName = existingViews == 0 ? project.GetDbSetPropertyName(table, projectSelection.Settings.PluralizeDbSetPropertyNames) : project.GetFullDbSetPropertyName(table);
357 |
358 | var includeExpression = new List();
359 |
360 | if (projectSelection.Settings.DeclareNavigationProperties)
361 | {
362 | foreach (var foreignKey in table.ForeignKeys)
363 | {
364 | var foreignTable = project.Database.FindTable(foreignKey.References);
365 |
366 | if (foreignKey == null)
367 | continue;
368 |
369 | includeExpression.Add(string.Format("Include(e => e.{0})", foreignKey.GetParentNavigationProperty(foreignTable, project).Name));
370 | }
371 | }
372 |
373 | var method = new MethodDefinition
374 | {
375 | AccessModifier = AccessModifier.Public,
376 | IsStatic = true,
377 | IsAsync = true,
378 | Type = string.Format("Task<{0}>", project.GetEntityName(table)),
379 | Name = project.GetGetRepositoryMethodName(table),
380 | IsExtension = true,
381 | Parameters =
382 | {
383 | new ParameterDefinition(project.GetDbContextName(project.Database), "dbContext"),
384 | new ParameterDefinition(project.GetEntityName(table), "entity"),
385 | new ParameterDefinition("bool", "tracking", "true"),
386 | new ParameterDefinition("bool", "include", "true")
387 | }
388 | };
389 |
390 | if (includeExpression.Count == 0)
391 | {
392 | method.Lines = new()
393 | {
394 | new CodeLine("var query = dbContext.{0}.AsQueryable();", dbSetName),
395 | new EmptyLine(),
396 | new CodeLine("if (!tracking)"),
397 | new CodeLine(1, "query = query.AsNoTracking();"),
398 | new EmptyLine(),
399 | new CodeLine("return await query.FirstOrDefaultAsync({1});", dbSetName, expression)
400 | };
401 | }
402 | else
403 | {
404 | method.Lines = new()
405 | {
406 | new CodeLine("var query = dbContext.{0}.AsQueryable();", dbSetName),
407 | new EmptyLine(),
408 | new CodeLine("if (!tracking)"),
409 | new CodeLine(1, "query = query.AsNoTracking();"),
410 | new EmptyLine(),
411 | new CodeLine("if (include)"),
412 | new CodeLine(1, "query = query.{0};", string.Join(".", includeExpression)),
413 | new EmptyLine(),
414 | new CodeLine("return await query.FirstOrDefaultAsync({1});", dbSetName, expression)
415 | };
416 | }
417 |
418 | return method;
419 | }
420 |
421 | private static MethodDefinition GetGetByUniqueMethods(ProjectFeature projectFeature, ITable table, Unique unique)
422 | {
423 | var project = projectFeature.GetEntityFrameworkCoreProject();
424 |
425 | var selection = project.GetSelection(table);
426 |
427 | var expression = string.Format("item => {0}", string.Join(" && ", unique.Key.Select(item => string.Format("item.{0} == entity.{0}", project.CodeNamingConvention.GetPropertyName(item)))));
428 |
429 | var existingViews = project.Database.Views.Count(item => item.Name == table.Name);
430 |
431 | var genericTypeName = existingViews == 0 ? project.GetEntityName(table) : project.GetFullEntityName(table);
432 | var dbSetName = existingViews == 0 ? project.GetDbSetPropertyName(table, selection.Settings.PluralizeDbSetPropertyNames) : project.GetFullDbSetPropertyName(table);
433 |
434 | var includeExpression = new List();
435 |
436 | if (selection.Settings.DeclareNavigationProperties)
437 | {
438 | foreach (var foreignKey in table.ForeignKeys)
439 | {
440 | var foreignTable = project.Database.FindTable(foreignKey.References);
441 |
442 | if (foreignKey == null)
443 | continue;
444 |
445 | includeExpression.Add(string.Format("Include(e => e.{0})", foreignKey.GetParentNavigationProperty(foreignTable, project).Name));
446 | }
447 | }
448 |
449 | return new MethodDefinition
450 | {
451 | AccessModifier = AccessModifier.Public,
452 | IsStatic = true,
453 | IsAsync = true,
454 | Type = string.Format("Task<{0}>", project.GetEntityName(table)),
455 | Name = project.GetGetByUniqueRepositoryMethodName(table, unique),
456 | IsExtension = true,
457 | Parameters =
458 | {
459 | new ParameterDefinition(project.GetDbContextName(project.Database), "dbContext"),
460 | new ParameterDefinition(project.GetEntityName(table), "entity"),
461 | new ParameterDefinition("bool", "tracking", "true"),
462 | new ParameterDefinition("bool", "include", "true")
463 | },
464 | Lines =
465 | {
466 | new CodeLine("var query = dbContext.{0}.AsQueryable();", dbSetName),
467 | new EmptyLine(),
468 | new CodeLine("if (!tracking)"),
469 | new CodeLine(1, "query = query.AsNoTracking();"),
470 | new EmptyLine(),
471 | new CodeLine("if (include)"),
472 | new CodeLine(1, "query = query.{0};", string.Join(".", includeExpression)),
473 | new EmptyLine(),
474 | new CodeLine("return await query.FirstOrDefaultAsync({1});", dbSetName, expression)
475 | }
476 | };
477 | }
478 | }
479 | }
480 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/EntityClassBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using CatFactory.CodeFactory;
3 | using CatFactory.Collections;
4 | using CatFactory.NetCore;
5 | using CatFactory.NetCore.ObjectOrientedProgramming;
6 | using CatFactory.ObjectOrientedProgramming;
7 | using CatFactory.ObjectRelationalMapping;
8 | using CatFactory.ObjectRelationalMapping.Programmability;
9 |
10 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
11 | {
12 | public static class EntityClassBuilder
13 | {
14 | public static EntityClassDefinition GetEntityClassDefinition(this EntityFrameworkCoreProject project, ITable table, bool isDomainDrivenDesign)
15 | {
16 | var definition = new EntityClassDefinition
17 | {
18 | Namespaces =
19 | {
20 | "System"
21 | },
22 | AccessModifier = AccessModifier.Public,
23 | Name = project.GetEntityName(table),
24 | IsPartial = true,
25 | Constructors =
26 | {
27 | new ClassConstructorDefinition(AccessModifier.Public)
28 | },
29 | DbObject = table
30 | };
31 |
32 | if (isDomainDrivenDesign)
33 | definition.Namespace = project.Database.HasDefaultSchema(table) ? project.GetDomainModelsNamespace() : project.GetDomainModelsNamespace(table.Schema);
34 | else
35 | definition.Namespace = project.Database.HasDefaultSchema(table) ? project.GetEntityLayerNamespace() : project.GetEntityLayerNamespace(table.Schema);
36 |
37 | if (!string.IsNullOrEmpty(table.Description))
38 | definition.Documentation.Summary = table.Description;
39 |
40 | var projectSelection = project.GetSelection(table);
41 |
42 | if (projectSelection.Settings.UseDataAnnotations)
43 | {
44 | definition.Namespaces.Add("System.ComponentModel.DataAnnotations");
45 | definition.Namespaces.Add("System.ComponentModel.DataAnnotations.Schema");
46 | }
47 |
48 | if (projectSelection.Settings.EnableDataBindings)
49 | {
50 | definition.Namespaces.Add("System.ComponentModel");
51 |
52 | definition.Implements.Add("INotifyPropertyChanged");
53 |
54 | definition.Events.Add(new EventDefinition("PropertyChangedEventHandler", "PropertyChanged"));
55 | }
56 |
57 | if (table.PrimaryKey != null)
58 | {
59 | var constructor = new ClassConstructorDefinition
60 | {
61 | AccessModifier = AccessModifier.Public
62 | };
63 |
64 | foreach (var key in table.GetColumnsFromConstraint(table.PrimaryKey))
65 | {
66 | var col = (Column)key;
67 |
68 | var propertyType = project.Database.ResolveDatabaseType(col);
69 |
70 | constructor.Parameters.Add(new ParameterDefinition(propertyType, project.GetParameterName(col)));
71 |
72 | constructor.Lines.Add(new CodeLine("{0} = {1};", project.GetPropertyName(key.Name), project.GetParameterName(col)));
73 | }
74 |
75 | definition.Constructors.Add(constructor);
76 | }
77 |
78 | var columns = table.Columns;
79 |
80 | foreach (var column in columns)
81 | {
82 | var propertyType = project.Database.ResolveDatabaseType(column);
83 |
84 | if (projectSelection.Settings.EnableDataBindings)
85 | {
86 | definition.AddPropWithField(propertyType, project.GetPropertyName(table, column));
87 | }
88 | else
89 | {
90 | if (projectSelection.Settings.BackingFields.Contains(table.GetFullColumnName(column)))
91 | {
92 | definition.AddPropWithField(propertyType, project.GetPropertyName(table, column));
93 | }
94 | else if (projectSelection.Settings.UseAutomaticPropertiesForEntities)
95 | {
96 | definition.Properties.Add(new PropertyDefinition(AccessModifier.Public, propertyType, project.GetPropertyName(table, column))
97 | {
98 | IsAutomatic = true
99 | });
100 | }
101 | else
102 | {
103 | definition.AddPropWithField(propertyType, project.GetPropertyName(table, column));
104 | }
105 | }
106 | }
107 |
108 | if (projectSelection.Settings.AuditEntity == null)
109 | {
110 | definition.Implements.Add(projectSelection.Settings.EntityInterfaceName);
111 | }
112 | else
113 | {
114 | var count = 0;
115 |
116 | foreach (var column in columns)
117 | {
118 | if (projectSelection.Settings.AuditEntity.Names.Contains(column.Name))
119 | count += 1;
120 | }
121 |
122 | if (count == projectSelection.Settings.AuditEntity.Names.Count())
123 | definition.Implements.Add("IAuditEntity");
124 | else
125 | definition.Implements.Add("IEntity");
126 | }
127 |
128 | if (projectSelection.Settings.SimplifyDataTypes)
129 | definition.SimplifyDataTypes();
130 |
131 | if (projectSelection.Settings.DeclareNavigationProperties)
132 | {
133 | foreach (var foreignKey in table.ForeignKeys)
134 | {
135 | var foreignTable = project.Database.FindTable(foreignKey.References);
136 |
137 | if (foreignTable == null)
138 | continue;
139 |
140 | if (isDomainDrivenDesign)
141 | {
142 | if (definition.Namespace != project.GetDomainModelsNamespace(foreignTable.Schema))
143 | {
144 | definition
145 | .Namespaces
146 | .AddUnique(project.Database.HasDefaultSchema(foreignTable) ? project.GetDomainModelsNamespace() : project.GetDomainModelsNamespace(foreignTable.Schema))
147 | ;
148 | }
149 | }
150 | else
151 | {
152 | if (definition.Namespace != project.GetEntityLayerNamespace(foreignTable.Schema))
153 | {
154 | definition
155 | .Namespaces
156 | .AddUnique(project.Database.HasDefaultSchema(foreignTable) ? project.GetEntityLayerNamespace() : project.GetEntityLayerNamespace(foreignTable.Schema))
157 | ;
158 | }
159 | }
160 |
161 | var fkProperty = foreignKey.GetParentNavigationProperty(foreignTable, project);
162 |
163 | if (!definition.Properties.Any(item => item.Name == fkProperty.Name))
164 | definition.Properties.Add(fkProperty);
165 | }
166 |
167 | foreach (var child in project.Database.Tables)
168 | {
169 | foreach (var foreignKey in child.ForeignKeys)
170 | {
171 | if (foreignKey.References.EndsWith(table.FullName))
172 | {
173 | definition.Namespaces
174 | .AddUnique(projectSelection.Settings.NavigationPropertyEnumerableNamespace);
175 |
176 | if (isDomainDrivenDesign)
177 | {
178 | if (definition.Namespace != project.GetDomainModelsNamespace(child.Schema))
179 | {
180 | definition
181 | .Namespaces
182 | .AddUnique(project.Database.HasDefaultSchema(child) ? project.GetDomainModelsNamespace() : project.GetDomainModelsNamespace(child.Schema))
183 | ;
184 | }
185 | }
186 | else
187 | {
188 | if (definition.Namespace != project.GetEntityLayerNamespace(child.Schema))
189 | {
190 | definition
191 | .Namespaces
192 | .AddUnique(project.Database.HasDefaultSchema(child) ? project.GetEntityLayerNamespace() : project.GetEntityLayerNamespace(child.Schema))
193 | ;
194 | }
195 | }
196 |
197 | var navigationProperty = project.GetChildNavigationProperty(projectSelection, child, foreignKey);
198 |
199 | if (!definition.Properties.Any(item => item.Name == navigationProperty.Name))
200 | definition.Properties.Add(navigationProperty);
201 | }
202 | }
203 | }
204 | }
205 |
206 | return definition;
207 | }
208 |
209 | public static EntityClassDefinition GetEntityClassDefinition(this EntityFrameworkCoreProject project, IView view, string ns)
210 | {
211 | var definition = new EntityClassDefinition
212 | {
213 | Namespaces =
214 | {
215 | "System"
216 | },
217 | Namespace = ns,
218 | AccessModifier = AccessModifier.Public,
219 | Name = project.GetEntityName(view),
220 | IsPartial = true,
221 | Constructors =
222 | {
223 | new ClassConstructorDefinition
224 | {
225 | AccessModifier = AccessModifier.Public
226 | }
227 | },
228 | DbObject = view
229 | };
230 |
231 | if (!string.IsNullOrEmpty(view.Description))
232 | definition.Documentation.Summary = view.Description;
233 |
234 | var projectSelection = project.GetSelection(view);
235 |
236 | if (projectSelection.Settings.UseDataAnnotations)
237 | {
238 | definition.Namespaces.Add("System.ComponentModel.DataAnnotations");
239 | definition.Namespaces.Add("System.ComponentModel.DataAnnotations.Schema");
240 | }
241 |
242 | foreach (var column in view.Columns)
243 | {
244 | var propertyType = project.Database.ResolveDatabaseType(column);
245 |
246 | definition.Properties.Add(new PropertyDefinition
247 | {
248 | AccessModifier = AccessModifier.Public,
249 | Type = propertyType,
250 | Name = project.GetPropertyName(view, column),
251 | IsAutomatic = true
252 | });
253 | }
254 |
255 | if (projectSelection.Settings.SimplifyDataTypes)
256 | definition.SimplifyDataTypes();
257 |
258 | return definition;
259 | }
260 |
261 | public static EntityClassDefinition GetEntityClassDefinition(this EntityFrameworkCoreProject project, TableFunction tableFunction)
262 | {
263 | var definition = new EntityClassDefinition
264 | {
265 | Namespaces =
266 | {
267 | "System"
268 | },
269 | Namespace = project.Database.HasDefaultSchema(tableFunction) ? project.GetEntityLayerNamespace() : project.GetEntityLayerNamespace(tableFunction.Schema),
270 | AccessModifier = AccessModifier.Public,
271 | Name = project.GetEntityResultName(tableFunction),
272 | IsPartial = true,
273 | Constructors =
274 | {
275 | new ClassConstructorDefinition
276 | {
277 | AccessModifier = AccessModifier.Public
278 | }
279 | },
280 | DbObject = tableFunction
281 | };
282 |
283 | if (!string.IsNullOrEmpty(tableFunction.Description))
284 | definition.Documentation.Summary = tableFunction.Description;
285 |
286 | var projectSelection = project.GetSelection(tableFunction);
287 |
288 | foreach (var column in tableFunction.Columns)
289 | {
290 | var type = project.Database.ResolveDatabaseType(column);
291 |
292 | definition.Properties.Add(new PropertyDefinition(AccessModifier.Public, type, project.GetPropertyName(column.Name)) { IsAutomatic = true });
293 | }
294 |
295 | if (projectSelection.Settings.SimplifyDataTypes)
296 | definition.SimplifyDataTypes();
297 |
298 | return definition;
299 | }
300 |
301 | public static EntityClassDefinition GetEntityClassDefinition(this EntityFrameworkCoreProject project, StoredProcedure storedProcedure)
302 | {
303 | var definition = new EntityClassDefinition
304 | {
305 | Namespaces =
306 | {
307 | "System"
308 | },
309 | Namespace = project.Database.HasDefaultSchema(storedProcedure) ? project.GetEntityLayerNamespace() : project.GetEntityLayerNamespace(storedProcedure.Schema),
310 | AccessModifier = AccessModifier.Public,
311 | Name = project.GetEntityResultName(storedProcedure),
312 | IsPartial = true,
313 | Constructors =
314 | {
315 | new ClassConstructorDefinition
316 | {
317 | AccessModifier = AccessModifier.Public
318 | }
319 | },
320 | DbObject = storedProcedure
321 | };
322 |
323 | if (!string.IsNullOrEmpty(storedProcedure.Description))
324 | definition.Documentation.Summary = storedProcedure.Description;
325 |
326 | var projectSelection = project.GetSelection(storedProcedure);
327 |
328 | if (storedProcedure.ResultSets.Count == 0)
329 | {
330 | // todo: Add logic to stored procedures with no result set
331 | }
332 | else
333 | {
334 | foreach (var property in storedProcedure.ResultSets)
335 | {
336 | var propertyType = project.Database.ResolveDatabaseType(property.Type);
337 |
338 | definition.Properties.Add(new PropertyDefinition(AccessModifier.Public, propertyType, project.GetPropertyName(property.Name))
339 | {
340 | IsAutomatic = true
341 | });
342 | }
343 | }
344 |
345 | if (projectSelection.Settings.SimplifyDataTypes)
346 | definition.SimplifyDataTypes();
347 |
348 | return definition;
349 | }
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/EntityConfigurationClassBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using CatFactory.CodeFactory;
5 | using CatFactory.Collections;
6 | using CatFactory.NetCore;
7 | using CatFactory.NetCore.CodeFactory;
8 | using CatFactory.ObjectOrientedProgramming;
9 | using CatFactory.ObjectRelationalMapping;
10 |
11 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
12 | {
13 | public static class EntityConfigurationClassBuilder
14 | {
15 | public static EntityConfigurationClassDefinition GetEntityConfigurationClassDefinition(this EntityFrameworkCoreProject project, ITable table, bool isDomainDrivenDesign)
16 | {
17 | var definition = new EntityConfigurationClassDefinition
18 | {
19 | Namespaces =
20 | {
21 | "Microsoft.EntityFrameworkCore",
22 | "Microsoft.EntityFrameworkCore.Metadata.Builders"
23 | },
24 | AccessModifier = AccessModifier.Internal,
25 | Name = project.GetEntityConfigurationName(table),
26 | DbObject = table
27 | };
28 |
29 | if (isDomainDrivenDesign)
30 | {
31 | definition.Namespace = project.GetDomainConfigurationsNamespace(project.Database.HasDefaultSchema(table) ? string.Empty : table.Schema);
32 | definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(project.Database.HasDefaultSchema(table) ? string.Empty : table.Schema));
33 | }
34 | else
35 | {
36 | definition.Namespace = project.Database.HasDefaultSchema(table) ? project.GetDataLayerConfigurationsNamespace() : project.GetDataLayerConfigurationsNamespace(table.Schema);
37 | definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(project.Database.HasDefaultSchema(table) ? string.Empty : table.Schema));
38 | }
39 |
40 | // todo: Check logic to build property's name
41 |
42 | var propertyType = "";
43 |
44 | if (table.HasSameEnclosingName())
45 | propertyType = string.Join(".", (new string[] { project.ProjectNamespaces.EntityLayer, project.Database.HasDefaultSchema(table) ? string.Empty : table.Schema, project.GetEntityName(table) }).Where(item => !string.IsNullOrEmpty(item)));
46 | else
47 | propertyType = project.GetEntityName(table);
48 |
49 | definition.Implements.Add(string.Format("IEntityTypeConfiguration<{0}>", propertyType));
50 |
51 | var configLines = new List
52 | {
53 | new CommentLine(" Set configuration for entity")
54 | };
55 |
56 | if (string.IsNullOrEmpty(table.Schema))
57 | configLines.Add(new CodeLine("builder.ToTable(\"{0}\");", table.Name));
58 | else
59 | configLines.Add(new CodeLine("builder.ToTable(\"{0}\", \"{1}\");", table.Name, table.Schema));
60 |
61 | configLines.Add(new EmptyLine());
62 |
63 | var columns = default(List);
64 |
65 | if (table.PrimaryKey == null || table.PrimaryKey.Key.Count == 0)
66 | {
67 | configLines.Add(LineHelper.Warning("Add configuration for entity's key"));
68 | configLines.Add(new EmptyLine());
69 | }
70 | else
71 | {
72 | configLines.Add(new CommentLine(" Set key for entity"));
73 |
74 | if (table.PrimaryKey.Key.Count == 1)
75 | {
76 | configLines.Add(new CodeLine("builder.HasKey(p => p.{0});", project.CodeNamingConvention.GetPropertyName(table.PrimaryKey.Key[0])));
77 | configLines.Add(new EmptyLine());
78 | }
79 | else if (table.PrimaryKey.Key.Count > 1)
80 | {
81 | configLines.Add(new CodeLine("builder.HasKey(p => new {{ {0} }});", string.Join(", ", table.PrimaryKey.Key.Select(item => string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(item))))));
82 | configLines.Add(new EmptyLine());
83 | }
84 | }
85 |
86 | if (table.Identity != null)
87 | {
88 | configLines.Add(new CommentLine(" Set identity for entity (auto increment)"));
89 |
90 | if (project.Version >= EntityFrameworkCoreVersion.Version_3_0)
91 | {
92 | var exp = new List();
93 |
94 | if (table.Identity.Seed != 1)
95 | exp.Add(string.Format("seed: {0}", table.Identity.Seed));
96 |
97 | if (table.Identity.Increment != 1)
98 | exp.Add(string.Format("increment: {0}", table.Identity.Increment));
99 |
100 | configLines.Add(new CodeLine("builder.Property(p => p.{0}).UseIdentityColumn({1});", project.CodeNamingConvention.GetPropertyName(table.Identity.Name), string.Join(",", exp)));
101 | }
102 | else
103 | configLines.Add(new CodeLine("builder.Property(p => p.{0}).UseSqlServerIdentityColumn();", project.CodeNamingConvention.GetPropertyName(table.Identity.Name)));
104 |
105 | configLines.Add(new EmptyLine());
106 | }
107 |
108 | columns = table.Columns;
109 |
110 | configLines.Add(new CommentLine(" Set configuration for columns"));
111 |
112 | for (var i = 0; i < columns.Count; i++)
113 | {
114 | var column = columns[i];
115 |
116 | var valueConversion = default(Type);
117 |
118 | if (project.Database.HasTypeMappedToClr(column))
119 | {
120 | var lines = new List
121 | {
122 | string.Format("Property(p => p.{0})", project.GetPropertyName(table, column))
123 | };
124 |
125 | if (string.Compare(column.Name, project.GetPropertyName(table, column)) != 0)
126 | lines.Add(string.Format("HasColumnName(\"{0}\")", column.Name));
127 |
128 | if (project.Database.ColumnIsByteArray(column))
129 | lines.Add(string.Format("HasColumnType(\"{0}({1})\")", column.Type, column.Length));
130 | else if (project.Database.ColumnIsDecimal(column))
131 | lines.Add(string.Format("HasColumnType(\"{0}({1}, {2})\")", column.Type, column.Prec, column.Scale));
132 | else if (project.Database.ColumnIsDouble(column) || project.Database.ColumnIsSingle(column))
133 | lines.Add(string.Format("HasColumnType(\"{0}({1})\")", column.Type, column.Prec));
134 | else if (project.Database.ColumnIsString(column))
135 | {
136 | if (column.Length <= 0)
137 | {
138 | lines.Add(string.Format("HasColumnType(\"{0}(max)\")", column.Type));
139 | }
140 | else
141 | {
142 | lines.Add(string.Format("HasColumnType(\"{0}\")", column.Type));
143 | lines.Add(string.Format("HasMaxLength({0})", column.Length));
144 | }
145 | }
146 | else
147 | lines.Add(string.Format("HasColumnType(\"{0}\")", column.Type));
148 |
149 | // todo: Use ValueConversionMaps to detect and apply ValueConversion Type based on Type
150 |
151 | if (project.ValueConversionMaps.TryGetValue(column.Type, out valueConversion) == true)
152 | lines.Add($".HasConversion(typeof({valueConversion?.FullName}))");
153 |
154 | if (!column.Nullable)
155 | lines.Add("IsRequired()");
156 |
157 | configLines.Add(new CodeLine("builder"));
158 |
159 | foreach (var line in lines)
160 | {
161 | configLines.Add(new CodeLine(1, ".{0}", line));
162 | }
163 |
164 | configLines.Add(new CodeLine(1, ";"));
165 | configLines.Add(new EmptyLine());
166 | }
167 | else
168 | {
169 | configLines.Add(new CodeLine("builder.Ignore(p => p.{0});", project.GetPropertyName(table, column)));
170 | configLines.Add(new EmptyLine());
171 | }
172 | }
173 |
174 | var projectSelection = project.GetSelection(table);
175 |
176 | for (var i = 0; i < columns.Count; i++)
177 | {
178 | var column = columns[i];
179 |
180 | if (projectSelection.Settings.HasConcurrencyToken && string.Compare(column.Name, projectSelection.Settings.ConcurrencyToken) == 0)
181 | {
182 | configLines.Add(new CommentLine(" Set concurrency token for entity"));
183 | configLines.Add(new CodeLine("builder"));
184 | configLines.Add(new CodeLine(1, ".Property(p => p.{0})", project.GetPropertyName(table, column)));
185 | configLines.Add(new CodeLine(1, ".ValueGeneratedOnAddOrUpdate()"));
186 | configLines.Add(new CodeLine(1, ".IsConcurrencyToken()"));
187 | configLines.Add(new CodeLine(1, ";"));
188 | configLines.Add(new EmptyLine());
189 | }
190 |
191 | if (projectSelection.Settings.HasRowVersion && string.Compare(column.Name, projectSelection.Settings.RowVersion) == 0)
192 | {
193 | configLines.Add(new CommentLine(" Set row version for entity"));
194 | configLines.Add(new CodeLine("builder"));
195 | configLines.Add(new CodeLine(1, ".Property(p => p.{0})", project.GetPropertyName(table, column)));
196 | configLines.Add(new CodeLine(1, ".ValueGeneratedOnAddOrUpdate()"));
197 | configLines.Add(new CodeLine(1, ".IsRowVersion()"));
198 | configLines.Add(new CodeLine(1, ";"));
199 | configLines.Add(new EmptyLine());
200 | }
201 | }
202 |
203 | if (projectSelection.Settings.AddConfigurationForUniquesInFluentAPI && table.Uniques.Count > 0)
204 | {
205 | configLines.Add(new CommentLine(" Add configuration for uniques"));
206 | configLines.Add(new EmptyLine());
207 |
208 | foreach (var unique in table.Uniques)
209 | {
210 | configLines.Add(new CodeLine("builder"));
211 |
212 | if (unique.Key.Count == 1)
213 | {
214 | configLines.Add(new CodeLine(1, ".HasIndex(p => p.{0})", project.CodeNamingConvention.GetPropertyName(unique.Key.First())));
215 | configLines.Add(new CodeLine(1, ".IsUnique()"));
216 | }
217 | else
218 | {
219 | configLines.Add(new CodeLine(1, ".HasIndex(p => new {{ {0} }})", string.Join(", ", unique.Key.Select(item => string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(item))))));
220 | configLines.Add(new CodeLine(1, ".IsUnique()"));
221 | }
222 |
223 | if (project.Version >= EntityFrameworkCoreVersion.Version_5_0)
224 | configLines.Add(new CodeLine(1, ".HasDatabaseName(\"{0}\")", unique.ConstraintName));
225 | else
226 | configLines.Add(new CodeLine(1, ".HasName(\"{0}\")", unique.ConstraintName));
227 |
228 | configLines.Add(new CodeLine(1, ";"));
229 | configLines.Add(new EmptyLine());
230 | }
231 | }
232 |
233 | if (projectSelection.Settings.AddConfigurationForForeignKeysInFluentAPI && projectSelection.Settings.DeclareNavigationProperties && table.ForeignKeys.Count > 0)
234 | {
235 | configLines.Add(new CommentLine(" Add configuration for foreign keys"));
236 | configLines.Add(new EmptyLine());
237 |
238 | foreach (var foreignKey in table.ForeignKeys)
239 | {
240 | var foreignTable = project.Database.FindTable(foreignKey.References);
241 |
242 | if (foreignTable == null || foreignKey.Key.Count == 0)
243 | continue;
244 |
245 | if (foreignKey.Key.Count == 1)
246 | {
247 | var foreignProperty = foreignKey.GetParentNavigationProperty(foreignTable, project);
248 |
249 | configLines.Add(new CodeLine("builder"));
250 | configLines.Add(new CodeLine(1, ".HasOne(p => p.{0})", foreignProperty.Name));
251 | configLines.Add(new CodeLine(1, ".WithMany(b => b.{0})", project.GetNavigationPropertyName(table)));
252 | configLines.Add(new CodeLine(1, ".HasForeignKey(p => {0})", string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(foreignKey.Key.First()))));
253 | configLines.Add(new CodeLine(1, ".HasConstraintName(\"{0}\")", foreignKey.ConstraintName));
254 | configLines.Add(new CodeLine(1, ";"));
255 | configLines.Add(new EmptyLine());
256 | }
257 | else
258 | {
259 | configLines.Add(LineHelper.Warning(" Add logic for foreign key with multiple key"));
260 | }
261 | }
262 | }
263 |
264 | if (projectSelection.Settings.AddConfigurationForDefaultsInFluentAPI && table.Defaults.Count > 0)
265 | {
266 | configLines.Add(new CommentLine(" Add configuration for defaults"));
267 | configLines.Add(new EmptyLine());
268 |
269 | foreach (var def in table.Defaults)
270 | {
271 | var propertyName = def.Key.First();
272 |
273 | configLines.Add(new CodeLine("builder"));
274 | configLines.Add(new CodeLine(1, ".Property(p => p.{0})", project.GetPropertyName(propertyName)));
275 | configLines.Add(new CodeLine(1, ".HasDefaultValueSql(\"{0}\");", def.Value));
276 | configLines.Add(new EmptyLine());
277 | }
278 | }
279 |
280 | definition.Methods.Add(new MethodDefinition
281 | {
282 | AccessModifier = AccessModifier.Public,
283 | Type = "void",
284 | Name = "Configure",
285 | Parameters =
286 | {
287 | new ParameterDefinition(string.Format("EntityTypeBuilder<{0}>", propertyType), "builder")
288 | },
289 | Lines = configLines
290 | });
291 |
292 | return definition;
293 | }
294 |
295 | public static EntityConfigurationClassDefinition GetEntityConfigurationClassDefinition(this EntityFrameworkCoreProject project, IView view, bool isDomainDrivenDesign)
296 | {
297 | var definition = new EntityConfigurationClassDefinition
298 | {
299 | Namespaces =
300 | {
301 | "Microsoft.EntityFrameworkCore",
302 | "Microsoft.EntityFrameworkCore.Metadata.Builders"
303 | },
304 | AccessModifier = AccessModifier.Internal,
305 | Name = project.GetEntityConfigurationName(view),
306 | Implements =
307 | {
308 | string.Format("IEntityTypeConfiguration<{0}>", project.GetEntityName(view))
309 | },
310 | DbObject = view
311 | };
312 |
313 | if (isDomainDrivenDesign)
314 | {
315 | definition.Namespace = project.GetDomainConfigurationsNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema);
316 |
317 | definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema));
318 | definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema));
319 | }
320 | else
321 | {
322 | definition.Namespace = project.Database.HasDefaultSchema(view) ? project.GetDataLayerConfigurationsNamespace() : project.GetDataLayerConfigurationsNamespace(view.Schema);
323 |
324 | definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema));
325 | definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema));
326 | }
327 |
328 | var configLines = new List
329 | {
330 | new CommentLine(" Set configuration for entity")
331 | };
332 |
333 | if (string.IsNullOrEmpty(view.Schema))
334 | configLines.Add(new CodeLine("builder.ToTable(\"{0}\");", view.Name));
335 | else
336 | configLines.Add(new CodeLine("builder.ToTable(\"{0}\", \"{1}\");", view.Name, view.Schema));
337 |
338 | configLines.Add(new EmptyLine());
339 |
340 | var primaryKeys = project
341 | .Database
342 | .Tables
343 | .Where(item => item.PrimaryKey != null)
344 | .Select(item => item.GetColumnsFromConstraint(item.PrimaryKey).Select(c => c.Name).First())
345 | .ToList();
346 |
347 | var result = view.Columns.Where(item => primaryKeys.Contains(item.Name)).ToList();
348 |
349 | if (result.Count == 0)
350 | result = view.Columns.Where(item => !item.Nullable).ToList();
351 |
352 | configLines.Add(new CommentLine(" Add configuration for entity's key"));
353 |
354 | if (project.Version >= EntityFrameworkCoreVersion.Version_3_0)
355 | {
356 | configLines.Add(new CodeLine("builder.HasNoKey();"));
357 | }
358 | else
359 | {
360 | if (result.Count == 1)
361 | configLines.Add(new CodeLine("builder.HasKey(p => {0});", string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(result.First().Name))));
362 | else
363 | configLines.Add(new CodeLine("builder.HasKey(p => new {{ {0} }});", string.Join(", ", result.Select(item => string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(item.Name))))));
364 | }
365 |
366 | configLines.Add(new EmptyLine());
367 |
368 | configLines.Add(new CommentLine(" Set configuration for columns"));
369 |
370 | for (var i = 0; i < view.Columns.Count; i++)
371 | {
372 | var column = view.Columns[i];
373 |
374 | var valueConversion = default(Type);
375 |
376 | if (project.Database.HasTypeMappedToClr(column))
377 | {
378 | var lines = new List
379 | {
380 | string.Format("Property(p => p.{0})" , project.GetPropertyName( view, column))
381 | };
382 |
383 | if (string.Compare(column.Name, project.GetPropertyName(view, column)) != 0)
384 | lines.Add(string.Format("HasColumnName(\"{0}\")", column.Name));
385 |
386 | else if (project.Database.ColumnIsDecimal(column))
387 | lines.Add(string.Format("HasColumnType(\"{0}({1}, {2})\")", column.Type, column.Prec, column.Scale));
388 | else if (project.Database.ColumnIsDouble(column) || project.Database.ColumnIsSingle(column))
389 | lines.Add(string.Format("HasColumnType(\"{0}({1})\")", column.Type, column.Prec));
390 | if (project.Database.ColumnIsString(column))
391 | {
392 | if (column.Length <= 0)
393 | {
394 | lines.Add(string.Format("HasColumnType(\"{0}(max)\")", column.Type));
395 | }
396 | else
397 | {
398 | lines.Add(string.Format("HasColumnType(\"{0}\")", column.Type));
399 | lines.Add(string.Format("HasMaxLength({0})", column.Length));
400 | }
401 | }
402 | else
403 | lines.Add(string.Format("HasColumnType(\"{0}\")", column.Type));
404 |
405 | // todo: Use ValueConversionMaps to detect and apply ValueConversion Type based on Type
406 |
407 | if (project.ValueConversionMaps?.TryGetValue(column.Type, out valueConversion) == true)
408 | lines.Add($"HasConversion(typeof({valueConversion?.FullName}))");
409 |
410 | configLines.Add(new CodeLine("builder"));
411 |
412 | foreach (var line in lines)
413 | {
414 | configLines.Add(new CodeLine(1, ".{0}", line));
415 | }
416 |
417 | configLines.Add(new CodeLine(1, ";"));
418 | configLines.Add(new EmptyLine());
419 | }
420 | else
421 | {
422 | var lines = new List
423 | {
424 | string.Format("builder.Ignore(p => p.{0})", project.GetPropertyName( view, column))
425 | };
426 |
427 | configLines.Add(new CodeLine("{0}", string.Join(".", lines)));
428 | configLines.Add(new CodeLine(";"));
429 | }
430 | }
431 |
432 | definition.Methods.Add(new MethodDefinition
433 | {
434 | AccessModifier = AccessModifier.Public,
435 | Type = "void",
436 | Name = "Configure",
437 | Parameters =
438 | {
439 | new ParameterDefinition(string.Format("EntityTypeBuilder<{0}>", project.GetEntityName(view)), "builder")
440 | },
441 | Lines = configLines
442 | });
443 |
444 | return definition;
445 | }
446 | }
447 | }
448 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/EntityInterfaceBuilder.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
4 | {
5 | public static class EntityInterfaceBuilder
6 | {
7 | public static EntityInterfaceDefinition GetEntityInterfaceDefinition(this EntityFrameworkCoreProject project, bool isDomainDrivenDesign)
8 | => new EntityInterfaceDefinition
9 | {
10 | Namespace = isDomainDrivenDesign ? project.GetDomainModelsNamespace() : project.GetEntityLayerNamespace(),
11 | Namespaces =
12 | {
13 | "System"
14 | },
15 | AccessModifier = AccessModifier.Public,
16 | Name = "IEntity"
17 | };
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/PagingExtensionsClassBuilder.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.CodeFactory;
2 | using CatFactory.ObjectOrientedProgramming;
3 |
4 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
5 | {
6 | public static class PagingExtensionsClassBuilder
7 | {
8 | public static PagingExtensionsClassDefinition GetPagingExtensionsClassDefinition(this EntityFrameworkCoreProject project, bool isDomainDrivenDesign)
9 | {
10 | var definition = new PagingExtensionsClassDefinition
11 | {
12 | Namespaces =
13 | {
14 | "System",
15 | "System.Linq",
16 | },
17 | Namespace = isDomainDrivenDesign ? project.Name : project.GetDataLayerRepositoriesNamespace(),
18 | AccessModifier = AccessModifier.Public,
19 | IsStatic = true,
20 | Name = "PagingExtensions"
21 | };
22 |
23 | if (!isDomainDrivenDesign)
24 | {
25 | definition.Namespaces.Add(project.GetDataLayerNamespace());
26 | definition.Namespaces.Add(project.GetEntityLayerNamespace());
27 | }
28 |
29 | definition.Methods.Add(new MethodDefinition("IQueryable", "Paging", new ParameterDefinition(project.GetDbContextName(project.Database), "dbContext"), new ParameterDefinition("int", "pageSize", "0"), new ParameterDefinition("int", "pageNumber", "0"))
30 | {
31 | AccessModifier = AccessModifier.Public,
32 | IsExtension = true,
33 | IsStatic = true,
34 | GenericTypes =
35 | {
36 | new GenericTypeDefinition
37 | {
38 | Name = "TEntity",
39 | Constraint = "TEntity : class"
40 | }
41 | },
42 | Lines =
43 | {
44 | new CodeLine("var query = dbContext.Set().AsQueryable();"),
45 | new CodeLine(),
46 | new CodeLine("return pageSize > 0 && pageNumber > 0 ? query.Skip((pageNumber - 1) * pageSize).Take(pageSize) : query;")
47 | }
48 | });
49 |
50 | definition.Methods.Add(new MethodDefinition("IQueryable", "Paging", new ParameterDefinition("IQueryable", "query"), new ParameterDefinition("int", "pageSize", "0"), new ParameterDefinition("int", "pageNumber", "0"))
51 | {
52 | AccessModifier = AccessModifier.Public,
53 | IsExtension = true,
54 | IsStatic = true,
55 | GenericTypes =
56 | {
57 | new GenericTypeDefinition
58 | {
59 | Name = "TModel",
60 | Constraint = "TModel : class"
61 | }
62 | },
63 | Lines =
64 | {
65 | new CodeLine("return pageSize > 0 && pageNumber > 0 ? query.Skip((pageNumber - 1) * pageSize).Take(pageSize) : query;")
66 | }
67 | });
68 |
69 | return definition;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/QueryModelClassBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using CatFactory.NetCore;
3 | using CatFactory.NetCore.ObjectOrientedProgramming;
4 | using CatFactory.ObjectOrientedProgramming;
5 | using CatFactory.ObjectRelationalMapping;
6 |
7 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
8 | {
9 | public static class QueryModelClassBuilder
10 | {
11 | public static QueryModelClassDefinition GetQueryModelClassDefinition(this EntityFrameworkCoreProject project, ITable table)
12 | {
13 | var definition = new QueryModelClassDefinition
14 | {
15 | Namespaces =
16 | {
17 | "System"
18 | },
19 | Namespace = project.GetDomainQueryModelsNamespace(),
20 | AccessModifier = AccessModifier.Public,
21 | Name = project.GetQueryModelName(table),
22 | DbObject = table
23 | };
24 |
25 | foreach (var column in table.Columns)
26 | {
27 | definition.Properties.Add(new PropertyDefinition(AccessModifier.Public, project.Database.ResolveDatabaseType(column), project.GetPropertyName(table, column))
28 | {
29 | IsAutomatic = true
30 | });
31 | }
32 |
33 | foreach (var foreignKey in table.ForeignKeys)
34 | {
35 | var foreignTable = project.Database.FindTable(foreignKey.References);
36 |
37 | if (foreignTable == null)
38 | continue;
39 |
40 | var foreignKeyAlias = NamingConvention.GetCamelCase(project.GetEntityName(foreignTable));
41 |
42 | foreach (var column in foreignTable?.GetColumnsWithNoPrimaryKey())
43 | {
44 | var col = (Column)column;
45 |
46 | var propertyName = project.GetPropertyName(foreignTable, col);
47 |
48 | var target = string.Format("{0}{1}", project.GetEntityName(foreignTable), propertyName);
49 |
50 | if (definition.Properties.Count(item => item.Name == propertyName) == 0)
51 | definition.Properties.Add(new PropertyDefinition(AccessModifier.Public, project.Database.ResolveDatabaseType(col), target)
52 | {
53 | IsAutomatic = true
54 | });
55 | }
56 | }
57 |
58 | definition.SimplifyDataTypes();
59 |
60 | return definition;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/RepositoryBaseClassBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CatFactory.CodeFactory;
3 | using CatFactory.ObjectOrientedProgramming;
4 |
5 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
6 | {
7 | public static class RepositoryBaseClassBuilder
8 | {
9 | public static PagingExtensionsClassDefinition GetRepositoryBaseClassDefinition(this EntityFrameworkCoreProject project)
10 | {
11 | var definition = new PagingExtensionsClassDefinition
12 | {
13 | Namespaces =
14 | {
15 | "System",
16 | "System.Threading.Tasks",
17 | },
18 | Namespace = project.GetDataLayerContractsNamespace(),
19 | AccessModifier = AccessModifier.Public,
20 | Name = "Repository",
21 | Fields =
22 | {
23 | new FieldDefinition(AccessModifier.Protected, "bool", "Disposed"),
24 | new FieldDefinition(AccessModifier.Protected, project.GetDbContextName(project.Database), "DbContext")
25 | {
26 | IsReadOnly = true
27 | }
28 | },
29 | Constructors =
30 | {
31 | new ClassConstructorDefinition(AccessModifier.Public, new ParameterDefinition(project.GetDbContextName(project.Database), "dbContext"))
32 | {
33 | Lines =
34 | {
35 | new CodeLine("DbContext = dbContext;")
36 | }
37 | }
38 | },
39 | Methods =
40 | {
41 | new MethodDefinition(AccessModifier.Public, "void", "Dispose")
42 | {
43 | IsVirtual = true,
44 | Lines =
45 | {
46 | new CodeLine("if (Disposed)"),
47 | new CodeLine(1, "return;"),
48 | new EmptyLine(),
49 | new CodeLine("DbContext?.Dispose();"),
50 | new EmptyLine(),
51 | new CodeLine("Disposed = true;")
52 | }
53 | },
54 | GetAddMethod(project),
55 | GetUpdateMethod(project),
56 | GetRemoveMethod(project),
57 | new MethodDefinition(AccessModifier.Public, "int", "CommitChanges")
58 | {
59 | Lines =
60 | {
61 | new CodeLine("return DbContext.SaveChanges();")
62 | }
63 | },
64 | new MethodDefinition(AccessModifier.Public, "Task", "CommitChangesAsync")
65 | {
66 | IsAsync = true,
67 | Lines =
68 | {
69 | new CodeLine("return await DbContext.SaveChangesAsync();")
70 | }
71 | }
72 | }
73 | };
74 |
75 | var selection = project.GlobalSelection();
76 |
77 | if (selection.Settings.AuditEntity != null)
78 | definition.Namespaces.Add(project.GetEntityLayerNamespace());
79 |
80 | return definition;
81 | }
82 |
83 | private static MethodDefinition GetAddMethod(EntityFrameworkCoreProject project)
84 | {
85 | var lines = new List();
86 |
87 | var selection = project.GlobalSelection();
88 |
89 | if (selection.Settings.AuditEntity == null)
90 | {
91 | lines.AddRange(new List
92 | {
93 | new CodeLine("DbContext.Add(entity);")
94 | });
95 | }
96 | else
97 | {
98 | lines.AddRange(new List
99 | {
100 | new CommentLine(" Cast entity to IAuditEntity"),
101 | new CodeLine("if(entity is IAuditEntity cast)"),
102 | new CodeLine("{"),
103 | new CommentLine(1, " Set creation datetime"),
104 | new CodeLine(1, "cast.CreationDateTime = DateTime.Now;"),
105 | new CodeLine("}"),
106 | new CodeLine(),
107 | new CodeLine("DbContext.Add(entity);"),
108 | });
109 | }
110 |
111 | return new MethodDefinition("void", "Add", new ParameterDefinition("TEntity", "entity"))
112 | {
113 | AccessModifier = AccessModifier.Public,
114 | IsVirtual = true,
115 | GenericTypes =
116 | {
117 | new GenericTypeDefinition
118 | {
119 | Name = "TEntity",
120 | Constraint = "TEntity : class"
121 | }
122 | },
123 | Lines = lines
124 | };
125 | }
126 |
127 | private static MethodDefinition GetUpdateMethod(EntityFrameworkCoreProject project)
128 | {
129 | var lines = new List();
130 |
131 | var selection = project.GlobalSelection();
132 |
133 | if (selection.Settings.AuditEntity == null)
134 | {
135 | lines.AddRange(new List
136 | {
137 | new CodeLine("DbContext.Update(entity);")
138 | });
139 | }
140 | else
141 | {
142 | lines.AddRange(new List
143 | {
144 | new CommentLine(" Cast entity to IAuditEntity"),
145 | new CodeLine("if (entity is IAuditEntity cast)"),
146 | new CodeLine("{"),
147 | new CommentLine(1, " Set update datetime"),
148 | new CodeLine(1, "cast.LastUpdateDateTime = DateTime.Now;"),
149 | new CodeLine("}"),
150 | new CodeLine(),
151 | new CodeLine("DbContext.Update(entity);")
152 | });
153 | }
154 |
155 | return new MethodDefinition("void", "Update", new ParameterDefinition("TEntity", "entity"))
156 | {
157 | AccessModifier = AccessModifier.Public,
158 | IsVirtual = true,
159 | GenericTypes =
160 | {
161 | new GenericTypeDefinition
162 | {
163 | Name = "TEntity",
164 | Constraint = "TEntity : class"
165 | }
166 | },
167 | Lines = lines
168 | };
169 | }
170 |
171 | private static MethodDefinition GetRemoveMethod(EntityFrameworkCoreProject project)
172 | => new MethodDefinition("void", "Remove", new ParameterDefinition("TEntity", "entity"))
173 | {
174 | AccessModifier = AccessModifier.Public,
175 | IsVirtual = true,
176 | GenericTypes =
177 | {
178 | new GenericTypeDefinition
179 | {
180 | Name = "TEntity",
181 | Constraint = "TEntity : class"
182 | }
183 | },
184 | Lines =
185 | {
186 | new CodeLine("DbContext.Remove(entity);")
187 | }
188 | };
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/Extensions/RepositoryInterfaceBuilder.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions.Extensions
4 | {
5 | public static class RepositoryInterfaceBuilder
6 | {
7 | public static RepositoryInterfaceDefinition GetRepositoryInterfaceDefinition(this EntityFrameworkCoreProject project)
8 | => new RepositoryInterfaceDefinition
9 | {
10 | Namespaces =
11 | {
12 | "System",
13 | "System.Threading.Tasks"
14 | },
15 | Namespace = project.GetDataLayerContractsNamespace(),
16 | AccessModifier = AccessModifier.Public,
17 | Name = "IRepository",
18 | Implements =
19 | {
20 | "IDisposable"
21 | },
22 | Methods =
23 | {
24 | new MethodDefinition("void", "Add", new ParameterDefinition("TEntity", "entity"))
25 | {
26 | GenericTypes =
27 | {
28 | new GenericTypeDefinition
29 | {
30 | Name = "TEntity",
31 | Constraint = "TEntity : class"
32 | }
33 | }
34 | },
35 | new MethodDefinition("void", "Update", new ParameterDefinition("TEntity", "entity"))
36 | {
37 | GenericTypes =
38 | {
39 | new GenericTypeDefinition
40 | {
41 | Name = "TEntity",
42 | Constraint = "TEntity : class"
43 | }
44 | }
45 | },
46 | new MethodDefinition("void", "Remove", new ParameterDefinition("TEntity", "entity"))
47 | {
48 | GenericTypes =
49 | {
50 | new GenericTypeDefinition
51 | {
52 | Name = "TEntity",
53 | Constraint = "TEntity : class"
54 | }
55 | }
56 | },
57 | new MethodDefinition("int", "CommitChanges"),
58 | new MethodDefinition("Task", "CommitChangesAsync")
59 | }
60 | };
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/PagingExtensionsClassDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class PagingExtensionsClassDefinition : CSharpClassDefinition
6 | {
7 | public PagingExtensionsClassDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/QueryModelClassDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class QueryModelClassDefinition : CSharpClassDefinition
6 | {
7 | public QueryModelClassDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/RepositoryClassDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class RepositoryClassDefinition : CSharpClassDefinition
6 | {
7 | public RepositoryClassDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/Definitions/RepositoryInterfaceDefinition.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.NetCore.ObjectOrientedProgramming;
2 |
3 | namespace CatFactory.EntityFrameworkCore.Definitions
4 | {
5 | public class RepositoryInterfaceDefinition : CSharpInterfaceDefinition
6 | {
7 | public RepositoryInterfaceDefinition()
8 | : base()
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/DomainExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using CatFactory.EntityFrameworkCore.Definitions.Extensions;
3 | using CatFactory.Markdown;
4 | using CatFactory.ObjectRelationalMapping;
5 |
6 | namespace CatFactory.EntityFrameworkCore
7 | {
8 | public static class DomainExtensions
9 | {
10 | public static EntityFrameworkCoreProject ScaffoldDomain(this EntityFrameworkCoreProject project)
11 | {
12 | ScaffoldEntityInterface(project);
13 | ScaffoldModels(project);
14 |
15 | ScaffoldConfigurations(project);
16 |
17 | ScaffoldDbContext(project);
18 |
19 | ScaffoldQueryModels(project);
20 |
21 | ScaffoldExtensions(project);
22 |
23 | ScaffoldMdReadMe(project);
24 |
25 | return project;
26 | }
27 |
28 | internal static void ScaffoldEntityInterface(EntityFrameworkCoreProject project)
29 | {
30 | project.Scaffold(project.GetEntityInterfaceDefinition(true), project.GetDomainModelsDirectory());
31 |
32 | if (project.GlobalSelection().Settings.AuditEntity != null)
33 | project.Scaffold(project.GetAuditEntityInterfaceDefinition(true), project.GetDomainModelsDirectory());
34 | }
35 |
36 | internal static EntityFrameworkCoreProject ScaffoldModels(this EntityFrameworkCoreProject project)
37 | {
38 | foreach (var table in project.Database.Tables)
39 | {
40 | var selection = project.GetSelection(table);
41 |
42 | var definition = project.GetEntityClassDefinition(table, true);
43 |
44 | if (selection.Settings.UseDataAnnotations)
45 | definition.AddDataAnnotations(table, project);
46 |
47 | project.Scaffold(definition, project.GetDomainModelsDirectory(), project.Database.HasDefaultSchema(table) ? "" : table.Schema);
48 | }
49 |
50 | foreach (var view in project.Database.Views)
51 | {
52 | var selection = project.GetSelection(view);
53 |
54 | var definition = project.GetEntityClassDefinition(view, project.Database.HasDefaultSchema(view) ? project.GetDomainModelsNamespace() : project.GetDomainModelsNamespace(view.Schema));
55 |
56 | if (selection.Settings.UseDataAnnotations)
57 | definition.AddDataAnnotations(view, project);
58 |
59 | project.Scaffold(definition, project.GetDomainModelsDirectory(), project.Database.HasDefaultSchema(view) ? "" : view.Schema);
60 | }
61 |
62 | return project;
63 | }
64 |
65 | internal static void ScaffoldConfigurations(EntityFrameworkCoreProject project)
66 | {
67 | var projectSelection = project.GlobalSelection();
68 |
69 | if (!projectSelection.Settings.UseDataAnnotations)
70 | {
71 | foreach (var table in project.Database.Tables)
72 | {
73 | var definition = project.GetEntityConfigurationClassDefinition(table, true);
74 |
75 | project.Scaffold(definition, project.GetDomainConfigurationsDirectory(), project.Database.HasDefaultSchema(table) ? "" : table.Schema);
76 | }
77 |
78 | foreach (var view in project.Database.Views)
79 | {
80 | var definition = project.GetEntityConfigurationClassDefinition(view, true);
81 |
82 | project.Scaffold(definition, project.GetDomainConfigurationsDirectory(), project.Database.HasDefaultSchema(view) ? "" : view.Schema);
83 | }
84 | }
85 | }
86 |
87 | internal static void ScaffoldDbContext(EntityFrameworkCoreProject project)
88 | {
89 | var projectSelection = project.GlobalSelection();
90 |
91 | project.Scaffold(project.GetDbContextClassDefinition(projectSelection, true), project.GetDomainDirectory());
92 | }
93 |
94 | internal static void ScaffoldQueryModels(EntityFrameworkCoreProject project)
95 | {
96 | foreach (var table in project.Database.Tables)
97 | {
98 | var selection = project.GetSelection(table);
99 |
100 | if (!selection.Settings.EntitiesWithDataContracts)
101 | continue;
102 |
103 | project.Scaffold(project.GetQueryModelClassDefinition(table), project.GetDomainQueryModelsDirectory());
104 | }
105 | }
106 |
107 | internal static void ScaffoldExtensions(EntityFrameworkCoreProject project)
108 | {
109 | project.Scaffold(project.GetPagingExtensionsClassDefinition(true), project.GetDomainDirectory());
110 |
111 | foreach (var projectFeature in project.Features)
112 | {
113 | project.Scaffold(projectFeature.GetDbContextQueryExtensionsClassDefinition(), project.GetDomainDirectory());
114 | }
115 | }
116 |
117 | internal static void ScaffoldMdReadMe(this EntityFrameworkCoreProject project)
118 | {
119 | var readMe = new MdDocument();
120 |
121 | readMe.H1("CatFactory ==^^==: Scaffolding Made Easy");
122 |
123 | readMe.WriteLine("How to use this code on your ASP.NET Core Application:");
124 |
125 | readMe.OrderedList(
126 | "Install EntityFrameworkCore.SqlServer package",
127 | "Register the DbContext and Repositories in ConfigureServices method (Startup class)"
128 | );
129 |
130 | readMe.H2("Install package");
131 |
132 | readMe.WriteLine("You can install the NuGet packages in Visual Studio or Windows Command Line, for more info:");
133 |
134 | readMe.WriteLine(
135 | Md.Link("Install and manage packages with the Package Manager Console in Visual Studio (PowerShell)", "https://docs.microsoft.com/en-us/nuget/consume-packages/install-use-packages-powershell")
136 | );
137 |
138 | readMe.WriteLine(
139 | Md.Link(".NET Core CLI", "https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package")
140 | );
141 |
142 | readMe.H2("Register DbContext and Repositories");
143 |
144 | readMe.WriteLine("Add the following code lines in {0} method (Startup class):", Md.Bold("ConfigureServices"));
145 | readMe.WriteLine(" services.AddDbContext<{0}>(options => options.UseSqlServer(\"ConnectionString\"));", project.GetDbContextName(project.Database));
146 | readMe.WriteLine(" services.AddScope<{0}, {1}>()", "IDboRepository", "DboRepository");
147 |
148 | readMe.WriteLine("Happy scaffolding!");
149 |
150 | var codeProjectLink = Md.Link("Scaffolding Entity Framework Core with CatFactory", "https://www.codeproject.com/Articles/1160615/Scaffolding-Entity-Framework-Core-with-CatFactory");
151 |
152 | readMe.WriteLine("You can check the guide for this package in: {0}", codeProjectLink);
153 |
154 | var gitHubRepositoryLink = Md.Link("GitHub repository", "https://github.com/hherzl/CatFactory.EntityFrameworkCore");
155 |
156 | readMe.WriteLine("Also you can check the source code on {0}", gitHubRepositoryLink);
157 |
158 | readMe.WriteLine("CatFactory Development Team ==^^==");
159 |
160 | File.WriteAllText(Path.Combine(project.OutputDirectory, "README.md"), readMe.ToString());
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/EntityFrameworkCoreProject.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using CatFactory.CodeFactory;
6 | using CatFactory.CodeFactory.Scaffolding;
7 | using CatFactory.NetCore;
8 | using CatFactory.NetCore.CodeFactory;
9 | using CatFactory.NetCore.ObjectOrientedProgramming;
10 | using CatFactory.ObjectOrientedProgramming;
11 | using CatFactory.ObjectRelationalMapping;
12 | using Microsoft.Extensions.Logging;
13 |
14 | namespace CatFactory.EntityFrameworkCore
15 | {
16 | public class EntityFrameworkCoreProject : CSharpProject
17 | {
18 | public static EntityFrameworkCoreProject CreateForV2x(string name, Database database, string outputDirectory)
19 | => new()
20 | {
21 | Name = name,
22 | Database = database,
23 | OutputDirectory = outputDirectory,
24 | Version = EntityFrameworkCoreVersion.Version_2_0
25 | };
26 |
27 | public static EntityFrameworkCoreProject CreateForV3x(string name, Database database, string outputDirectory)
28 | => new()
29 | {
30 | Name = name,
31 | Database = database,
32 | OutputDirectory = outputDirectory,
33 | Version = EntityFrameworkCoreVersion.Version_3_0
34 | };
35 |
36 | public static EntityFrameworkCoreProject CreateForV5x(string name, Database database, string outputDirectory)
37 | => new()
38 | {
39 | Name = name,
40 | Database = database,
41 | OutputDirectory = outputDirectory,
42 | Version = EntityFrameworkCoreVersion.Version_5_0
43 | };
44 |
45 | [Obsolete("Replace using the CreateForV2x method")]
46 | public static EntityFrameworkCoreProject Create(string name, Database database, string outputDirectory)
47 | => new()
48 | {
49 | Name = name,
50 | Database = database,
51 | OutputDirectory = outputDirectory
52 | };
53 |
54 | [DebuggerBrowsable(DebuggerBrowsableState.Never)]
55 | private EntityFrameworkCoreProjectNamespaces m_projectNamespaces;
56 |
57 | [DebuggerBrowsable(DebuggerBrowsableState.Never)]
58 | private Dictionary m_valueConversionMaps;
59 |
60 | public EntityFrameworkCoreProject()
61 | : base()
62 | {
63 | }
64 |
65 | public EntityFrameworkCoreProject(ILogger logger)
66 | : base(logger)
67 | {
68 | }
69 |
70 | public EntityFrameworkCoreVersion Version { get; set; }
71 |
72 | public EntityFrameworkCoreProjectNamespaces ProjectNamespaces
73 | {
74 | get => m_projectNamespaces ??= new EntityFrameworkCoreProjectNamespaces();
75 | set => m_projectNamespaces = value;
76 | }
77 |
78 | ///
79 | /// A dictionary of (string)CatFactory.ObjectRelationalMapping.DatabaseTypeMap.DatabaseType to
80 | /// {OutputDirectory}\{EntityFrameworkCoreProjectNamespaces.ValueConversions}\Type can be
81 | /// submitted to the Entity Framework Core project via ValueConversionMaps for use in {Enity}Configuration.cs
82 | /// files
83 | ///
84 | public Dictionary ValueConversionMaps
85 | {
86 | get => m_valueConversionMaps ??= new Dictionary();
87 | set => m_valueConversionMaps = value;
88 | }
89 |
90 | // todo: Add logic to show author's info
91 | public AuthorInfo AuthorInfo { get; set; }
92 |
93 | protected override IEnumerable GetDbObjectsBySchema(string schema)
94 | {
95 | foreach (var item in base.GetDbObjectsBySchema(schema))
96 | {
97 | yield return item;
98 | }
99 |
100 | foreach (var item in Database.GetTableFunctions().Where(tableFunction => tableFunction.Schema == schema))
101 | {
102 | yield return new DbObject(item.Schema, item.Name)
103 | {
104 | Type = "TableFunction"
105 | };
106 | }
107 |
108 | foreach (var item in Database.GetStoredProcedures().Where(storedProcedure => storedProcedure.Schema == schema))
109 | {
110 | yield return new DbObject(item.Schema, item.Name)
111 | {
112 | Type = "StoredProcedure"
113 | };
114 | }
115 | }
116 |
117 | public override void BuildFeatures()
118 | {
119 | if (Database == null)
120 | return;
121 |
122 | if (this.GlobalSelection().Settings.AuditEntity != null)
123 | this.GlobalSelection().Settings.EntityInterfaceName = "IAuditEntity";
124 |
125 | Features = Database
126 | .DbObjects
127 | .Select(item => item.Schema)
128 | .Distinct()
129 | .Select(item => new ProjectFeature(item, GetDbObjectsBySchema(item), this))
130 | .ToList();
131 | }
132 |
133 | public override void Scaffold(IObjectDefinition objectDefinition, string outputDirectory, string subdirectory = "")
134 | {
135 | var codeBuilder = default(ICodeBuilder);
136 |
137 | var selection = objectDefinition.DbObject == null ? this.GlobalSelection() : this.GetSelection(objectDefinition.DbObject);
138 |
139 | if (objectDefinition is CSharpClassDefinition)
140 | {
141 | codeBuilder = new CSharpClassBuilder
142 | {
143 | OutputDirectory = outputDirectory,
144 | ForceOverwrite = selection.Settings.ForceOverwrite,
145 | ObjectDefinition = objectDefinition
146 | };
147 | }
148 | else if (objectDefinition is CSharpInterfaceDefinition)
149 | {
150 | codeBuilder = new CSharpInterfaceBuilder
151 | {
152 | OutputDirectory = outputDirectory,
153 | ForceOverwrite = selection.Settings.ForceOverwrite,
154 | ObjectDefinition = objectDefinition
155 | };
156 | }
157 |
158 | OnScaffoldingDefinition(new ScaffoldingDefinitionEventArgs(Logger, codeBuilder));
159 |
160 | codeBuilder.CreateFile(subdirectory: subdirectory);
161 |
162 | OnScaffoldedDefinition(new ScaffoldedDefinitionEventArgs(Logger, codeBuilder));
163 | }
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/EntityFrameworkCoreProjectDomainExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace CatFactory.EntityFrameworkCore
4 | {
5 | public static partial class EntityFrameworkCoreProjectDomainExtensions
6 | {
7 | public static string GetDomainDirectory(this EntityFrameworkCoreProject project)
8 | => Path.Combine(project.OutputDirectory);
9 |
10 | public static string GetDomainModelsDirectory(this EntityFrameworkCoreProject project)
11 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.Models);
12 |
13 | public static string GetDomainQueryModelsDirectory(this EntityFrameworkCoreProject project)
14 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.QueryModels);
15 |
16 | public static string GetDomainConfigurationsDirectory(this EntityFrameworkCoreProject project)
17 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.Configurations);
18 |
19 | public static string GetDomainConfigurationsDirectory(this EntityFrameworkCoreProject project, string schema)
20 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.Configurations, schema);
21 |
22 | public static string GetDomainModelsNamespace(this EntityFrameworkCoreProject project)
23 | => project.CodeNamingConvention.GetNamespace(project.Name, project.ProjectNamespaces.Models);
24 |
25 | public static string GetDomainModelsNamespace(this EntityFrameworkCoreProject project, string ns)
26 | => string.IsNullOrEmpty(ns) ? GetDomainModelsNamespace(project) : project.CodeNamingConvention.GetNamespace(project.Name, project.ProjectNamespaces.Models, ns);
27 |
28 | public static string GetDomainQueryModelsNamespace(this EntityFrameworkCoreProject project)
29 | => project.CodeNamingConvention.GetNamespace(project.Name, project.ProjectNamespaces.QueryModels);
30 |
31 | public static string GetDomainConfigurationsNamespace(this EntityFrameworkCoreProject project)
32 | => project.CodeNamingConvention.GetNamespace(project.Name, project.ProjectNamespaces.Configurations);
33 |
34 | public static string GetDomainConfigurationsNamespace(this EntityFrameworkCoreProject project, string ns)
35 | => string.IsNullOrEmpty(ns) ? GetDomainConfigurationsNamespace(project) : project.CodeNamingConvention.GetNamespace(project.Name, project.ProjectNamespaces.Configurations, ns);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/EntityFrameworkCoreProjectLayersExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace CatFactory.EntityFrameworkCore
4 | {
5 | public static class EntityFrameworkCoreProjectLayersExtensions
6 | {
7 | public static string GetEntityLayerNamespace(this EntityFrameworkCoreProject project)
8 | => string.Join(".", project.CodeNamingConvention.GetNamespace(project.Name), project.CodeNamingConvention.GetNamespace(project.ProjectNamespaces.EntityLayer));
9 |
10 | public static string GetEntityLayerNamespace(this EntityFrameworkCoreProject project, string ns)
11 | => string.IsNullOrEmpty(ns) ? GetEntityLayerNamespace(project) : string.Join(".", project.Name, project.ProjectNamespaces.EntityLayer, ns);
12 |
13 | public static string GetDataLayerNamespace(this EntityFrameworkCoreProject project)
14 | => string.Join(".", new string[] { project.CodeNamingConvention.GetNamespace(project.Name), project.ProjectNamespaces.DataLayer });
15 |
16 | public static string GetDataLayerConfigurationsNamespace(this EntityFrameworkCoreProject project)
17 | => string.Join(".", project.CodeNamingConvention.GetNamespace(project.Name), project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.Configurations);
18 |
19 | public static string GetDataLayerConfigurationsNamespace(this EntityFrameworkCoreProject project, string schema)
20 | => project.CodeNamingConvention.GetNamespace(project.Name, project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.Configurations, schema);
21 |
22 | public static string GetDataLayerContractsNamespace(this EntityFrameworkCoreProject project)
23 | => string.Join(".", project.CodeNamingConvention.GetNamespace(project.Name), project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.Contracts);
24 |
25 | public static string GetDataLayerDataContractsNamespace(this EntityFrameworkCoreProject project)
26 | => string.Join(".", project.CodeNamingConvention.GetNamespace(project.Name), project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.DataContracts);
27 |
28 | public static string GetDataLayerRepositoriesNamespace(this EntityFrameworkCoreProject project)
29 | => string.Join(".", project.CodeNamingConvention.GetNamespace(project.Name), project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.Repositories);
30 |
31 | public static string GetEntityLayerDirectory(this EntityFrameworkCoreProject project)
32 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.EntityLayer);
33 |
34 | public static string GetEntityLayerDirectory(this EntityFrameworkCoreProject project, string schema)
35 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.EntityLayer, schema);
36 |
37 | public static string GetDataLayerDirectory(this EntityFrameworkCoreProject project)
38 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.DataLayer);
39 |
40 | public static string GetDataLayerDirectory(this EntityFrameworkCoreProject project, string subdirectory)
41 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.DataLayer, subdirectory);
42 |
43 | public static string GetDataLayerConfigurationsDirectory(this EntityFrameworkCoreProject project)
44 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.Configurations);
45 |
46 | public static string GetDataLayerConfigurationsDirectory(this EntityFrameworkCoreProject project, string schema)
47 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.Configurations, schema);
48 |
49 | public static string GetDataLayerContractsDirectory(this EntityFrameworkCoreProject project)
50 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.Contracts);
51 |
52 | public static string GetDataLayerDataContractsDirectory(this EntityFrameworkCoreProject project)
53 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.DataContracts);
54 |
55 | public static string GetDataLayerRepositoriesDirectory(this EntityFrameworkCoreProject project)
56 | => Path.Combine(project.OutputDirectory, project.ProjectNamespaces.DataLayer, project.ProjectNamespaces.Repositories);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/EntityFrameworkCoreProjectNamespaces.cs:
--------------------------------------------------------------------------------
1 | namespace CatFactory.EntityFrameworkCore
2 | {
3 | public class EntityFrameworkCoreProjectNamespaces
4 | {
5 | public EntityFrameworkCoreProjectNamespaces()
6 | {
7 | Models = "Models";
8 | QueryModels = "QueryModels";
9 | EntityLayer = "EntityLayer";
10 | DataLayer = "DataLayer";
11 | Configurations = "Configurations";
12 | Contracts = "Contracts";
13 | DataContracts = "DataContracts";
14 | Repositories = "Repositories";
15 | ValueConversion = "ValueConversion";
16 | }
17 |
18 | public string Models { get; set; }
19 |
20 | public string QueryModels { get; set; }
21 |
22 | public string EntityLayer { get; set; }
23 |
24 | public string DataLayer { get; set; }
25 |
26 | public string Configurations { get; set; }
27 |
28 | public string Contracts { get; set; }
29 |
30 | public string DataContracts { get; set; }
31 |
32 | public string Repositories { get; set; }
33 |
34 | ///
35 | /// Project Microsoft.EntityFrameworkCore.Storage.ValueConversion classes and types can be found here;
36 | ///
37 | public string ValueConversion { get; set; }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/EntityFrameworkCoreProjectRepositoriesExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using CatFactory.CodeFactory.Scaffolding;
3 | using CatFactory.ObjectOrientedProgramming;
4 | using CatFactory.ObjectRelationalMapping;
5 | using CatFactory.ObjectRelationalMapping.Programmability;
6 |
7 | namespace CatFactory.EntityFrameworkCore
8 | {
9 | public static partial class EntityFrameworkCoreProjectExtensions
10 | {
11 | public static string GetParameterName(this EntityFrameworkCoreProject project, Column column)
12 | => project.CodeNamingConvention.GetParameterName(column.Name);
13 |
14 | public static string GetNavigationPropertyName(this EntityFrameworkCoreProject project, IDbObject dbObject)
15 | => string.Format("{0}List", project.CodeNamingConvention.GetClassName(dbObject.Name));
16 |
17 | public static string GetEntityName(this EntityFrameworkCoreProject project, IDbObject dbObject)
18 | => project.CodeNamingConvention.GetClassName(dbObject.Name);
19 |
20 | public static string GetEntityResultName(this EntityFrameworkCoreProject project, IDbObject dbObject)
21 | => string.Format("{0}Result", project.CodeNamingConvention.GetClassName(dbObject.Name));
22 |
23 | public static string GetPluralName(this EntityFrameworkCoreProject project, IDbObject dbObject)
24 | => project.NamingService.Pluralize(project.GetEntityName(dbObject));
25 |
26 | public static string GetDbContextName(this EntityFrameworkCoreProject project, Database database)
27 | => project.CodeNamingConvention.GetClassName(string.Format("{0}DbContext", database.Name));
28 |
29 | public static string GetDbSetPropertyName(this EntityFrameworkCoreProject project, IDbObject dbObject, bool pluralize)
30 | => pluralize ? project.NamingService.Pluralize(project.GetEntityName(dbObject)) : project.GetEntityName(dbObject);
31 |
32 | public static string GetFullDbSetPropertyName(this EntityFrameworkCoreProject project, IDbObject dbObject)
33 | => project.NamingService.Pluralize(string.Concat(project.CodeNamingConvention.GetNamespace(dbObject.Schema), project.GetEntityName(dbObject)));
34 |
35 | public static string GetEntityConfigurationName(this EntityFrameworkCoreProject project, IDbObject dbObject)
36 | => string.Format("{0}Configuration", project.GetEntityName(dbObject));
37 |
38 | public static string GetFullEntityConfigurationName(this EntityFrameworkCoreProject project, IDbObject dbObject)
39 | => project.CodeNamingConvention.GetNamespace(project.ProjectNamespaces.Configurations, dbObject.Schema, string.Format("{0}Configuration", project.GetEntityName(dbObject)));
40 |
41 | public static string GetFullEntityName(this EntityFrameworkCoreProject project, IDbObject dbObject)
42 | => string.Join(".", project.CodeNamingConvention.GetNamespace(project.ProjectNamespaces.EntityLayer), project.CodeNamingConvention.GetClassName(dbObject.Schema), project.CodeNamingConvention.GetClassName(dbObject.Name));
43 |
44 | public static string GetQueryModelName(this EntityFrameworkCoreProject project, IDbObject dbObject)
45 | => string.Format("{0}QueryModel", project.CodeNamingConvention.GetClassName(dbObject.Name));
46 |
47 | public static string GetDataContractName(this EntityFrameworkCoreProject project, IDbObject dbObject)
48 | => string.Format("{0}Dto", project.CodeNamingConvention.GetClassName(dbObject.Name));
49 |
50 | public static string GetGetAllExtensionMethodName(this EntityFrameworkCoreProject project, IDbObject dbObject)
51 | => string.Format("Get{0}", project.GetPluralName(dbObject));
52 |
53 | public static string GetGetAllRepositoryMethodName(this EntityFrameworkCoreProject project, IDbObject dbObject)
54 | => string.Format("Get{0}", project.GetPluralName(dbObject));
55 |
56 | public static string GetGetRepositoryMethodName(this EntityFrameworkCoreProject project, IDbObject dbObject)
57 | => string.Format("Get{0}Async", project.GetEntityName(dbObject));
58 |
59 | public static string GetGetByUniqueRepositoryMethodName(this EntityFrameworkCoreProject project, ITable table, Unique unique)
60 | => string.Format("Get{0}By{1}Async", project.GetEntityName(table), string.Join("And", unique.Key.Select(item => project.CodeNamingConvention.GetPropertyName(item))));
61 |
62 | public static string GetAddRepositoryMethodName(this EntityFrameworkCoreProject project, ITable table)
63 | => string.Format("Add{0}Async", project.GetEntityName(table));
64 |
65 | public static string GetUpdateRepositoryMethodName(this EntityFrameworkCoreProject project, ITable table)
66 | => string.Format("Update{0}Async", project.GetEntityName(table));
67 |
68 | public static string GetRemoveRepositoryMethodName(this EntityFrameworkCoreProject project, ITable table)
69 | => string.Format("Remove{0}Async", project.GetEntityName(table));
70 |
71 | public static string GetScalarFunctionMethodName(this EntityFrameworkCoreProject project, ScalarFunction scalarFunction)
72 | => string.Format("{0}{1}", project.CodeNamingConvention.GetClassName(scalarFunction.Schema), project.CodeNamingConvention.GetClassName(scalarFunction.Name));
73 |
74 | public static bool HasSameEnclosingName(this ITable table)
75 | => table.Schema == table.Name;
76 |
77 | public static PropertyDefinition GetChildNavigationProperty(this EntityFrameworkCoreProject project, ProjectSelection projectSelection, ITable table, ForeignKey foreignKey)
78 | {
79 | var propertyType = string.Format("{0}<{1}>", projectSelection.Settings.NavigationPropertyEnumerableType, project.GetEntityName(table));
80 |
81 | return new PropertyDefinition(propertyType, project.GetNavigationPropertyName(table))
82 | {
83 | AccessModifier = AccessModifier.Public,
84 | IsVirtual = projectSelection.Settings.DeclareNavigationPropertiesAsVirtual
85 | };
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/EntityFrameworkCoreProjectSelectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using CatFactory.CodeFactory.Scaffolding;
4 | using CatFactory.ObjectRelationalMapping;
5 |
6 | namespace CatFactory.EntityFrameworkCore
7 | {
8 | public static class EntityFrameworkCoreProjectSelectionExtensions
9 | {
10 | public static ProjectSelection GetSelection(this EntityFrameworkCoreProject project, IDbObject dbObj)
11 | {
12 | // Sales.OrderHeader
13 | var selectionForFullName = project.Selections.FirstOrDefault(item => item.Pattern == dbObj.FullName);
14 |
15 | if (selectionForFullName != null)
16 | return selectionForFullName;
17 |
18 | // Sales.*
19 | var selectionForSchema = project.Selections.FirstOrDefault(item => item.Pattern == string.Format("{0}.*", dbObj.Schema));
20 |
21 | if (selectionForSchema != null)
22 | return selectionForSchema;
23 |
24 | // *.OrderHeader
25 | var selectionForName = project.Selections.FirstOrDefault(item => item.Pattern == string.Format("*.{0}", dbObj.Name));
26 |
27 | if (selectionForName != null)
28 | return selectionForName;
29 |
30 | return project.GlobalSelection();
31 | }
32 |
33 | public static EntityFrameworkCoreProject GlobalSelection(this EntityFrameworkCoreProject project, Action action = null)
34 | {
35 | var settings = new EntityFrameworkCoreProjectSettings();
36 |
37 | var selection = project.Selections.FirstOrDefault(item => item.IsGlobal);
38 |
39 | if (selection == null)
40 | {
41 | selection = new ProjectSelection
42 | {
43 | Pattern = ProjectSelection.GlobalPattern,
44 | Settings = settings
45 | };
46 |
47 | project.Selections.Add(selection);
48 | }
49 | else
50 | {
51 | settings = selection.Settings;
52 | }
53 |
54 | action?.Invoke(settings);
55 |
56 | return project;
57 | }
58 |
59 | public static ProjectSelection GlobalSelection(this EntityFrameworkCoreProject project)
60 | => project.Selections.FirstOrDefault(item => item.IsGlobal);
61 |
62 | public static EntityFrameworkCoreProject Selection(this EntityFrameworkCoreProject project, string pattern, Action action = null)
63 | {
64 | var selection = project.Selections.FirstOrDefault(item => item.Pattern == pattern);
65 |
66 | if (selection == null)
67 | {
68 | var globalSettings = project.GlobalSelection().Settings;
69 |
70 | selection = new ProjectSelection
71 | {
72 | Pattern = pattern,
73 | Settings = new EntityFrameworkCoreProjectSettings
74 | {
75 | ForceOverwrite = globalSettings.ForceOverwrite,
76 | SimplifyDataTypes = globalSettings.SimplifyDataTypes,
77 | UseAutomaticPropertiesForEntities = globalSettings.UseAutomaticPropertiesForEntities,
78 | EnableDataBindings = globalSettings.EnableDataBindings,
79 | UseDataAnnotations = globalSettings.UseDataAnnotations,
80 | DeclareNavigationProperties = globalSettings.DeclareNavigationProperties,
81 | DeclareNavigationPropertiesAsVirtual = globalSettings.DeclareNavigationPropertiesAsVirtual,
82 | NavigationPropertyEnumerableNamespace = globalSettings.NavigationPropertyEnumerableNamespace,
83 | NavigationPropertyEnumerableType = globalSettings.NavigationPropertyEnumerableType,
84 | ConcurrencyToken = globalSettings.ConcurrencyToken,
85 | EntityInterfaceName = globalSettings.EntityInterfaceName,
86 | AuditEntity = globalSettings.AuditEntity == null ? null : new AuditEntity
87 | {
88 | CreationUserColumnName = globalSettings.AuditEntity.CreationUserColumnName,
89 | CreationDateTimeColumnName = globalSettings.AuditEntity.CreationDateTimeColumnName,
90 | LastUpdateUserColumnName = globalSettings.AuditEntity.LastUpdateUserColumnName,
91 | LastUpdateDateTimeColumnName = globalSettings.AuditEntity.LastUpdateDateTimeColumnName
92 | },
93 | EntitiesWithDataContracts = globalSettings.EntitiesWithDataContracts,
94 | BackingFields = globalSettings.BackingFields.Select(item => item).ToList(),
95 | InsertExclusions = globalSettings.InsertExclusions.Select(item => item).ToList(),
96 | UpdateExclusions = globalSettings.UpdateExclusions.Select(item => item).ToList(),
97 | AddConfigurationForForeignKeysInFluentAPI = globalSettings.AddConfigurationForForeignKeysInFluentAPI,
98 | AddConfigurationForUniquesInFluentAPI = globalSettings.AddConfigurationForUniquesInFluentAPI,
99 | AddConfigurationForChecksInFluentAPI = globalSettings.AddConfigurationForChecksInFluentAPI,
100 | AddConfigurationForDefaultsInFluentAPI = globalSettings.AddConfigurationForDefaultsInFluentAPI,
101 | }
102 | };
103 |
104 | project.Selections.Add(selection);
105 | }
106 |
107 | action?.Invoke(selection.Settings);
108 |
109 | return project;
110 | }
111 |
112 | [Obsolete("Use Selection method.")]
113 | public static EntityFrameworkCoreProject Select(this EntityFrameworkCoreProject project, string pattern, Action action = null)
114 | => project.Selection(pattern, action);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/EntityFrameworkCoreProjectSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using CatFactory.CodeFactory.Scaffolding;
5 | using CatFactory.Diagnostics;
6 |
7 | namespace CatFactory.EntityFrameworkCore
8 | {
9 | public class EntityFrameworkCoreProjectSettings : IProjectSettings
10 | {
11 | [DebuggerBrowsable(DebuggerBrowsableState.Never)]
12 | private List m_backingFields;
13 |
14 | [DebuggerBrowsable(DebuggerBrowsableState.Never)]
15 | private List m_insertExclusions;
16 |
17 | [DebuggerBrowsable(DebuggerBrowsableState.Never)]
18 | private List m_updateExclusions;
19 |
20 | public EntityFrameworkCoreProjectSettings()
21 | {
22 | SimplifyDataTypes = true;
23 | UseAutomaticPropertiesForEntities = true;
24 | UseMefForEntitiesMapping = true;
25 | DeclareDbSetPropertiesInDbContext = true;
26 | NavigationPropertyEnumerableNamespace = "System.Collections.ObjectModel";
27 | NavigationPropertyEnumerableType = "Collection";
28 | EntityInterfaceName = "IEntity";
29 | AddConfigurationForUniquesInFluentAPI = true;
30 | AddConfigurationForDefaultsInFluentAPI = true;
31 | }
32 |
33 | // todo: Add implementation
34 | public ValidationResult Validate()
35 | {
36 | throw new NotImplementedException();
37 | }
38 |
39 | public bool ForceOverwrite { get; set; }
40 |
41 | public bool SimplifyDataTypes { get; set; }
42 |
43 | public bool UseAutomaticPropertiesForEntities { get; set; }
44 |
45 | public bool EnableDataBindings { get; set; }
46 |
47 | public bool UseDataAnnotations { get; set; }
48 |
49 | [Obsolete("Temporarily disabled")]
50 | public bool UseMefForEntitiesMapping { get; set; }
51 |
52 | public bool DeclareDbSetPropertiesInDbContext { get; }
53 |
54 | public bool PluralizeDbSetPropertyNames { get; set; }
55 |
56 | public bool DeclareNavigationProperties { get; set; }
57 |
58 | public bool DeclareNavigationPropertiesAsVirtual { get; set; }
59 |
60 | public string NavigationPropertyEnumerableNamespace { get; set; }
61 |
62 | public string NavigationPropertyEnumerableType { get; set; }
63 |
64 | public string ConcurrencyToken { get; set; }
65 |
66 | public bool HasConcurrencyToken
67 | => !string.IsNullOrEmpty(ConcurrencyToken);
68 |
69 | public string RowVersion { get; set; }
70 |
71 | public bool HasRowVersion
72 | => !string.IsNullOrEmpty(RowVersion);
73 |
74 | public string EntityInterfaceName { get; set; }
75 |
76 | public AuditEntity AuditEntity { get; set; }
77 |
78 | public bool EntitiesWithDataContracts { get; set; }
79 |
80 | public bool AddConfigurationForUniquesInFluentAPI { get; set; }
81 |
82 | public bool AddConfigurationForChecksInFluentAPI { get; set; }
83 |
84 | public bool AddConfigurationForDefaultsInFluentAPI { get; set; }
85 |
86 | public bool AddConfigurationForForeignKeysInFluentAPI { get; set; }
87 |
88 | public List BackingFields
89 | {
90 | get => m_backingFields ??= new List();
91 | set => m_backingFields = value;
92 | }
93 |
94 | public List InsertExclusions
95 | {
96 | get => m_insertExclusions ??= new List();
97 | set => m_insertExclusions = value;
98 | }
99 |
100 | public List UpdateExclusions
101 | {
102 | get => m_updateExclusions ??= new List();
103 | set => m_updateExclusions = value;
104 | }
105 |
106 | public bool UseApplyConfigurationsFromAssemblyMethod { get; set; }
107 |
108 | ///
109 | /// When true the Database DefaultSchema is also used as a namespace and folder
110 | ///
111 | public bool DefaultSchemaAsSubdirectory { get; set; }
112 |
113 | ///
114 | /// Navigation Property Enumerable Interface Type
115 | /// Typically ICollection
116 | ///
117 | public string NavigationPropertyEnumerableInterfaceType { get; set; }
118 |
119 | ///
120 | /// DefaultSchemaAsNamespace
121 | /// default = false;
122 | /// When true use DefaultSchema (dbo) as namespace and class
123 | ///
124 | public bool DefaultSchemaAsNamespace { get; set; }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/EntityFrameworkCoreVersion.cs:
--------------------------------------------------------------------------------
1 | namespace CatFactory.EntityFrameworkCore
2 | {
3 | public enum EntityFrameworkCoreVersion : short
4 | {
5 | Version_2_0 = 20,
6 | Version_2_1 = 21,
7 | Version_2_2 = 22,
8 | Version_3_0 = 30,
9 | Version_3_1 = 31,
10 | Version_5_0 = 50,
11 | Version_6_0 = 60,
12 | Version_7_0 = 70
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/EntityLayerExtensions.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.EntityFrameworkCore.Definitions.Extensions;
2 | using CatFactory.ObjectRelationalMapping;
3 |
4 | namespace CatFactory.EntityFrameworkCore
5 | {
6 | public static class EntityLayerExtensions
7 | {
8 | public static EntityFrameworkCoreProject ScaffoldEntityLayer(this EntityFrameworkCoreProject project)
9 | {
10 | ScaffoldEntityInterface(project);
11 | ScaffoldEntities(project);
12 |
13 | return project;
14 | }
15 |
16 | private static void ScaffoldEntityInterface(EntityFrameworkCoreProject project)
17 | {
18 | project.Scaffold(project.GetEntityInterfaceDefinition(false), project.GetEntityLayerDirectory());
19 |
20 | if (project.GlobalSelection().Settings.AuditEntity != null)
21 | project.Scaffold(project.GetAuditEntityInterfaceDefinition(false), project.GetEntityLayerDirectory());
22 | }
23 |
24 | private static EntityFrameworkCoreProject ScaffoldEntities(this EntityFrameworkCoreProject project)
25 | {
26 | foreach (var table in project.Database.Tables)
27 | {
28 | var selection = project.GetSelection(table);
29 |
30 | var definition = project.GetEntityClassDefinition(table, false);
31 |
32 | if (selection.Settings.UseDataAnnotations)
33 | definition.AddDataAnnotations(table, project);
34 |
35 | project.Scaffold(definition, project.GetEntityLayerDirectory(), project.Database.HasDefaultSchema(table) ? "" : table.Schema);
36 | }
37 |
38 | foreach (var view in project.Database.Views)
39 | {
40 | var selection = project.GetSelection(view);
41 |
42 | var definition = project.GetEntityClassDefinition(view, project.Database.HasDefaultSchema(view) ? project.GetEntityLayerNamespace() : project.GetEntityLayerNamespace(view.Schema));
43 |
44 | if (selection.Settings.UseDataAnnotations)
45 | definition.AddDataAnnotations(view, project);
46 |
47 | project.Scaffold(definition, project.GetEntityLayerDirectory(), project.Database.HasDefaultSchema(view) ? "" : view.Schema);
48 | }
49 |
50 | // todo: Review this scaffolding
51 |
52 | //foreach (var tableFunction in project.Database.TableFunctions)
53 | //{
54 | // var selection = project.GetSelection(tableFunction);
55 |
56 | // var definition = project.GetEntityClassDefinition(tableFunction);
57 |
58 | // project.Scaffold(definition, project.GetEntityLayerDirectory(), project.Database.HasDefaultSchema(tableFunction) ? "" : tableFunction.Schema);
59 | //}
60 |
61 | // todo: Review this scaffolding
62 |
63 | //foreach (var storedProcedure in project.Database.StoredProcedures)
64 | //{
65 | // var selection = project.GetSelection(storedProcedure);
66 |
67 | // var definition = project.GetEntityClassDefinition(storedProcedure);
68 |
69 | // project.Scaffold(definition, project.GetEntityLayerDirectory(), project.Database.HasDefaultSchema(storedProcedure) ? "" : storedProcedure.Schema);
70 | //}
71 |
72 | return project;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/IDotNetClassDefinitionExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using CatFactory.NetCore;
3 | using CatFactory.NetCore.ObjectOrientedProgramming;
4 | using CatFactory.ObjectOrientedProgramming;
5 | using CatFactory.ObjectRelationalMapping;
6 |
7 | namespace CatFactory.EntityFrameworkCore
8 | {
9 | public static class IDotNetClassDefinitionExtensions
10 | {
11 | public static void AddDataAnnotations(this IDotNetClassDefinition classDefinition, ITable table, EntityFrameworkCoreProject project)
12 | {
13 | classDefinition.Attributes.Add(new MetadataAttribute("Table", string.Format("\"{0}\"", table.Name))
14 | {
15 | Sets =
16 | {
17 | new MetadataAttributeSet("Schema", string.Format("\"{0}\"", table.Schema))
18 | }
19 | });
20 |
21 | var selection = project.GetSelection(table);
22 |
23 | for (var i = 0; i < table.Columns.Count; i++)
24 | {
25 | var column = table.Columns[i];
26 |
27 | foreach (var property in classDefinition.Properties)
28 | {
29 | if (project.GetPropertyName(table, column) != property.Name)
30 | continue;
31 |
32 | if (table.Identity?.Name == column.Name)
33 | property.Attributes.Add(new MetadataAttribute("DatabaseGenerated", "DatabaseGeneratedOption.Identity"));
34 |
35 | if (table.PrimaryKey != null && table.PrimaryKey.Key.Contains(column.Name))
36 | property.Attributes.Add(new MetadataAttribute("Key"));
37 |
38 | if (property.Name == column.Name)
39 | property.Attributes.Add(new MetadataAttribute("Column"));
40 | else
41 | property.Attributes.Add(new MetadataAttribute("Column", string.Format("\"{0}\"", column.Name)));
42 |
43 | if (!column.Nullable && table.Identity != null && table.Identity.Name != column.Name)
44 | property.Attributes.Add(new MetadataAttribute("Required"));
45 |
46 | if (project.Database.ColumnIsString(column) && column.Length > 0)
47 | property.Attributes.Add(new MetadataAttribute("StringLength", column.Length.ToString()));
48 |
49 | if (!string.IsNullOrEmpty(selection.Settings.ConcurrencyToken) && selection.Settings.ConcurrencyToken == column.Name)
50 | property.Attributes.Add(new MetadataAttribute("Timestamp"));
51 | }
52 | }
53 | }
54 |
55 | public static void AddDataAnnotations(this IDotNetClassDefinition classDefinition, IView view, EntityFrameworkCoreProject project)
56 | {
57 | classDefinition.Attributes.Add(new MetadataAttribute("Table", string.Format("\"{0}\"", view.Name))
58 | {
59 | Sets =
60 | {
61 | new MetadataAttributeSet("Schema", string.Format("\"{0}\"", view.Schema))
62 | }
63 | });
64 |
65 | var primaryKeys = project
66 | .Database
67 | .Tables
68 | .Where(item => item.PrimaryKey != null)
69 | .Select(item => item.GetColumnsFromConstraint(item.PrimaryKey).Select(column => column.Name).First())
70 | .ToList();
71 |
72 | var result = view.Columns
73 | .Where(item => primaryKeys.Contains(item.Name))
74 | .ToList();
75 |
76 | for (var i = 0; i < view.Columns.Count; i++)
77 | {
78 | var column = view.Columns[i];
79 |
80 | foreach (var property in classDefinition.Properties)
81 | {
82 | if (project.GetPropertyName(view, column) != property.Name)
83 | continue;
84 |
85 | if (property.Name == column.Name)
86 | {
87 | property.Attributes.Add(new MetadataAttribute("Column")
88 | {
89 | Sets = { new MetadataAttributeSet("Order", (i + 1).ToString()) }
90 | });
91 | }
92 | else
93 | {
94 | property.Attributes.Add(new MetadataAttribute("Column", string.Format("\"{0}\"", column.Name))
95 | {
96 | Sets = { new MetadataAttributeSet("Order", (i + 1).ToString()) }
97 | });
98 | }
99 |
100 | if (!column.Nullable && primaryKeys.Contains(column.Name))
101 | property.Attributes.Add(new MetadataAttribute("Key"));
102 |
103 | if (!column.Nullable)
104 | property.Attributes.Add(new MetadataAttribute("Required"));
105 | }
106 | }
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/CatFactory.EntityFrameworkCore/ProjectFeatureExtensions.cs:
--------------------------------------------------------------------------------
1 | using CatFactory.CodeFactory.Scaffolding;
2 |
3 | namespace CatFactory.EntityFrameworkCore
4 | {
5 | public static class ProjectFeatureExtensions
6 | {
7 | public static EntityFrameworkCoreProject GetEntityFrameworkCoreProject(this ProjectFeature projectFeature)
8 | => projectFeature.Project as EntityFrameworkCoreProject;
9 |
10 | public static string GetRepositoryInterfaceName(this ProjectFeature projectFeature)
11 | => string.Format("{0}Repository",
12 | projectFeature.GetEntityFrameworkCoreProject().CodeNamingConvention.GetInterfaceName(projectFeature.Name)
13 | );
14 |
15 | public static string GetRepositoryClassName(this ProjectFeature projectFeature)
16 | => string.Format("{0}Repository",
17 | projectFeature.GetEntityFrameworkCoreProject().CodeNamingConvention.GetClassName(projectFeature.Name)
18 | );
19 |
20 | public static string GetQueryExtensionsClassName(this ProjectFeature projectFeature)
21 | => string.Format("{0}{1}QueryExtensions",
22 | projectFeature.GetEntityFrameworkCoreProject().GetDbContextName(projectFeature.Project.Database),
23 | projectFeature.Project.CodeNamingConvention.GetClassName(projectFeature.Name)
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 H. Herzl
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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CatFactory.EntityFrameworkCore ==^^==
2 |
3 | This is the **CatFactory** package for *Entity Framework Core*.
4 |
5 | ## What Is CatFactory?
6 |
7 | **CatFactory** is a scaffolding engine for .NET Core built with C#.
8 |
9 | ## How does it Works?
10 |
11 | The concept behind **CatFactory** is to import an existing database from *SQL Server* instance and then to scaffold a target technology.
12 |
13 | We can also replace the database from *SQL Server* instance with an in-memory database.
14 |
15 | The flow to import an existing database is:
16 |
17 | 1. Create Database Factory
18 | 2. Import Database
19 | 3. Create instance of Project (Entity Framework Core, Dapper, etc)
20 | 4. Build Features (One feature per schema)
21 | 5. Scaffold objects, these methods read all objects from database and create instances for code builders
22 |
23 | ## Donation
24 |
25 | You can make a donation via PayPal using this link: [](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=XB49JFNSMGY6U&item_name=CatFactory¤cy_code=USD&source=url)
26 |
27 | Thanks for your help! ==^^==
28 |
29 | ## Code Snippet
30 |
31 | You can check the [`Wiki`](https://github.com/hherzl/CatFactory.EntityFrameworkCore/wiki) to get code snippets for this package.
32 |
33 | Also these technologies are supported:
34 |
35 | + [`ASP.NET Core`](https://github.com/hherzl/CatFactory.AspNetCore)
36 | + [`Dapper`](https://github.com/hherzl/CatFactory.Dapper)
37 |
38 | ## Roadmap
39 |
40 | There will be a lot of improvements for **CatFactory** on road:
41 |
42 | * Scaffolding Services Layer
43 | * Dapper Integration for ASP.NET Core
44 | * MD files
45 | * Scaffolding C# Client for ASP.NET Web API
46 | * Scaffolding Unit Tests for ASP.NET Core
47 | * Scaffolding Integration Tests for ASP.NET Core
48 | * Scaffolding Angular
49 |
50 | ## Concepts behind CatFactory
51 |
52 | Database Type
53 | Project Selection
54 | Event Handlers to Scaffold
55 | Database Object Model
56 | Import Bag
57 |
58 | Read more on: [`Concepts behind CatFactory`](https://github.com/hherzl/CatFactory/wiki/Concepts-behind-CatFactory)
59 |
60 | ## Packages
61 |
62 | CatFactory
63 | CatFactory.SqlServer
64 | CatFactory.PostgreSql
65 | CatFactory.NetCore
66 | CatFactory.EntityFrameworkCore
67 | CatFactory.AspNetCore
68 | CatFactory.Dapper
69 | CatFactory.TypeScript
70 |
71 | Read more on: [`Packages Features Chart`](https://github.com/hherzl/CatFactory/wiki/Packages-Features-Chart)
72 |
73 | ## Quick Starts
74 |
75 | [`Scaffolding Dapper with CatFactory`](https://www.codeproject.com/Articles/1213355/Scaffolding-Dapper-with-CatFactory)
76 |
77 | [`Scaffolding View Models with CatFactory`](https://www.codeproject.com/Tips/1164636/Scaffolding-View-Models-with-CatFactory)
78 |
79 | [`Scaffolding Entity Framework Core 2 with CatFactory`](https://www.codeproject.com/Articles/1160615/Scaffolding-Entity-Framework-Core-with-CatFactory)
80 |
81 | [`Scaffolding ASP.NET Core 2 with CatFactory`](https://www.codeproject.com/Tips/1229909/Scaffolding-ASP-NET-Core-with-CatFactory)
82 |
83 | [`Scaffolding TypeScript with CatFactory`](https://www.codeproject.com/Tips/1166380/Scaffolding-TypeScript-with-CatFactory)
84 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | cls
2 | set initialPath=%cd%
3 | set srcPath=%cd%\CatFactory.EntityFrameworkCore
4 | set testsPath=%cd%\CatFactory.EntityFrameworkCore.Tests
5 | set outputBasePath=C:\Temp\CatFactory.EntityFrameworkCore
6 | cd %srcPath%
7 | dotnet build
8 | cd %testsPath%
9 | dotnet test
10 | cd %outputBasePath%\OnlineStore.Core.Tests
11 | dotnet test
12 | cd %outputBasePath%\OnlineStore.Domain.Tests
13 | dotnet test
14 | cd %outputBasePath%\OnlineStoreWithDataAnnotations.Core.Tests
15 | dotnet test
16 | cd %outputBasePath%\Northwind.Core.Tests
17 | dotnet test
18 | cd %outputBasePath%\AdventureWorks.Core.Tests
19 | dotnet test
20 | cd %srcPath%
21 | dotnet pack
22 | cd %initialPath%
23 | pause
24 |
--------------------------------------------------------------------------------