├── .gitattributes ├── .gitignore ├── Digipolis.DataAccess.sln ├── LICENSE.txt ├── changelog.md ├── gulpfile.js ├── nuget.config ├── package.json ├── readme.md ├── samples └── DataAccess.SampleApp │ ├── .bowerrc │ ├── Controllers │ └── HomeController.cs │ ├── DataAccess.SampleApp.csproj │ ├── Entities │ ├── Appartment.cs │ ├── Building.cs │ └── Room.cs │ ├── Migrations │ ├── 20171124112019_initial.Designer.cs │ ├── 20171124112019_initial.cs │ ├── 20171124112404_lowercasedtablesandfieldswithcolumnattribute.Designer.cs │ ├── 20171124112404_lowercasedtablesandfieldswithcolumnattribute.cs │ └── SampleAppContextModelSnapshot.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── SampleAppContext.cs │ ├── Startup.cs │ ├── Views │ ├── Home │ │ ├── Index.cshtml │ │ └── Seed.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml │ ├── _config │ └── dataaccess.json │ ├── appsettings.json │ ├── bower.json │ ├── bundleconfig.json │ ├── web.config │ └── wwwroot │ ├── _references.js │ ├── css │ └── site.min.css │ ├── favicon.ico │ ├── images │ ├── banner1.svg │ ├── banner2.svg │ ├── banner3.svg │ └── banner4.svg │ ├── js │ ├── site.js │ └── site.min.js │ └── lib │ ├── bootstrap │ ├── .bower.json │ ├── LICENSE │ └── dist │ │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ │ └── js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── npm.js │ ├── jquery-validation-unobtrusive │ ├── .bower.json │ ├── jquery.validate.unobtrusive.js │ └── jquery.validate.unobtrusive.min.js │ ├── jquery-validation │ ├── .bower.json │ ├── LICENSE.md │ └── dist │ │ ├── additional-methods.js │ │ ├── additional-methods.min.js │ │ ├── jquery.validate.js │ │ └── jquery.validate.min.js │ └── jquery │ ├── .bower.json │ ├── LICENSE.txt │ └── dist │ ├── jquery.js │ ├── jquery.min.js │ └── jquery.min.map ├── src └── Digipolis.DataAccess │ ├── Attributes │ └── HasPrecisionAttribute.cs │ ├── Context │ ├── EntityContextBase.cs │ ├── IEntityContext.cs │ └── ModelBuilderExtensions.cs │ ├── DataAccess.cs │ ├── Digipolis.DataAccess.csproj │ ├── Entities │ └── EntityBase.cs │ ├── Exceptions │ ├── EntityNotFoundException.cs │ └── RepositoryNotFoundException.cs │ ├── Options │ ├── ConnectionString.cs │ └── Defaults.cs │ ├── Paging │ ├── DataPage.cs │ ├── DataPager.cs │ └── IDataPager.cs │ ├── Properties │ ├── AssemblyInfo.cs │ ├── GlobalSuppressions.cs │ └── debugSettings.json │ ├── Query │ ├── Filter.cs │ ├── Includes.cs │ ├── OrderBy.cs │ └── ReplaceExpressionVisitor.cs │ ├── Repositories │ ├── EntityRepositoryBase.cs │ ├── GenericEntityRepository.cs │ ├── IRepository.cs │ ├── IRepositoryInjection.cs │ └── RepositoryBase.cs │ ├── Startup │ └── ServiceCollectionExtensions.cs │ └── Uow │ ├── IUnitOfWork.cs │ ├── IUnitOfWorkBase.cs │ ├── IUowProvider.cs │ ├── UnitOfWork.cs │ ├── UnitOfWorkBase.cs │ └── UowProvider.cs └── test └── Digipolis.DataAccess.UnitTests ├── Digipolis.DataAccess.UnitTests.csproj ├── Exceptions └── EntityNotFoundExceptionTests │ └── InstantiationTests.cs ├── Options └── ConnectionStringTests │ ├── InstantiationTests.cs │ └── ToStringTests.cs ├── Paging └── DataPagerTests.cs ├── Properties └── AssemblyInfo.cs ├── Repositories └── GenericEntityRepositoryTests.cs ├── Startup └── ServiceCollectionExtensionsTests │ └── AddDataAccessOptionsTests.cs ├── Uow └── UowProviderTests.cs ├── _TestData ├── dbconfig1.json └── dbconfig2.json └── _TestObjects ├── Foo.cs ├── FooRepository.cs ├── IFooRepository.cs ├── InMemoryContext.cs └── TestContext.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | node_modules/ 5 | bower_components/ 6 | 7 | .vs/ 8 | .vscode/ 9 | .cr/ 10 | 11 | # site css 12 | site.css 13 | site.css.map 14 | 15 | # User-specific files 16 | *.suo 17 | *.user 18 | *.sln.docstates 19 | *.lock.json 20 | 21 | # Build results 22 | [Dd]ebug/ 23 | [Dd]ebugPublic/ 24 | [Rr]elease/ 25 | x64/ 26 | build/ 27 | bld/ 28 | [Bb]in/ 29 | [Oo]bj/ 30 | 31 | # Roslyn cache directories 32 | *.ide/ 33 | 34 | # MSTest test Results 35 | [Tt]est[Rr]esult*/ 36 | [Bb]uild[Ll]og.* 37 | 38 | #NUNIT 39 | *.VisualState.xml 40 | TestResult.xml 41 | 42 | # Build Results of an ATL Project 43 | [Dd]ebugPS/ 44 | [Rr]eleasePS/ 45 | dlldata.c 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 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | 88 | # TFS 2012 Local Workspace 89 | $tf/ 90 | 91 | # Guidance Automation Toolkit 92 | *.gpState 93 | 94 | # ReSharper is a .NET coding add-in 95 | _ReSharper*/ 96 | *.[Rr]e[Ss]harper 97 | *.DotSettings.user 98 | 99 | # JustCode is a .NET coding addin-in 100 | .JustCode 101 | 102 | # TeamCity is a build add-in 103 | _TeamCity* 104 | 105 | # DotCover is a Code Coverage Tool 106 | *.dotCover 107 | 108 | # NCrunch 109 | _NCrunch_* 110 | .*crunch*.local.xml 111 | 112 | # MightyMoose 113 | *.mm.* 114 | AutoTest.Net/ 115 | 116 | # Web workbench (sass) 117 | .sass-cache/ 118 | 119 | # Installshield output folder 120 | [Ee]xpress/ 121 | 122 | # DocProject is a documentation generator add-in 123 | DocProject/buildhelp/ 124 | DocProject/Help/*.HxT 125 | DocProject/Help/*.HxC 126 | DocProject/Help/*.hhc 127 | DocProject/Help/*.hhk 128 | DocProject/Help/*.hhp 129 | DocProject/Help/Html2 130 | DocProject/Help/html 131 | 132 | # Click-Once directory 133 | publish/ 134 | 135 | # Publish Web Output 136 | *.[Pp]ublish.xml 137 | *.azurePubxml 138 | ## TODO: Comment the next line if you want to checkin your 139 | ## web deploy settings but do note that will include unencrypted 140 | ## passwords 141 | #*.pubxml 142 | 143 | # NuGet Packages Directory 144 | packages/* 145 | ## TODO: If the tool you use requires repositories.config 146 | ## uncomment the next line 147 | #!packages/repositories.config 148 | 149 | # Enable "build/" folder in the NuGet Packages folder since 150 | # NuGet packages use it for MSBuild targets. 151 | # This line needs to be after the ignore of the build folder 152 | # (and the packages folder if the line above has been uncommented) 153 | !packages/build/ 154 | 155 | # Windows Azure Build Output 156 | csx/ 157 | *.build.csdef 158 | 159 | # Windows Store app package directory 160 | AppPackages/ 161 | 162 | # Others 163 | sql/ 164 | *.Cache 165 | ClientBin/ 166 | [Ss]tyle[Cc]op.* 167 | ~$* 168 | *~ 169 | *.dbmdl 170 | *.dbproj.schemaview 171 | *.pfx 172 | *.publishsettings 173 | 174 | # RIA/Silverlight projects 175 | Generated_Code/ 176 | 177 | # Backup & report files from converting an old project file 178 | # to a newer Visual Studio version. Backup files are not needed, 179 | # because we have git ;-) 180 | _UpgradeReport_Files/ 181 | Backup*/ 182 | UpgradeLog*.XML 183 | UpgradeLog*.htm 184 | 185 | # SQL Server files 186 | *.mdf 187 | *.ldf 188 | 189 | # Business Intelligence projects 190 | *.rdl.data 191 | *.bim.layout 192 | *.bim_*.settings 193 | 194 | # Microsoft Fakes 195 | FakesAssemblies/ 196 | 197 | # LightSwitch generated files 198 | GeneratedArtifacts/ 199 | _Pvt_Extensions/ 200 | ModelManifest.xml 201 | 202 | _SpecRunner.html -------------------------------------------------------------------------------- /Digipolis.DataAccess.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.6 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3D5D0B67-478E-4734-83F5-9D9F612E5661}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{263D749B-EEBE-4B2A-B79A-B162BAB68E24}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{708891CD-FD0A-455F-9ECE-9615ADDC7A64}" 11 | ProjectSection(SolutionItems) = preProject 12 | changelog.md = changelog.md 13 | gulpfile.js = gulpfile.js 14 | nuget.config = nuget.config 15 | package.json = package.json 16 | readme.md = readme.md 17 | EndProjectSection 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{D3A85B77-BCBF-455F-9882-A63809F8F8B0}" 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Digipolis.DataAccess.UnitTests", "test\Digipolis.DataAccess.UnitTests\Digipolis.DataAccess.UnitTests.csproj", "{FF0474FF-5844-4B0A-8B7B-47AC592BDE03}" 22 | EndProject 23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Digipolis.DataAccess", "src\Digipolis.DataAccess\Digipolis.DataAccess.csproj", "{9EA166E6-D15B-453F-A68E-8119BC472933}" 24 | EndProject 25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataAccess.SampleApp", "samples\DataAccess.SampleApp\DataAccess.SampleApp.csproj", "{C5A387B7-1E4A-441F-9571-389A76710710}" 26 | EndProject 27 | Global 28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 29 | Debug|Any CPU = Debug|Any CPU 30 | Release|Any CPU = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {FF0474FF-5844-4B0A-8B7B-47AC592BDE03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {FF0474FF-5844-4B0A-8B7B-47AC592BDE03}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {FF0474FF-5844-4B0A-8B7B-47AC592BDE03}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {FF0474FF-5844-4B0A-8B7B-47AC592BDE03}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {9EA166E6-D15B-453F-A68E-8119BC472933}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {9EA166E6-D15B-453F-A68E-8119BC472933}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {9EA166E6-D15B-453F-A68E-8119BC472933}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {9EA166E6-D15B-453F-A68E-8119BC472933}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {C5A387B7-1E4A-441F-9571-389A76710710}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {C5A387B7-1E4A-441F-9571-389A76710710}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {C5A387B7-1E4A-441F-9571-389A76710710}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {C5A387B7-1E4A-441F-9571-389A76710710}.Release|Any CPU.Build.0 = Release|Any CPU 45 | EndGlobalSection 46 | GlobalSection(SolutionProperties) = preSolution 47 | HideSolutionNode = FALSE 48 | EndGlobalSection 49 | GlobalSection(NestedProjects) = preSolution 50 | {FF0474FF-5844-4B0A-8B7B-47AC592BDE03} = {263D749B-EEBE-4B2A-B79A-B162BAB68E24} 51 | {9EA166E6-D15B-453F-A68E-8119BC472933} = {3D5D0B67-478E-4734-83F5-9D9F612E5661} 52 | {C5A387B7-1E4A-441F-9571-389A76710710} = {D3A85B77-BCBF-455F-9882-A63809F8F8B0} 53 | EndGlobalSection 54 | EndGlobal 55 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | UnitOfWork/Repository library for .NET Core applications - Copyright (C) 2017 Digipolis Open Source Team 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU Affero General Public License as 5 | published by the Free Software Foundation, either version 3 of the 6 | License, or (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Affero General Public License for more details. 12 | 13 | You should have received a copy of the GNU Affero General Public License 14 | along with this program. If not, see . -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # DataAccess Toolbox Changelog 2 | 3 | ## 4.0.4 4 | 5 | - revert to 4.0.1 optimization issue with context disposal in UoW base 6 | 7 | ## 4.0.3 8 | 9 | - fix for repository disposal 10 | 11 | ## 4.0.2 12 | 13 | - improved memory management 14 | - improved database connection handling 15 | 16 | ## 4.0.1 17 | 18 | - fixed dependency injection memory leak 19 | 20 | ## 4.0.0 21 | 22 | - update dependencies for .Net Standard 2.0 23 | 24 | ## 3.0.1 25 | 26 | - bugfix: columnattribute now works when using LowerCaseTablesAndFields modelbuilder extension 27 | 28 | ## 3.0.0 29 | 30 | - conversion to csproj and MSBuild. 31 | 32 | ## 2.5.2 33 | 34 | - Recompilation to correct wrong dependencies. 35 | 36 | ## 2.5.1 37 | 38 | - Bugfix invalid cast exception when creating custom repositories. 39 | 40 | ## 2.5.0 41 | 42 | - Bugfix invalid cast exception when using GetCustomRepository. 43 | 44 | ## 2.4.0 45 | 46 | - Added ModelBuilder extensions. 47 | 48 | ## 2.3.1 49 | 50 | - Added Any and AnyAsync methods to Repository. 51 | 52 | ## 2.3.0 53 | 54 | - Removed EntityBase constraint on multiple generic interfaces and classes. 55 | - Added PageNumber, PageLength and TotalPageCount and renamed TotalCount to TotalEntityCount on DataPage class. 56 | 57 | ## 2.2.1 58 | 59 | - Bugfix includes with Get and GetAsync. 60 | 61 | ## 2.2.0 62 | 63 | - NoTracking behaviour. 64 | 65 | ## 2.1.0 66 | 67 | - Changed include functionality. 68 | 69 | ## 2.0.0 70 | 71 | - Upgrade to dotnet core 1.0.0. 72 | 73 | ## 1.6.2 74 | 75 | - Re-Added GetRepository (removed in 1.6.0). 76 | 77 | ## 1.6.0 78 | 79 | - Added PluralizeTableNames to EntityContextOptions. 80 | - Added DefaultSchema to EntityContextOptions. 81 | - Changed generic implementation of GetRepository. 82 | - Changed dependencies to logger from ILogger to ILogger of DataAccess. 83 | 84 | ## 1.5.0 85 | 86 | - Added paging. 87 | 88 | ## 1.4.0 89 | 90 | - Upgrade to ASP.NET 5 RC1. 91 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var toc = require('gulp-doctoc'); 3 | 4 | gulp.task('readme', function () { 5 | gulp.src("./readme.md") 6 | .pipe(toc()) 7 | .pipe(gulp.dest(".")); 8 | 9 | }); 10 | 11 | gulp.task('default', ['readme']); -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.5.2", 3 | "name": "digipolis-dataaccess-framework", 4 | "private": true, 5 | "devDependencies": { 6 | "gulp": "3.9.0", 7 | "gulp-doctoc": "0.1.3" 8 | } 9 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # DataAccess Toolbox 2 | 3 | The DataAccess Toolbox contains the base classes for data access in ASP.NET Core with Entity Framework Core 1.0 using the unit-of-work and repository pattern. 4 | 5 | It contains : 6 | - base classes for entities. 7 | - base classes for repositories. 8 | - generic repositories. 9 | - unit-of-work and repository pattern. 10 | (- automatic discovery of repositories -- not yet) 11 | 12 | 13 | ## Table of Contents 14 | 15 | 16 | 17 | 18 | 19 | - [Installation](#installation) 20 | - [Configuration in Startup.ConfigureServices](#configuration-in-startupconfigureservices) 21 | - [NpgSql](#npgsql) 22 | - [EntityContext](#entitycontext) 23 | - [ModelBuilder extensions](#modelbuilder-extensions) 24 | - [Set all table- and field-names to lowercase](#set-all-table--and-field-names-to-lowercase) 25 | - [Disable cascading deletes](#disable-cascading-deletes) 26 | - [Entities](#entities) 27 | - [UnitOfWork](#unitofwork) 28 | - [Repositories](#repositories) 29 | - [Get and GetAsync](#get-and-getasync) 30 | - [GetAll and GetAllAsync](#getall-and-getallasync) 31 | - [Any and AnyAsync](#any-and-anyasync) 32 | - [Add](#add) 33 | - [Update](#update) 34 | - [Remove](#remove) 35 | - [Custom Repositories](#custom-repositories) 36 | - [Query](#query) 37 | - [Filter](#filter) 38 | - [Includes](#includes) 39 | - [OrderBy](#orderby) 40 | - [Paging](#paging) 41 | 42 | 43 | ## Installation 44 | 45 | Adding the DataAccess Toolbox to a project is as easy as adding it to the csproj project file: 46 | 47 | ```xml 48 | 49 | 50 | 51 | ``` 52 | 53 | or if your project still works with project.json : 54 | 55 | 56 | ``` json 57 | "dependencies": { 58 | "Digipolis.DataAccess": "4.0.0" 59 | } 60 | ``` 61 | 62 | **For netcoreapp2.0-projects a package version >= 4.0.0 must be used. 63 | For netcoreapp1.x-projects use a package version < 4.0.0. A separate branch (netstandard_1_6) has been created to apply changes for the older version if necessary.** 64 | 65 | Make sure you have our Nuget feed configured (https://www.myget.org/F/digipolisantwerp/api/v3/index.json.). 66 | 67 | Alternatively, it can also be added via the NuGet Package Manager interface. 68 | 69 | ## Configuration in Startup.ConfigureServices 70 | 71 | The DataAccess framework is registered in the _**ConfigureServices**_ method of the *Startup* class. 72 | 73 | 74 | ``` csharp 75 | services.AddDataAccess(); 76 | ``` 77 | 78 | Next to this registration you will need to register entity framework separately. 79 | 80 | ### NpgSql 81 | 82 | If you use NpgSql, you can for example use this entity framework configuration: 83 | 84 | ``` csharp 85 | var connection = @"Server=127.0.0.1;Port=5432;Database=TestDB;User Id=postgres;Password=mypwd;"; 86 | services.AddDbContext(options => options.UseNpgsql(connection)); 87 | ``` 88 | 89 | Check the [Entity Framework documentation](https://ef.readthedocs.io/en/latest/) for more info on the configuration possibilities. 90 | 91 | 92 | ## EntityContext 93 | 94 | You inherit a DbContext object from the EntityContextBase class in the toolbox. This context contains all your project-specific DbSets and custom logic. 95 | The constructor has to accept an DbContextOptions<TContext> as input parameter, to be passed to the base constructor and where TContext is the type of your context. 96 | The EntityContextBase is a generic type with your context as type parameter. This is necessary in order to pass the generic DbContextOptions object to the underlying DbContext constructor. 97 | 98 | For example : 99 | 100 | ``` csharp 101 | public class EntityContext : EntityContextBase 102 | { 103 | public EntityContext(DbContextOptions options) : base(options) 104 | { } 105 | 106 | public DbSet 107 | MyEntities { get; set; } 108 | public DbSet 109 | MyOtherEntities { get; set; } 110 | 111 | protected override void OnModelCreating(DbModelBuilder modelBuilder) 112 | { 113 | // optional, see Entity Framework documentation 114 | } 115 | } 116 | ``` 117 | 118 | ## ModelBuilder extensions 119 | 120 | Sometimes you want more control over the way the database structure is layed out (e.g. you are bound by rules set by the database administrators), other times you might already have a database in place and you can't change the structure. 121 | The EF ModelBuilder allows you to control the mapping of the CLR types to the database schema. The following extensions give you extra possibilities that are not included in the standard Entity Framework libraries. 122 | 123 | ### Set all table- and field-names to lowercase 124 | 125 | ```csharp 126 | protected override void OnModelCreating(ModelBuilder modelBuilder) 127 | { 128 | base.OnModelCreating(modelBuilder); 129 | 130 | modelBuilder.LowerCaseTablesAndFields(); 131 | } 132 | ``` 133 | 134 | ### Disable cascading deletes 135 | 136 | ```csharp 137 | protected override void OnModelCreating(ModelBuilder modelBuilder) 138 | { 139 | base.OnModelCreating(modelBuilder); 140 | 141 | modelBuilder.DisableCascadingDeletes(); 142 | } 143 | ``` 144 | 145 | ## Entities 146 | 147 | Your Entities are inherited from the base class EntityBase in the toolbox : 148 | 149 | ``` csharp 150 | public class MyEntity : EntityBase 151 | { 152 | public string MyProperty { get; set; } 153 | } 154 | ``` 155 | 156 | The EntityBase class already contains an int property, named Id that can be used as primary key. 157 | 158 | ## UnitOfWork 159 | 160 | The toolbox contains a UnitOfWork class and IUnitofWork interface that encapsulates the DbContext and that you use in your business classes to separate the data access code from business code. 161 | The IUnitOfWork is instantiated by the IUowProvider. 162 | 163 | First inject the IUowProvider in your business class : 164 | 165 | ``` csharp 166 | public class BusinessClass 167 | { 168 | public BusinessClass(IUowProvider uowProvider) 169 | { 170 | _uowProvider = uowProvider; 171 | } 172 | 173 | private readonly IUowProvider _uowProvider; 174 | } 175 | ``` 176 | 177 | Then ask the IUowProvider for a IUnitOfWork : 178 | 179 | ``` csharp 180 | using ( var uow = _uowProvider.CreateUnitOfWork() ) 181 | { 182 | // your business logic that needs dataaccess comes here 183 | } 184 | ``` 185 | 186 | You can pass in false if you don't want the **change tracking** to activate (better performance when you only want to retrieve data and not insert/update/delete). 187 | 188 | Now access your data via repositories : 189 | 190 | ``` csharp 191 | var repository = uow.GetRepository(); 192 | // your data access code via the repository comes here 193 | ``` 194 | 195 | The UnitOfWork will be automatically injected in the repository and used to interact with the database. 196 | 197 | To persist your changes to the database, call the SaveChanges or SaveChangesAsync method of the IUnitOfWork : 198 | 199 | ``` csharp 200 | uow.SaveChanges(); 201 | ``` 202 | 203 | ## Repositories 204 | 205 | The toolbox registers generic repositories in the ASP.NET Core DI container. They provide the following methods : 206 | 207 | ### Get and GetAsync 208 | 209 | Retrieve a single record by id, optionally passing in an IncludeList of child entities that you also want retrieved : 210 | 211 | ``` csharp 212 | using (var uow = _uowProvider.CreateUnitOfWork()) 213 | { 214 | var repository = uow.GetRepository(); 215 | 216 | // retrieve MyEntity with id = 5 217 | var entity = repository.Get(5); 218 | 219 | // retrieve MyEntity with id 12 and its child object 220 | var includeList = new IncludeList(e => e.Child); 221 | var entity2 = repository.Get(12, includes: includeList); 222 | } 223 | ``` 224 | 225 | ### GetAll and GetAllAsync 226 | 227 | Retrieves all records, with or without child records. 228 | 229 | ``` csharp 230 | using (var uow = _uowProvider.CreateUnitOfWork(false)) 231 | { 232 | var repository = uow.GetRepository(); 233 | var entities = repository.GetAll(includes: includes); 234 | } 235 | ``` 236 | 237 | ### Any and AnyAsync 238 | 239 | Checks if at least one record exists with the provided filter. 240 | 241 | ``` csharp 242 | using (var uow = _uowProvider.CreateUnitOfWork(false)) 243 | { 244 | var repository = uow.GetRepository(); 245 | bool exists = repository.Any(filter: filter); 246 | } 247 | ``` 248 | 249 | ### Add 250 | 251 | Adds a record to the repository. The record is persisted to the database when calling IUnitOfWork.SaveChanges(). 252 | 253 | ``` csharp 254 | using (var uow = _uowProvider.CreateUnitOfWork()) 255 | { 256 | var repository = uow.GetRepository(); 257 | repository.Add(newEntity); 258 | uow.SaveChanges(); 259 | } 260 | ``` 261 | 262 | ### Update 263 | 264 | Updates an existing record. 265 | 266 | Important note! When you update an entity with children objects, these child objects will also be updated. There is no need to update al the child objects separately. 267 | This is a new behaviour from the entity framework core **update** method on the DbSet. 268 | 269 | ``` csharp 270 | using (var uow = _uowProvider.CreateUnitOfWork()) 271 | { 272 | var repository = uow.GetRepository(); 273 | repository.Update(updatedEntity); 274 | await uow.SaveChangesAsync(); 275 | } 276 | ``` 277 | 278 | ### Remove 279 | 280 | You can call this method with an existing entity : 281 | 282 | ``` csharp 283 | using (var uow = _uowProvider.CreateUnitOfWork()) 284 | { 285 | var repository = uow.GetRepository(); 286 | repository.Remove(existingEntity); 287 | await uow.SaveChangesAsync(); 288 | } 289 | ``` 290 | 291 | Or with the Id of an existing entity : 292 | 293 | ``` csharp 294 | using (var uow = _uowProvider.CreateUnitOfWork()) 295 | { 296 | var repository = uow.GetRepository(); 297 | repository.Remove(id); 298 | uow.SaveChangesAsync(); 299 | } 300 | ``` 301 | 302 | ### Custom Repositories 303 | 304 | When you need more functionality in a repository than the generic methods, you can create our own repositories by inheriting from the repository base classes. 305 | 306 | To make a repository that is tied to 1 entity type, you inherit from the _**EntityRepositoryBase**_ class : 307 | 308 | ``` csharp 309 | public class MyRepository : EntityRepositoryBase , IMyRepository 310 | { 311 | public MyRepository(ILogger logger) : base(logger, null) 312 | { } 313 | } 314 | ``` 315 | 316 | This base class already contains the generic Add, Update, Delete, Get and Query methods. 317 | 318 | If you just want to start with an empty repository or a repository that is not tied to 1 type of entity, inherit from the _**RepositoryBase**_ class : 319 | 320 | ``` csharp 321 | public class MyRepository : RepositoryBase, IMyRepository 322 | { 323 | public MyRepository(ILogger logger) : base(logger, null) 324 | { } 325 | } 326 | ``` 327 | 328 | **Don't forget to register your own repositories in the DI container at startup :** 329 | 330 | ``` csharp 331 | services.AddTransient(); // or any other scope (Scoped, Singleton). 332 | ``` 333 | 334 | ## Query 335 | These helpers help generating queries: 336 | 337 | ### Filter 338 | A Filter holds the requested filter (WHERE) values. 339 | 340 | ``` csharp 341 | List<`Participant`> participants = null; 342 | 343 | using (var uow = _uowProvider.CreateUnitOfWork(false)) 344 | { 345 | Filter 346 | filter = new Filter 347 | (null); 348 | 349 | filter.AddExpression(e => idList.Contains(e.Id)); 350 | 351 | var repository = uow.GetRepository>(); 352 | 353 | participants = (await repository.QueryAsync(filter.Expression, includes:includes)).ToList(); 354 | } 355 | ``` 356 | 357 | ### Includes 358 | Holds the parameters to generate the Include part of the query. 359 | 360 | ``` csharp 361 | 362 | var includes = new Includes(query => 363 | { 364 | return query.Include(b => b.Appartments) 365 | .ThenInclude(a => a.Rooms); 366 | }); 367 | 368 | buildings = await repository.GetAllAsync(null, includes.Expression); 369 | 370 | ``` 371 | 372 | ### OrderBy 373 | Holds the parameters to generate the OrderBy part of the query. 374 | 375 | ``` csharp 376 | 377 | var orderBy = new OrderBy(string.IsNullOrEmpty(paging.Sort) ? "Reservation.DateOfReservation" : paging.Sort, paging.Descending); 378 | 379 | ``` 380 | 381 | ## Paging 382 | 383 | When working with large collections of data you'll want to keep your application performant. Instead of retrieving all records, you can serve your data 384 | to the consumer in pages. 385 | 386 | The repositories have methods that can be used with paging systems. You can also inject a IDataPager object in your classes to retrieve paged data : 387 | 388 | ``` csharp 389 | public class MyBusinessClass 390 | { 391 | public MyBusinessClass(IDataPager pager) 392 | { 393 | _pager = pager; 394 | } 395 | 396 | private readonly IDataPager _pager; 397 | } 398 | ``` 399 | 400 | and call its methods to retrieve paged data : 401 | 402 | ``` csharp 403 | var pageNumber = 1; 404 | var pageLength = 10; 405 | 406 | var data = _pager.Get(pageNumber, pageLength); 407 | 408 | var filter = new Filter(e => e.AProperty == true); 409 | 410 | var filteredData = _pager.Query(pageNumber, pageLenght, filter); 411 | ``` 412 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "wwwroot/lib" 3 | } 4 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.EntityFrameworkCore; 7 | using Digipolis.DataAccess; 8 | using DataAccess.SampleApp.Entities; 9 | using Digipolis.DataAccess.Query; 10 | 11 | namespace DataAccess.SampleApp.Controllers 12 | { 13 | public class HomeController : Controller 14 | { 15 | private readonly IUowProvider _uowProvider; 16 | 17 | public HomeController(IUowProvider uowProvider) 18 | { 19 | _uowProvider = uowProvider; 20 | } 21 | 22 | public async Task Index() 23 | { 24 | //await Seed(); 25 | IEnumerable buildings = null; 26 | 27 | using (var uow = _uowProvider.CreateUnitOfWork()) 28 | { 29 | var repository = uow.GetRepository(); 30 | 31 | //************************************** 32 | 33 | var includes = new Includes(query => 34 | { 35 | return query.Include(b => b.Appartments) 36 | .ThenInclude(a => a.Rooms); 37 | }); 38 | 39 | buildings = await repository.GetAllAsync(null, includes.Expression); 40 | 41 | //var building = await repository.GetAsync(1, includes.Expression); 42 | 43 | //************************************** 44 | 45 | //Func, IQueryable> func = query => 46 | //{ 47 | // return query.Include(b => b.Appartments) 48 | // .ThenInclude(a => a.Rooms); 49 | //}; 50 | 51 | //buildings = await repository.GetAllAsync(null, func); 52 | 53 | //************************************** 54 | 55 | //buildings = await repository.GetAllAsync(null, query => 56 | //{ 57 | // return query.Include(b => b.Appartments) 58 | // .ThenInclude(a => a.Rooms); 59 | //}); 60 | 61 | 62 | } 63 | 64 | return View(buildings); 65 | } 66 | 67 | public async Task Seed() 68 | { 69 | var buildings = new List 70 | { 71 | new Building 72 | { 73 | Name = "Building one", 74 | Appartments = new List 75 | { 76 | new Appartment 77 | { 78 | Number = 1, 79 | Floor = 1, 80 | Rooms = new List 81 | { 82 | new Room 83 | { 84 | Name = "Kitchen", 85 | }, 86 | new Room 87 | { 88 | Name = "Living", 89 | }, 90 | new Room 91 | { 92 | Name = "Bedroom", 93 | } 94 | } 95 | }, 96 | new Appartment 97 | { 98 | Number = 21, 99 | Floor = 2, 100 | Rooms = new List 101 | { 102 | new Room 103 | { 104 | Name = "Kitchen", 105 | }, 106 | new Room 107 | { 108 | Name = "Living", 109 | }, 110 | new Room 111 | { 112 | Name = "Bedroom 1", 113 | }, 114 | new Room 115 | { 116 | Name = "Bedroom 2", 117 | } 118 | } 119 | } 120 | } 121 | } 122 | }; 123 | 124 | using (var uow = _uowProvider.CreateUnitOfWork()) 125 | { 126 | var repository = uow.GetRepository(); 127 | 128 | foreach (var item in buildings) 129 | { 130 | repository.Add(item); 131 | } 132 | 133 | await uow.SaveChangesAsync(); 134 | } 135 | 136 | return View(); 137 | } 138 | 139 | 140 | public IActionResult Error() 141 | { 142 | return View(); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/DataAccess.SampleApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.0 5 | true 6 | DataAccess.SampleApp 7 | Exe 8 | DataAccess.SampleApp 9 | 2.0.0 10 | $(AssetTargetFallback);dotnet5.6;portable-net45+win8 11 | 12 | 13 | 14 | 15 | PreserveNewest 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Entities/Appartment.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace DataAccess.SampleApp.Entities 8 | { 9 | public class Appartment: EntityBase 10 | { 11 | public int Number { get; set; } 12 | public int Floor { get; set; } 13 | public ICollection Rooms { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Entities/Building.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace DataAccess.SampleApp.Entities 8 | { 9 | public class Building : EntityBase 10 | { 11 | public string Name { get; set; } 12 | public ICollection Appartments { get; set; } 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Entities/Room.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace DataAccess.SampleApp.Entities 9 | { 10 | public class Room : EntityBase 11 | { 12 | [Column("MyNewRoomName")] 13 | public string Name { get; set; } 14 | public int Length { get; set; } 15 | public int Width { get; set; } 16 | public int NumberOfDoors { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Migrations/20171124112019_initial.Designer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using DataAccess.SampleApp; 7 | 8 | namespace DataAccess.SampleApp.Migrations 9 | { 10 | [DbContext(typeof(SampleAppContext))] 11 | [Migration("20171124112019_initial")] 12 | partial class initial 13 | { 14 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 15 | { 16 | modelBuilder 17 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) 18 | .HasAnnotation("ProductVersion", "1.1.2"); 19 | 20 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Appartment", b => 21 | { 22 | b.Property("Id") 23 | .ValueGeneratedOnAdd(); 24 | 25 | b.Property("BuildingId"); 26 | 27 | b.Property("Floor"); 28 | 29 | b.Property("Number"); 30 | 31 | b.HasKey("Id"); 32 | 33 | b.HasIndex("BuildingId"); 34 | 35 | b.ToTable("Appartment"); 36 | }); 37 | 38 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Building", b => 39 | { 40 | b.Property("Id") 41 | .ValueGeneratedOnAdd(); 42 | 43 | b.Property("Name"); 44 | 45 | b.HasKey("Id"); 46 | 47 | b.ToTable("Buildings"); 48 | }); 49 | 50 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Room", b => 51 | { 52 | b.Property("Id") 53 | .ValueGeneratedOnAdd(); 54 | 55 | b.Property("AppartmentId"); 56 | 57 | b.Property("Length"); 58 | 59 | b.Property("Name"); 60 | 61 | b.Property("NumberOfDoors"); 62 | 63 | b.Property("Width"); 64 | 65 | b.HasKey("Id"); 66 | 67 | b.HasIndex("AppartmentId"); 68 | 69 | b.ToTable("Room"); 70 | }); 71 | 72 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Appartment", b => 73 | { 74 | b.HasOne("DataAccess.SampleApp.Entities.Building") 75 | .WithMany("Appartments") 76 | .HasForeignKey("BuildingId"); 77 | }); 78 | 79 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Room", b => 80 | { 81 | b.HasOne("DataAccess.SampleApp.Entities.Appartment") 82 | .WithMany("Rooms") 83 | .HasForeignKey("AppartmentId"); 84 | }); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Migrations/20171124112019_initial.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore.Migrations; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | 6 | namespace DataAccess.SampleApp.Migrations 7 | { 8 | public partial class initial : Migration 9 | { 10 | protected override void Up(MigrationBuilder migrationBuilder) 11 | { 12 | migrationBuilder.CreateTable( 13 | name: "Buildings", 14 | columns: table => new 15 | { 16 | Id = table.Column(nullable: false) 17 | .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), 18 | Name = table.Column(nullable: true) 19 | }, 20 | constraints: table => 21 | { 22 | table.PrimaryKey("PK_Buildings", x => x.Id); 23 | }); 24 | 25 | migrationBuilder.CreateTable( 26 | name: "Appartment", 27 | columns: table => new 28 | { 29 | Id = table.Column(nullable: false) 30 | .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), 31 | BuildingId = table.Column(nullable: true), 32 | Floor = table.Column(nullable: false), 33 | Number = table.Column(nullable: false) 34 | }, 35 | constraints: table => 36 | { 37 | table.PrimaryKey("PK_Appartment", x => x.Id); 38 | table.ForeignKey( 39 | name: "FK_Appartment_Buildings_BuildingId", 40 | column: x => x.BuildingId, 41 | principalTable: "Buildings", 42 | principalColumn: "Id", 43 | onDelete: ReferentialAction.Restrict); 44 | }); 45 | 46 | migrationBuilder.CreateTable( 47 | name: "Room", 48 | columns: table => new 49 | { 50 | Id = table.Column(nullable: false) 51 | .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), 52 | AppartmentId = table.Column(nullable: true), 53 | Length = table.Column(nullable: false), 54 | Name = table.Column(nullable: true), 55 | NumberOfDoors = table.Column(nullable: false), 56 | Width = table.Column(nullable: false) 57 | }, 58 | constraints: table => 59 | { 60 | table.PrimaryKey("PK_Room", x => x.Id); 61 | table.ForeignKey( 62 | name: "FK_Room_Appartment_AppartmentId", 63 | column: x => x.AppartmentId, 64 | principalTable: "Appartment", 65 | principalColumn: "Id", 66 | onDelete: ReferentialAction.Restrict); 67 | }); 68 | 69 | migrationBuilder.CreateIndex( 70 | name: "IX_Appartment_BuildingId", 71 | table: "Appartment", 72 | column: "BuildingId"); 73 | 74 | migrationBuilder.CreateIndex( 75 | name: "IX_Room_AppartmentId", 76 | table: "Room", 77 | column: "AppartmentId"); 78 | } 79 | 80 | protected override void Down(MigrationBuilder migrationBuilder) 81 | { 82 | migrationBuilder.DropTable( 83 | name: "Room"); 84 | 85 | migrationBuilder.DropTable( 86 | name: "Appartment"); 87 | 88 | migrationBuilder.DropTable( 89 | name: "Buildings"); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Migrations/20171124112404_lowercasedtablesandfieldswithcolumnattribute.Designer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using DataAccess.SampleApp; 7 | 8 | namespace DataAccess.SampleApp.Migrations 9 | { 10 | [DbContext(typeof(SampleAppContext))] 11 | [Migration("20171124112404_lowercasedtablesandfieldswithcolumnattribute")] 12 | partial class lowercasedtablesandfieldswithcolumnattribute 13 | { 14 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 15 | { 16 | modelBuilder 17 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) 18 | .HasAnnotation("ProductVersion", "1.1.2"); 19 | 20 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Appartment", b => 21 | { 22 | b.Property("Id") 23 | .ValueGeneratedOnAdd() 24 | .HasColumnName("id"); 25 | 26 | b.Property("BuildingId") 27 | .HasColumnName("buildingid"); 28 | 29 | b.Property("Floor") 30 | .HasColumnName("floor"); 31 | 32 | b.Property("Number") 33 | .HasColumnName("number"); 34 | 35 | b.HasKey("Id"); 36 | 37 | b.HasIndex("BuildingId"); 38 | 39 | b.ToTable("appartment"); 40 | }); 41 | 42 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Building", b => 43 | { 44 | b.Property("Id") 45 | .ValueGeneratedOnAdd() 46 | .HasColumnName("id"); 47 | 48 | b.Property("Name") 49 | .HasColumnName("name"); 50 | 51 | b.HasKey("Id"); 52 | 53 | b.ToTable("building"); 54 | }); 55 | 56 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Room", b => 57 | { 58 | b.Property("Id") 59 | .ValueGeneratedOnAdd() 60 | .HasColumnName("id"); 61 | 62 | b.Property("AppartmentId") 63 | .HasColumnName("appartmentid"); 64 | 65 | b.Property("Length") 66 | .HasColumnName("length"); 67 | 68 | b.Property("Name") 69 | .HasColumnName("mynewroomname"); 70 | 71 | b.Property("NumberOfDoors") 72 | .HasColumnName("numberofdoors"); 73 | 74 | b.Property("Width") 75 | .HasColumnName("width"); 76 | 77 | b.HasKey("Id"); 78 | 79 | b.HasIndex("AppartmentId"); 80 | 81 | b.ToTable("room"); 82 | }); 83 | 84 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Appartment", b => 85 | { 86 | b.HasOne("DataAccess.SampleApp.Entities.Building") 87 | .WithMany("Appartments") 88 | .HasForeignKey("BuildingId"); 89 | }); 90 | 91 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Room", b => 92 | { 93 | b.HasOne("DataAccess.SampleApp.Entities.Appartment") 94 | .WithMany("Rooms") 95 | .HasForeignKey("AppartmentId"); 96 | }); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Migrations/20171124112404_lowercasedtablesandfieldswithcolumnattribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore.Migrations; 4 | 5 | namespace DataAccess.SampleApp.Migrations 6 | { 7 | public partial class lowercasedtablesandfieldswithcolumnattribute : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.DropForeignKey( 12 | name: "FK_Appartment_Buildings_BuildingId", 13 | table: "Appartment"); 14 | 15 | migrationBuilder.DropForeignKey( 16 | name: "FK_Room_Appartment_AppartmentId", 17 | table: "Room"); 18 | 19 | migrationBuilder.DropPrimaryKey( 20 | name: "PK_Room", 21 | table: "Room"); 22 | 23 | migrationBuilder.DropPrimaryKey( 24 | name: "PK_Buildings", 25 | table: "Buildings"); 26 | 27 | migrationBuilder.DropPrimaryKey( 28 | name: "PK_Appartment", 29 | table: "Appartment"); 30 | 31 | migrationBuilder.RenameTable( 32 | name: "Room", 33 | newName: "room"); 34 | 35 | migrationBuilder.RenameTable( 36 | name: "Buildings", 37 | newName: "building"); 38 | 39 | migrationBuilder.RenameTable( 40 | name: "Appartment", 41 | newName: "appartment"); 42 | 43 | migrationBuilder.RenameColumn( 44 | name: "Width", 45 | table: "room", 46 | newName: "width"); 47 | 48 | migrationBuilder.RenameColumn( 49 | name: "NumberOfDoors", 50 | table: "room", 51 | newName: "numberofdoors"); 52 | 53 | migrationBuilder.RenameColumn( 54 | name: "Name", 55 | table: "room", 56 | newName: "mynewroomname"); 57 | 58 | migrationBuilder.RenameColumn( 59 | name: "Length", 60 | table: "room", 61 | newName: "length"); 62 | 63 | migrationBuilder.RenameColumn( 64 | name: "AppartmentId", 65 | table: "room", 66 | newName: "appartmentid"); 67 | 68 | migrationBuilder.RenameColumn( 69 | name: "Id", 70 | table: "room", 71 | newName: "id"); 72 | 73 | migrationBuilder.RenameIndex( 74 | name: "IX_Room_AppartmentId", 75 | table: "room", 76 | newName: "IX_room_appartmentid"); 77 | 78 | migrationBuilder.RenameColumn( 79 | name: "Name", 80 | table: "building", 81 | newName: "name"); 82 | 83 | migrationBuilder.RenameColumn( 84 | name: "Id", 85 | table: "building", 86 | newName: "id"); 87 | 88 | migrationBuilder.RenameColumn( 89 | name: "Number", 90 | table: "appartment", 91 | newName: "number"); 92 | 93 | migrationBuilder.RenameColumn( 94 | name: "Floor", 95 | table: "appartment", 96 | newName: "floor"); 97 | 98 | migrationBuilder.RenameColumn( 99 | name: "BuildingId", 100 | table: "appartment", 101 | newName: "buildingid"); 102 | 103 | migrationBuilder.RenameColumn( 104 | name: "Id", 105 | table: "appartment", 106 | newName: "id"); 107 | 108 | migrationBuilder.RenameIndex( 109 | name: "IX_Appartment_BuildingId", 110 | table: "appartment", 111 | newName: "IX_appartment_buildingid"); 112 | 113 | migrationBuilder.AddPrimaryKey( 114 | name: "PK_room", 115 | table: "room", 116 | column: "id"); 117 | 118 | migrationBuilder.AddPrimaryKey( 119 | name: "PK_building", 120 | table: "building", 121 | column: "id"); 122 | 123 | migrationBuilder.AddPrimaryKey( 124 | name: "PK_appartment", 125 | table: "appartment", 126 | column: "id"); 127 | 128 | migrationBuilder.AddForeignKey( 129 | name: "FK_appartment_building_buildingid", 130 | table: "appartment", 131 | column: "buildingid", 132 | principalTable: "building", 133 | principalColumn: "id", 134 | onDelete: ReferentialAction.Restrict); 135 | 136 | migrationBuilder.AddForeignKey( 137 | name: "FK_room_appartment_appartmentid", 138 | table: "room", 139 | column: "appartmentid", 140 | principalTable: "appartment", 141 | principalColumn: "id", 142 | onDelete: ReferentialAction.Restrict); 143 | } 144 | 145 | protected override void Down(MigrationBuilder migrationBuilder) 146 | { 147 | migrationBuilder.DropForeignKey( 148 | name: "FK_appartment_building_buildingid", 149 | table: "appartment"); 150 | 151 | migrationBuilder.DropForeignKey( 152 | name: "FK_room_appartment_appartmentid", 153 | table: "room"); 154 | 155 | migrationBuilder.DropPrimaryKey( 156 | name: "PK_room", 157 | table: "room"); 158 | 159 | migrationBuilder.DropPrimaryKey( 160 | name: "PK_building", 161 | table: "building"); 162 | 163 | migrationBuilder.DropPrimaryKey( 164 | name: "PK_appartment", 165 | table: "appartment"); 166 | 167 | migrationBuilder.RenameTable( 168 | name: "room", 169 | newName: "Room"); 170 | 171 | migrationBuilder.RenameTable( 172 | name: "building", 173 | newName: "Buildings"); 174 | 175 | migrationBuilder.RenameTable( 176 | name: "appartment", 177 | newName: "Appartment"); 178 | 179 | migrationBuilder.RenameColumn( 180 | name: "width", 181 | table: "Room", 182 | newName: "Width"); 183 | 184 | migrationBuilder.RenameColumn( 185 | name: "numberofdoors", 186 | table: "Room", 187 | newName: "NumberOfDoors"); 188 | 189 | migrationBuilder.RenameColumn( 190 | name: "mynewroomname", 191 | table: "Room", 192 | newName: "Name"); 193 | 194 | migrationBuilder.RenameColumn( 195 | name: "length", 196 | table: "Room", 197 | newName: "Length"); 198 | 199 | migrationBuilder.RenameColumn( 200 | name: "appartmentid", 201 | table: "Room", 202 | newName: "AppartmentId"); 203 | 204 | migrationBuilder.RenameColumn( 205 | name: "id", 206 | table: "Room", 207 | newName: "Id"); 208 | 209 | migrationBuilder.RenameIndex( 210 | name: "IX_room_appartmentid", 211 | table: "Room", 212 | newName: "IX_Room_AppartmentId"); 213 | 214 | migrationBuilder.RenameColumn( 215 | name: "name", 216 | table: "Buildings", 217 | newName: "Name"); 218 | 219 | migrationBuilder.RenameColumn( 220 | name: "id", 221 | table: "Buildings", 222 | newName: "Id"); 223 | 224 | migrationBuilder.RenameColumn( 225 | name: "number", 226 | table: "Appartment", 227 | newName: "Number"); 228 | 229 | migrationBuilder.RenameColumn( 230 | name: "floor", 231 | table: "Appartment", 232 | newName: "Floor"); 233 | 234 | migrationBuilder.RenameColumn( 235 | name: "buildingid", 236 | table: "Appartment", 237 | newName: "BuildingId"); 238 | 239 | migrationBuilder.RenameColumn( 240 | name: "id", 241 | table: "Appartment", 242 | newName: "Id"); 243 | 244 | migrationBuilder.RenameIndex( 245 | name: "IX_appartment_buildingid", 246 | table: "Appartment", 247 | newName: "IX_Appartment_BuildingId"); 248 | 249 | migrationBuilder.AddPrimaryKey( 250 | name: "PK_Room", 251 | table: "Room", 252 | column: "Id"); 253 | 254 | migrationBuilder.AddPrimaryKey( 255 | name: "PK_Buildings", 256 | table: "Buildings", 257 | column: "Id"); 258 | 259 | migrationBuilder.AddPrimaryKey( 260 | name: "PK_Appartment", 261 | table: "Appartment", 262 | column: "Id"); 263 | 264 | migrationBuilder.AddForeignKey( 265 | name: "FK_Appartment_Buildings_BuildingId", 266 | table: "Appartment", 267 | column: "BuildingId", 268 | principalTable: "Buildings", 269 | principalColumn: "Id", 270 | onDelete: ReferentialAction.Restrict); 271 | 272 | migrationBuilder.AddForeignKey( 273 | name: "FK_Room_Appartment_AppartmentId", 274 | table: "Room", 275 | column: "AppartmentId", 276 | principalTable: "Appartment", 277 | principalColumn: "Id", 278 | onDelete: ReferentialAction.Restrict); 279 | } 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Migrations/SampleAppContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using DataAccess.SampleApp; 7 | 8 | namespace DataAccess.SampleApp.Migrations 9 | { 10 | [DbContext(typeof(SampleAppContext))] 11 | partial class SampleAppContextModelSnapshot : ModelSnapshot 12 | { 13 | protected override void BuildModel(ModelBuilder modelBuilder) 14 | { 15 | modelBuilder 16 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) 17 | .HasAnnotation("ProductVersion", "1.1.2"); 18 | 19 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Appartment", b => 20 | { 21 | b.Property("Id") 22 | .ValueGeneratedOnAdd() 23 | .HasColumnName("id"); 24 | 25 | b.Property("BuildingId") 26 | .HasColumnName("buildingid"); 27 | 28 | b.Property("Floor") 29 | .HasColumnName("floor"); 30 | 31 | b.Property("Number") 32 | .HasColumnName("number"); 33 | 34 | b.HasKey("Id"); 35 | 36 | b.HasIndex("BuildingId"); 37 | 38 | b.ToTable("appartment"); 39 | }); 40 | 41 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Building", b => 42 | { 43 | b.Property("Id") 44 | .ValueGeneratedOnAdd() 45 | .HasColumnName("id"); 46 | 47 | b.Property("Name") 48 | .HasColumnName("name"); 49 | 50 | b.HasKey("Id"); 51 | 52 | b.ToTable("building"); 53 | }); 54 | 55 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Room", b => 56 | { 57 | b.Property("Id") 58 | .ValueGeneratedOnAdd() 59 | .HasColumnName("id"); 60 | 61 | b.Property("AppartmentId") 62 | .HasColumnName("appartmentid"); 63 | 64 | b.Property("Length") 65 | .HasColumnName("length"); 66 | 67 | b.Property("Name") 68 | .HasColumnName("mynewroomname"); 69 | 70 | b.Property("NumberOfDoors") 71 | .HasColumnName("numberofdoors"); 72 | 73 | b.Property("Width") 74 | .HasColumnName("width"); 75 | 76 | b.HasKey("Id"); 77 | 78 | b.HasIndex("AppartmentId"); 79 | 80 | b.ToTable("room"); 81 | }); 82 | 83 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Appartment", b => 84 | { 85 | b.HasOne("DataAccess.SampleApp.Entities.Building") 86 | .WithMany("Appartments") 87 | .HasForeignKey("BuildingId"); 88 | }); 89 | 90 | modelBuilder.Entity("DataAccess.SampleApp.Entities.Room", b => 91 | { 92 | b.HasOne("DataAccess.SampleApp.Entities.Appartment") 93 | .WithMany("Rooms") 94 | .HasForeignKey("AppartmentId"); 95 | }); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Hosting; 7 | 8 | namespace DataAccess.SampleApp 9 | { 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | var host = new WebHostBuilder() 15 | .UseKestrel() 16 | .UseContentRoot(Directory.GetCurrentDirectory()) 17 | .UseIISIntegration() 18 | .UseStartup() 19 | .Build(); 20 | 21 | host.Run(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:53436/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "DataAccess.SampleApp": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "launchUrl": "http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/SampleAppContext.cs: -------------------------------------------------------------------------------- 1 | using DataAccess.SampleApp.Entities; 2 | using Digipolis.DataAccess.Context; 3 | using Microsoft.EntityFrameworkCore; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace DataAccess.SampleApp 10 | { 11 | public class SampleAppContext : EntityContextBase 12 | { 13 | public SampleAppContext(DbContextOptions options) : base(options) 14 | { } 15 | 16 | public DbSet Buildings { get; set; } 17 | 18 | protected override void OnModelCreating(ModelBuilder modelBuilder) 19 | { 20 | base.OnModelCreating(modelBuilder); 21 | modelBuilder.LowerCaseTablesAndFields(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.Extensions.Configuration; 8 | using Microsoft.Extensions.DependencyInjection; 9 | using Microsoft.Extensions.Logging; 10 | using Microsoft.EntityFrameworkCore; 11 | using Digipolis.DataAccess; 12 | using Microsoft.Extensions.Options; 13 | using System.IO; 14 | 15 | namespace DataAccess.SampleApp 16 | { 17 | public class Startup 18 | { 19 | public Startup(IHostingEnvironment env) 20 | { 21 | var configPath = Path.Combine(env.ContentRootPath, "_config"); 22 | 23 | var builder = new ConfigurationBuilder() 24 | .SetBasePath(configPath) 25 | .AddJsonFile("dataaccess.json", optional: true, reloadOnChange: true) 26 | .AddEnvironmentVariables(); 27 | Configuration = builder.Build(); 28 | } 29 | 30 | public IConfigurationRoot Configuration { get; } 31 | 32 | // This method gets called by the runtime. Use this method to add services to the container. 33 | public void ConfigureServices(IServiceCollection services) 34 | { 35 | //Configure DataAccess service 36 | 37 | //var connection = @"Server=localhost;Port=5432;Database=data_access_sample_app;User Id=postgres;Password=root;"; 38 | var connection = BuildConnectionString(services); 39 | 40 | services.AddDbContext(options => options.UseNpgsql(connection.ToString())); 41 | 42 | services.AddDataAccess(); 43 | 44 | // Add framework services. 45 | services.AddMvc(); 46 | } 47 | 48 | private ConnectionString BuildConnectionString(IServiceCollection services) 49 | { 50 | var section = Configuration.GetSection("ConnectionString"); 51 | services.Configure(section); 52 | 53 | var configureOptions = services.BuildServiceProvider().GetRequiredService>(); 54 | var connectionString = new ConnectionString(); 55 | configureOptions.Configure(connectionString); 56 | return connectionString; 57 | } 58 | 59 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 60 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 61 | { 62 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 63 | loggerFactory.AddDebug(); 64 | 65 | if (env.IsDevelopment()) 66 | { 67 | app.UseDeveloperExceptionPage(); 68 | app.UseBrowserLink(); 69 | } 70 | else 71 | { 72 | app.UseExceptionHandler("/Home/Error"); 73 | } 74 | 75 | app.UseStaticFiles(); 76 | 77 | app.UseMvc(routes => 78 | { 79 | routes.MapRoute( 80 | name: "default", 81 | template: "{controller=Home}/{action=Index}/{id?}"); 82 | }); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IEnumerable 2 | 3 | @{ 4 | ViewData["Title"] = "Home Page"; 5 | } 6 | 7 |
8 |
9 |

Overview

10 | @foreach (var building in Model) 11 | { 12 |
Building name: @building.Name
13 | @foreach (var appartment in building.Appartments) 14 | { 15 |
Appartment number: @appartment.Number
16 | @foreach (var room in appartment.Rooms) 17 | { 18 |
Room name: @room.Name
19 | } 20 | } 21 | } 22 |
23 |
24 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Views/Home/Seed.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Seed"; 3 | } 4 |

@ViewData["Title"].

5 |

@ViewData["Message"]

6 | 7 |

Data has been seeded.

8 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Error"; 3 | } 4 | 5 |

Error.

6 |

An error occurred while processing your request.

7 | 8 |

Development Mode

9 |

10 | Swapping to Development environment will display more detailed information about the error that occurred. 11 |

12 |

13 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 14 |

15 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - DataAccess.SampleApp 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 39 |
40 | @RenderBody() 41 |
42 |
43 |

© 2016 - DataAccess.SampleApp

44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 61 | 62 | 63 | 64 | @RenderSection("scripts", required: false) 65 | 66 | 67 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using DataAccess.SampleApp 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/_config/dataaccess.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionString": { 3 | "Host": "localhost", 4 | "Port": "5432", 5 | "DbName": "data_access_sample_app", 6 | "User": "postgres", 7 | "Password": "admin" 8 | } 9 | } -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asp.net", 3 | "private": true, 4 | "dependencies": { 5 | "bootstrap": "3.3.6", 6 | "jquery": "2.2.0", 7 | "jquery-validation": "1.14.0", 8 | "jquery-validation-unobtrusive": "3.2.6" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/bundleconfig.json: -------------------------------------------------------------------------------- 1 | // Configure bundling and minification for the project. 2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241 3 | [ 4 | { 5 | "outputFileName": "wwwroot/css/site.min.css", 6 | // An array of relative input file paths. Globbing patterns supported 7 | "inputFiles": [ 8 | "wwwroot/css/site.css" 9 | ] 10 | }, 11 | { 12 | "outputFileName": "wwwroot/js/site.min.js", 13 | "inputFiles": [ 14 | "wwwroot/js/site.js" 15 | ], 16 | // Optionally specify minification options 17 | "minify": { 18 | "enabled": true, 19 | "renameLocals": true 20 | }, 21 | // Optinally generate .map file 22 | "sourceMap": false 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/_references.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}input,select,textarea{max-width:280px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}@media screen and (max-width:767px){.carousel-caption{display:none}} -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digipolisantwerp/dataaccess_aspnetcore_deprecated/bdcddbfd92d374e3ce067b5aa56956eb8c7ee8e4/samples/DataAccess.SampleApp/wwwroot/favicon.ico -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/images/banner1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/images/banner2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/images/banner3.svg: -------------------------------------------------------------------------------- 1 | banner3b -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/images/banner4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Write your Javascript code. 2 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/js/site.min.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digipolisantwerp/dataaccess_aspnetcore_deprecated/bdcddbfd92d374e3ce067b5aa56956eb8c7ee8e4/samples/DataAccess.SampleApp/wwwroot/js/site.min.js -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap", 3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 4 | "keywords": [ 5 | "css", 6 | "js", 7 | "less", 8 | "mobile-first", 9 | "responsive", 10 | "front-end", 11 | "framework", 12 | "web" 13 | ], 14 | "homepage": "http://getbootstrap.com", 15 | "license": "MIT", 16 | "moduleType": "globals", 17 | "main": [ 18 | "less/bootstrap.less", 19 | "dist/js/bootstrap.js" 20 | ], 21 | "ignore": [ 22 | "/.*", 23 | "_config.yml", 24 | "CNAME", 25 | "composer.json", 26 | "CONTRIBUTING.md", 27 | "docs", 28 | "js/tests", 29 | "test-infra" 30 | ], 31 | "dependencies": { 32 | "jquery": "1.9.1 - 2" 33 | }, 34 | "version": "3.3.6", 35 | "_release": "3.3.6", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.3.6", 39 | "commit": "81df608a40bf0629a1dc08e584849bb1e43e0b7a" 40 | }, 41 | "_source": "git://github.com/twbs/bootstrap.git", 42 | "_target": "3.3.6", 43 | "_originalSource": "bootstrap" 44 | } -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2015 Twitter, Inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":";;;;AAmBA,YAAA,aAAA,UAAA,aAAA,aAAA,aAME,YAAA,EAAA,KAAA,EAAA,eC2CA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBDvCR,mBAAA,mBAAA,oBAAA,oBAAA,iBAAA,iBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBCsCA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBDlCR,qBAAA,sBAAA,sBAAA,uBAAA,mBAAA,oBAAA,sBAAA,uBAAA,sBAAA,uBAAA,sBAAA,uBAAA,+BAAA,gCAAA,6BAAA,gCAAA,gCAAA,gCCiCA,mBAAA,KACQ,WAAA,KDlDV,mBAAA,oBAAA,iBAAA,oBAAA,oBAAA,oBAuBI,YAAA,KAyCF,YAAA,YAEE,iBAAA,KAKJ,aErEI,YAAA,EAAA,IAAA,EAAA,KACA,iBAAA,iDACA,iBAAA,4CAAA,iBAAA,qEAEA,iBAAA,+CCnBF,OAAA,+GH4CA,OAAA,0DACA,kBAAA,SAuC2C,aAAA,QAA2B,aAAA,KArCtE,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAgBN,aEtEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAiBN,aEvEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAkBN,UExEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,gBAAA,gBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,iBAAA,iBAEE,iBAAA,QACA,aAAA,QAMA,mBAAA,0BAAA,yBAAA,0BAAA,yBAAA,yBAAA,oBAAA,2BAAA,0BAAA,2BAAA,0BAAA,0BAAA,6BAAA,oCAAA,mCAAA,oCAAA,mCAAA,mCAME,iBAAA,QACA,iBAAA,KAmBN,aEzEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAoBN,YE1EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,kBAAA,kBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,mBAAA,mBAEE,iBAAA,QACA,aAAA,QAMA,qBAAA,4BAAA,2BAAA,4BAAA,2BAAA,2BAAA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,+BAAA,sCAAA,qCAAA,sCAAA,qCAAA,qCAME,iBAAA,QACA,iBAAA,KA2BN,eAAA,WClCE,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBD2CV,0BAAA,0BE3FI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GF0FF,kBAAA,SAEF,yBAAA,+BAAA,+BEhGI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GFgGF,kBAAA,SASF,gBE7GI,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SH+HA,cAAA,ICjEA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBD6DV,sCAAA,oCE7GI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBD0EV,cAAA,iBAEE,YAAA,EAAA,IAAA,EAAA,sBAIF,gBEhII,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SHkJA,cAAA,IAHF,sCAAA,oCEhII,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBDgFV,8BAAA,iCAYI,YAAA,EAAA,KAAA,EAAA,gBAKJ,qBAAA,kBAAA,mBAGE,cAAA,EAqBF,yBAfI,mDAAA,yDAAA,yDAGE,MAAA,KE7JF,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,UFqKJ,OACE,YAAA,EAAA,IAAA,EAAA,qBC3HA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBDsIV,eEtLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAKF,YEvLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAMF,eExLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAOF,cEzLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAeF,UEjMI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFuMJ,cE3MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFwMJ,sBE5MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyMJ,mBE7MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0MJ,sBE9MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2MJ,qBE/MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF+MJ,sBElLI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKFyLJ,YACE,cAAA,IC9KA,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBDgLV,wBAAA,8BAAA,8BAGE,YAAA,EAAA,KAAA,EAAA,QEnOE,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFiOF,aAAA,QALF,+BAAA,qCAAA,qCAQI,YAAA,KAUJ,OCnME,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gBD4MV,8BE5PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyPJ,8BE7PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0PJ,8BE9PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2PJ,2BE/PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF4PJ,8BEhQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF6PJ,6BEjQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoQJ,MExQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFsQF,aAAA,QC3NA,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA"} -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digipolisantwerp/dataaccess_aspnetcore_deprecated/bdcddbfd92d374e3ce067b5aa56956eb8c7ee8e4/samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digipolisantwerp/dataaccess_aspnetcore_deprecated/bdcddbfd92d374e3ce067b5aa56956eb8c7ee8e4/samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digipolisantwerp/dataaccess_aspnetcore_deprecated/bdcddbfd92d374e3ce067b5aa56956eb8c7ee8e4/samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digipolisantwerp/dataaccess_aspnetcore_deprecated/bdcddbfd92d374e3ce067b5aa56956eb8c7ee8e4/samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/jquery-validation-unobtrusive/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation-unobtrusive", 3 | "version": "3.2.6", 4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", 5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.", 6 | "main": [ 7 | "jquery.validate.unobtrusive.js" 8 | ], 9 | "ignore": [ 10 | "**/.*", 11 | "*.json", 12 | "*.md", 13 | "*.txt", 14 | "gulpfile.js" 15 | ], 16 | "keywords": [ 17 | "jquery", 18 | "asp.net", 19 | "mvc", 20 | "validation", 21 | "unobtrusive" 22 | ], 23 | "authors": [ 24 | "Microsoft" 25 | ], 26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm", 27 | "repository": { 28 | "type": "git", 29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git" 30 | }, 31 | "dependencies": { 32 | "jquery-validation": ">=1.8", 33 | "jquery": ">=1.8" 34 | }, 35 | "_release": "3.2.6", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.2.6", 39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7" 40 | }, 41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git", 42 | "_target": "3.2.6", 43 | "_originalSource": "jquery-validation-unobtrusive" 44 | } -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** Unobtrusive validation support library for jQuery and jQuery Validate 3 | ** Copyright (C) Microsoft Corporation. All rights reserved. 4 | */ 5 | !function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function m(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=p.unobtrusive.options||{},m=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),m("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),m("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),m("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var u,p=a.validator,v="unobtrusiveValidation";p.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=m(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){p.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=m(this);a&&a.attachValidation()})}},u=p.unobtrusive.adapters,u.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},u.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},u.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},u.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},p.addMethod("__dummy__",function(a,e,n){return!0}),p.addMethod("regex",function(a,e,n){var t;return this.optional(e)?!0:(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),p.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),p.methods.extension?(u.addSingleVal("accept","mimtype"),u.addSingleVal("extension","extension")):u.addSingleVal("extension","extension","accept"),u.addSingleVal("regex","pattern"),u.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),u.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),u.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),u.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),u.add("required",function(a){("INPUT"!==a.element.tagName.toUpperCase()||"CHECKBOX"!==a.element.type.toUpperCase())&&e(a,"required",!0)}),u.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),u.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),a(function(){p.unobtrusive.parse(document)})}(jQuery); -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/jquery-validation/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation", 3 | "homepage": "http://jqueryvalidation.org/", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/jzaefferer/jquery-validation.git" 7 | }, 8 | "authors": [ 9 | "Jörn Zaefferer " 10 | ], 11 | "description": "Form validation made easy", 12 | "main": "dist/jquery.validate.js", 13 | "keywords": [ 14 | "forms", 15 | "validation", 16 | "validate" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "demo", 25 | "lib" 26 | ], 27 | "dependencies": { 28 | "jquery": ">= 1.7.2" 29 | }, 30 | "version": "1.14.0", 31 | "_release": "1.14.0", 32 | "_resolution": { 33 | "type": "version", 34 | "tag": "1.14.0", 35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48" 36 | }, 37 | "_source": "git://github.com/jzaefferer/jquery-validation.git", 38 | "_target": ">=1.8", 39 | "_originalSource": "jquery-validation" 40 | } -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "2.2.0", 16 | "_release": "2.2.0", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "2.2.0", 20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5" 21 | }, 22 | "_source": "git://github.com/jquery/jquery-dist.git", 23 | "_target": "2.2.0", 24 | "_originalSource": "jquery" 25 | } -------------------------------------------------------------------------------- /samples/DataAccess.SampleApp/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Attributes/HasPrecisionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Digipolis.DataAccess.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] 6 | public sealed class HasPrecisionAttribute : Attribute 7 | { 8 | public HasPrecisionAttribute(byte precision, byte scale) 9 | { 10 | this.Precision = precision; 11 | this.Scale = scale; 12 | } 13 | 14 | public byte Precision { get; set; } 15 | public byte Scale { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Context/EntityContextBase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace Digipolis.DataAccess.Context 4 | { 5 | public class EntityContextBase : DbContext, IEntityContext where TContext : DbContext 6 | { 7 | public EntityContextBase(DbContextOptions options) : base(options) 8 | { 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Context/IEntityContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Digipolis.DataAccess.Context 7 | { 8 | interface IEntityContext 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Context/ModelBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | 6 | namespace Digipolis.DataAccess.Context 7 | { 8 | public static class ModelBuilderExtensions 9 | { 10 | public static void LowerCaseTablesAndFields(this ModelBuilder modelBuilder) 11 | { 12 | foreach ( var entityType in modelBuilder.Model.GetEntityTypes() ) 13 | { 14 | // Skip shadow types 15 | if ( entityType.ClrType == null ) 16 | { 17 | continue; 18 | } 19 | 20 | // Set the table name to the (simple) name of the CLR type and lowercase it 21 | entityType.Relational().TableName = entityType.ClrType.Name.ToLower(); 22 | 23 | // Lowercase all properties 24 | foreach ( var property in entityType.GetProperties() ) 25 | { 26 | //Check if property has a ColumnAttribute. If so, use the lowercased value of this attribute instead of lowercased property name 27 | var columnNameAttribute = property.GetAnnotations().FirstOrDefault(x => x.Name.ToLower().Contains("columnname"))?.Value; 28 | property.Relational().ColumnName = columnNameAttribute == null ? property.Name.ToLower() : columnNameAttribute.ToString().ToLower(); 29 | } 30 | } 31 | } 32 | 33 | public static void DisableCascadingDeletes(this ModelBuilder modelBuilder) 34 | { 35 | foreach ( var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(x => x.GetForeignKeys()) ) 36 | { 37 | relationship.DeleteBehavior = DeleteBehavior.Restrict; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/DataAccess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Digipolis.DataAccess 7 | { 8 | 9 | /// 10 | /// The sole purpose of this class is to be used as type for the generic ILogger 11 | /// 12 | public class DataAccess 13 | { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Digipolis.DataAccess.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 4.0.4 5 | netstandard2.0 6 | Digipolis.DataAccess 7 | Digipolis.DataAccess 8 | 2.0.0 9 | $(AssetTargetFallback);dnxcore50 10 | 4.0.4 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Entities/EntityBase.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Digipolis.DataAccess.Entities 4 | { 5 | public class EntityBase 6 | { 7 | // This is the base class for all entities. 8 | // The DataAccess repositories have this class as constraint for entities that are persisted in the database. 9 | 10 | [Key] 11 | public int Id { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Exceptions/EntityNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Digipolis.DataAccess.Exceptions 4 | { 5 | public class EntityNotFoundException : Exception 6 | { 7 | public EntityNotFoundException(string entityName, int entityKey) 8 | { 9 | this.EntityName = entityName; 10 | this.EntityKey = entityKey; 11 | _message = String.Format("Entity of type '{0}' and key {1} not found in the current context.", entityName, EntityKey); 12 | } 13 | 14 | public string EntityName { get; set; } 15 | 16 | public int EntityKey { get; set; } 17 | 18 | private readonly string _message = null; 19 | public override string Message 20 | { 21 | get { return _message; } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Exceptions/RepositoryNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Digipolis.DataAccess.Exceptions 4 | { 5 | public class RepositoryNotFoundException : Exception 6 | { 7 | public RepositoryNotFoundException(string repositoryName, string message) : base(message) 8 | { 9 | if ( String.IsNullOrWhiteSpace(repositoryName) ) throw new ArgumentException($"{nameof(repositoryName)} cannot be null or empty.", nameof(repositoryName)); 10 | this.RepositoryName = repositoryName; 11 | } 12 | 13 | public string RepositoryName { get; private set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Options/ConnectionString.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Options; 2 | using System; 3 | using System.Reflection; 4 | 5 | namespace Digipolis.DataAccess 6 | { 7 | public class ConnectionString 8 | { 9 | public ConnectionString() : this(Defaults.ConnectionString.Host, Defaults.ConnectionString.Port, Assembly.GetEntryAssembly().GetName().Name) 10 | { } 11 | 12 | public ConnectionString(string host, ushort port, string dbname, string user = null, string password = null) 13 | { 14 | ValidateArguments(host, dbname); 15 | Host = host; 16 | Port = port; 17 | DbName = dbname; 18 | User = user; 19 | Password = password; 20 | } 21 | 22 | public string Host { get; set; } 23 | public ushort Port { get; set; } 24 | public string DbName { get; set; } 25 | public string User { get; set; } 26 | public string Password { get; set; } 27 | 28 | private void ValidateArguments(string host, string dbname) 29 | { 30 | if ( host == null ) throw new ArgumentNullException(nameof(host), $"{nameof(host)} is null."); 31 | if ( dbname == null ) throw new ArgumentNullException(nameof(dbname), $"{nameof(dbname)} is null."); 32 | 33 | if ( host.Trim() == String.Empty ) throw new ArgumentException($"{nameof(host)} is empty.", nameof(host)); 34 | if ( dbname.Trim() == String.Empty ) throw new ArgumentException($"{nameof(dbname)} is empty.", nameof(dbname)); 35 | } 36 | 37 | public override string ToString() 38 | { 39 | var result = $"Server={Host};Database={DbName};"; 40 | 41 | if ( Port > 0 ) result += $"Port={Port};"; 42 | 43 | if ( User == null ) 44 | result += $"Integrated Security=true;"; 45 | else 46 | { 47 | result += $"User Id={User};"; 48 | if ( Password != null ) result += $"Password={Password};"; 49 | } 50 | 51 | return result; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Options/Defaults.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Digipolis.DataAccess.Options 5 | { 6 | public class Defaults 7 | { 8 | public class ConnectionString 9 | { 10 | public const string Host = "localhost"; 11 | public const int Port = 0; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Paging/DataPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Digipolis.DataAccess.Entities; 4 | 5 | namespace Digipolis.DataAccess.Paging 6 | { 7 | public class DataPage 8 | { 9 | public IEnumerable Data { get; set; } 10 | public long TotalEntityCount { get; set; } 11 | 12 | public int PageNumber { get; set; } 13 | public int PageLength { get; set; } 14 | 15 | public int TotalPageCount { 16 | get 17 | { 18 | return Convert.ToInt32(Math.Ceiling((decimal)TotalEntityCount / PageLength)); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Paging/DataPager.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Entities; 2 | using Digipolis.DataAccess.Query; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace Digipolis.DataAccess.Paging 9 | { 10 | public class DataPager : IDataPager 11 | { 12 | public DataPager(IUowProvider uowProvider) 13 | { 14 | _uowProvider = uowProvider; 15 | } 16 | 17 | private readonly IUowProvider _uowProvider; 18 | 19 | public DataPage Get(int pageNumber, int pageLength, OrderBy orderby = null, Func, IQueryable> includes = null) 20 | { 21 | using ( var uow = _uowProvider.CreateUnitOfWork(false) ) 22 | { 23 | var repository = uow.GetRepository(); 24 | 25 | var startRow = ( pageNumber - 1 ) * pageLength; 26 | var data = repository.GetPage(startRow, pageLength, includes: includes, orderBy: orderby?.Expression); 27 | var totalCount = repository.Count(); 28 | 29 | return CreateDataPage(pageNumber, pageLength, data, totalCount); 30 | } 31 | } 32 | 33 | public async Task> GetAsync(int pageNumber, int pageLength, OrderBy orderby = null, Func, IQueryable> includes = null) 34 | { 35 | using ( var uow = _uowProvider.CreateUnitOfWork(false) ) 36 | { 37 | var repository = uow.GetRepository(); 38 | 39 | var startRow = ( pageNumber - 1 ) * pageLength; 40 | var data = await repository.GetPageAsync(startRow, pageLength, includes: includes, orderBy: orderby?.Expression); 41 | var totalCount = await repository.CountAsync(); 42 | 43 | return CreateDataPage(pageNumber, pageLength, data, totalCount); 44 | } 45 | } 46 | 47 | public DataPage Query(int pageNumber, int pageLength, Filter filter, OrderBy orderby = null, Func, IQueryable> includes = null) 48 | { 49 | using ( var uow = _uowProvider.CreateUnitOfWork(false) ) 50 | { 51 | var repository = uow.GetRepository(); 52 | 53 | var startRow = ( pageNumber - 1 ) * pageLength; 54 | var data = repository.QueryPage(startRow, pageLength, filter.Expression, includes: includes, orderBy: orderby?.Expression); 55 | var totalCount = repository.Count(filter.Expression); 56 | 57 | return CreateDataPage(pageNumber, pageLength, data, totalCount); 58 | } 59 | } 60 | 61 | public async Task> QueryAsync(int pageNumber, int pageLength, Filter filter, OrderBy orderby = null, Func, IQueryable> includes = null) 62 | { 63 | using ( var uow = _uowProvider.CreateUnitOfWork(false) ) 64 | { 65 | var repository = uow.GetRepository(); 66 | 67 | var startRow = ( pageNumber - 1 ) * pageLength; 68 | var data = await repository.QueryPageAsync(startRow, pageLength, filter.Expression, includes: includes, orderBy: orderby?.Expression); 69 | var totalCount = await repository.CountAsync(filter.Expression); 70 | 71 | return CreateDataPage(pageNumber, pageLength, data, totalCount); 72 | } 73 | } 74 | 75 | private DataPage CreateDataPage(int pageNumber, int pageLength, IEnumerable data, long totalEntityCount) 76 | { 77 | var page = new DataPage() 78 | { 79 | Data = data, 80 | TotalEntityCount = totalEntityCount, 81 | PageLength = pageLength, 82 | PageNumber = pageNumber 83 | }; 84 | 85 | return page; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Paging/IDataPager.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Entities; 2 | using Digipolis.DataAccess.Query; 3 | using System; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace Digipolis.DataAccess.Paging 8 | { 9 | public interface IDataPager 10 | { 11 | DataPage Get(int pageNumber, int pageLength, OrderBy orderby = null, Func, IQueryable> includes = null); 12 | DataPage Query(int pageNumber, int pageLength, Filter filter, OrderBy orderby = null, Func, IQueryable> includes = null); 13 | 14 | Task> GetAsync(int pageNumber, int pageLength, OrderBy orderby = null, Func, IQueryable> includes = null); 15 | Task> QueryAsync(int pageNumber, int pageLength, Filter filter, OrderBy orderby = null, Func, IQueryable> includes = null); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Digipolis.DataAccess.UnitTests")] 2 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Properties/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Redundancies in Code", "RECS0145", Justification = "Less squiggles")] 2 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Redundancies in Code", "RECS0129", Justification = "Less squiggles")] -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Properties/debugSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Profiles": [] 3 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Query/Filter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using Digipolis.DataAccess.Entities; 4 | 5 | namespace Digipolis.DataAccess.Query 6 | { 7 | public class Filter 8 | { 9 | public Filter(Expression> expression) 10 | { 11 | Expression = expression; 12 | } 13 | 14 | public Expression> Expression { get; private set; } 15 | 16 | public void AddExpression(Expression> newExpression) 17 | { 18 | if ( newExpression == null ) throw new ArgumentNullException(nameof(newExpression), $"{nameof(newExpression)} is null."); 19 | 20 | if ( Expression == null ) Expression = newExpression; 21 | 22 | var parameter = System.Linq.Expressions.Expression.Parameter(typeof(TEntity)); 23 | 24 | var leftVisitor = new ReplaceExpressionVisitor(newExpression.Parameters[0], parameter); 25 | var left = leftVisitor.Visit(newExpression.Body); 26 | 27 | var rightVisitor = new ReplaceExpressionVisitor(Expression.Parameters[0], parameter); 28 | var right = rightVisitor.Visit(Expression.Body); 29 | 30 | Expression = System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression.AndAlso(left, right), parameter); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Query/Includes.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Entities; 2 | using System; 3 | using System.Linq; 4 | 5 | namespace Digipolis.DataAccess.Query 6 | { 7 | public class Includes 8 | { 9 | public Includes(Func, IQueryable> expression) 10 | { 11 | Expression = expression; 12 | } 13 | 14 | public Func, IQueryable> Expression { get; private set; } 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Query/OrderBy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | using Digipolis.DataAccess.Entities; 7 | 8 | namespace Digipolis.DataAccess.Query 9 | { 10 | public class OrderBy 11 | { 12 | public OrderBy(Func, IOrderedQueryable> expression) 13 | { 14 | Expression = expression; 15 | } 16 | 17 | public OrderBy(string columName, bool reverse) 18 | { 19 | Expression = GetOrderBy(columName, reverse); 20 | } 21 | 22 | public Func, IOrderedQueryable> Expression { get; private set; } 23 | 24 | 25 | private Func, IOrderedQueryable> GetOrderBy(string columnName, bool reverse) 26 | { 27 | Type typeQueryable = typeof(IQueryable); 28 | ParameterExpression argQueryable = System.Linq.Expressions.Expression.Parameter(typeQueryable, "p"); 29 | var outerExpression = System.Linq.Expressions.Expression.Lambda(argQueryable, argQueryable); 30 | 31 | IQueryable query = new List().AsQueryable(); 32 | var entityType = typeof(TEntity); 33 | ParameterExpression arg = System.Linq.Expressions.Expression.Parameter(entityType, "x"); 34 | 35 | Expression expression = arg; 36 | string[] properties = columnName.Split('.'); 37 | foreach (string propertyName in properties) 38 | { 39 | PropertyInfo propertyInfo = entityType.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); 40 | expression = System.Linq.Expressions.Expression.Property(expression, propertyInfo); 41 | entityType = propertyInfo.PropertyType; 42 | } 43 | LambdaExpression lambda = System.Linq.Expressions.Expression.Lambda(expression, arg); 44 | string methodName = reverse ? "OrderByDescending" : "OrderBy"; 45 | 46 | MethodCallExpression resultExp = System.Linq.Expressions.Expression.Call(typeof(Queryable), 47 | methodName, 48 | new Type[] { typeof(TEntity), entityType }, 49 | outerExpression.Body, 50 | System.Linq.Expressions.Expression.Quote(lambda)); 51 | 52 | var finalLambda = System.Linq.Expressions.Expression.Lambda(resultExp, argQueryable); 53 | 54 | return (Func, IOrderedQueryable>)finalLambda.Compile(); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Query/ReplaceExpressionVisitor.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace Digipolis.DataAccess.Query 4 | { 5 | public class ReplaceExpressionVisitor : ExpressionVisitor 6 | { 7 | private readonly Expression _oldValue; 8 | private readonly Expression _newValue; 9 | 10 | public ReplaceExpressionVisitor(Expression oldValue, Expression newValue) 11 | { 12 | _oldValue = oldValue; 13 | _newValue = newValue; 14 | } 15 | 16 | public override Expression Visit(Expression node) 17 | { 18 | if ( node == _oldValue ) return _newValue; 19 | return base.Visit(node); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Repositories/EntityRepositoryBase.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Entities; 2 | using Digipolis.DataAccess.Query; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.Extensions.Logging; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Linq.Expressions; 9 | using System.Threading.Tasks; 10 | 11 | namespace Digipolis.DataAccess.Repositories 12 | { 13 | public abstract class EntityRepositoryBase : RepositoryBase, IRepository where TContext : DbContext where TEntity : EntityBase, new() 14 | { 15 | private readonly OrderBy DefaultOrderBy = new OrderBy(qry => qry.OrderBy(e => e.Id)); 16 | 17 | protected EntityRepositoryBase(ILogger logger, TContext context) : base(logger, context) 18 | { } 19 | 20 | public virtual IEnumerable GetAll(Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 21 | { 22 | var result = QueryDb(null, orderBy, includes); 23 | return result.ToList(); 24 | } 25 | 26 | public virtual async Task> GetAllAsync(Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 27 | { 28 | var result = QueryDb(null, orderBy, includes); 29 | return await result.ToListAsync(); 30 | } 31 | 32 | public virtual void Load(Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 33 | { 34 | var result = QueryDb(null, orderBy, includes); 35 | result.Load(); 36 | } 37 | 38 | public virtual async Task LoadAsync(Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 39 | { 40 | var result = QueryDb(null, orderBy, includes); 41 | await result.LoadAsync(); 42 | } 43 | 44 | public virtual IEnumerable GetPage(int startRow, int pageLength, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 45 | { 46 | if ( orderBy == null ) orderBy = DefaultOrderBy.Expression; 47 | 48 | var result = QueryDb(null, orderBy, includes); 49 | return result.Skip(startRow).Take(pageLength).ToList(); 50 | } 51 | 52 | public virtual async Task> GetPageAsync(int startRow, int pageLength, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 53 | { 54 | if ( orderBy == null ) orderBy = DefaultOrderBy.Expression; 55 | 56 | var result = QueryDb(null, orderBy, includes); 57 | return await result.Skip(startRow).Take(pageLength).ToListAsync(); 58 | } 59 | 60 | public virtual TEntity Get(int id, Func, IQueryable> includes = null) 61 | { 62 | IQueryable query = Context.Set(); 63 | 64 | if (includes != null) 65 | { 66 | query = includes(query); 67 | } 68 | 69 | return query.SingleOrDefault(x => x.Id == id); 70 | } 71 | 72 | public virtual Task GetAsync(int id, Func, IQueryable> includes = null) 73 | { 74 | IQueryable query = Context.Set(); 75 | 76 | if (includes != null) 77 | { 78 | query = includes(query); 79 | } 80 | 81 | return query.SingleOrDefaultAsync(x => x.Id == id); 82 | } 83 | 84 | public virtual IEnumerable Query(Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 85 | { 86 | var result = QueryDb(filter, orderBy, includes); 87 | return result.ToList(); 88 | } 89 | 90 | public virtual async Task> QueryAsync(Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 91 | { 92 | var result = QueryDb(filter, orderBy, includes); 93 | return await result.ToListAsync(); 94 | } 95 | 96 | public virtual void Load(Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 97 | { 98 | var result = QueryDb(filter, orderBy, includes); 99 | result.Load(); 100 | } 101 | 102 | public virtual async Task LoadAsync(Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 103 | { 104 | var result = QueryDb(filter, orderBy, includes); 105 | await result.LoadAsync(); 106 | } 107 | 108 | public virtual IEnumerable QueryPage(int startRow, int pageLength, Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 109 | { 110 | if ( orderBy == null ) orderBy = DefaultOrderBy.Expression; 111 | 112 | var result = QueryDb(filter, orderBy, includes); 113 | return result.Skip(startRow).Take(pageLength).ToList(); 114 | } 115 | 116 | public virtual async Task> QueryPageAsync(int startRow, int pageLength, Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null) 117 | { 118 | if ( orderBy == null ) orderBy = DefaultOrderBy.Expression; 119 | 120 | var result = QueryDb(filter, orderBy, includes); 121 | return await result.Skip(startRow).Take(pageLength).ToListAsync(); 122 | } 123 | 124 | public virtual void Add(TEntity entity) 125 | { 126 | if ( entity == null ) throw new InvalidOperationException("Unable to add a null entity to the repository."); 127 | Context.Set().Add(entity); 128 | } 129 | 130 | public virtual TEntity Update(TEntity entity) 131 | { 132 | return Context.Set().Update(entity).Entity; 133 | } 134 | 135 | public virtual void Remove(TEntity entity) 136 | { 137 | Context.Set().Attach(entity); 138 | Context.Entry(entity).State = EntityState.Deleted; 139 | Context.Set().Remove(entity); 140 | } 141 | 142 | public virtual void Remove(int id) 143 | { 144 | var entity = new TEntity() { Id = id }; 145 | this.Remove(entity); 146 | } 147 | 148 | public virtual bool Any(Expression> filter = null) 149 | { 150 | IQueryable query = Context.Set(); 151 | 152 | if (filter != null) 153 | { 154 | query = query.Where(filter); 155 | } 156 | 157 | return query.Any(); 158 | } 159 | 160 | public virtual Task AnyAsync(Expression> filter = null) 161 | { 162 | IQueryable query = Context.Set(); 163 | 164 | if (filter != null) 165 | { 166 | query = query.Where(filter); 167 | } 168 | 169 | return query.AnyAsync(); 170 | } 171 | 172 | public virtual int Count(Expression> filter = null) 173 | { 174 | IQueryable query = Context.Set(); 175 | 176 | if (filter != null) 177 | { 178 | query = query.Where(filter); 179 | } 180 | 181 | return query.Count(); 182 | } 183 | 184 | public virtual Task CountAsync(Expression> filter = null) 185 | { 186 | IQueryable query = Context.Set(); 187 | 188 | if (filter != null) 189 | { 190 | query = query.Where(filter); 191 | } 192 | 193 | return query.CountAsync(); 194 | } 195 | 196 | protected IQueryable QueryDb(Expression> filter, Func, IOrderedQueryable> orderBy, Func, IQueryable> includes) 197 | { 198 | IQueryable query = Context.Set(); 199 | 200 | if (filter != null) 201 | { 202 | query = query.Where(filter); 203 | } 204 | 205 | if (includes != null) 206 | { 207 | query = includes(query); 208 | } 209 | 210 | if (orderBy != null) 211 | { 212 | query = orderBy(query); 213 | } 214 | 215 | return query; 216 | } 217 | 218 | public void SetUnchanged(TEntity entity) 219 | { 220 | base.Context.Entry(entity).State = EntityState.Unchanged; 221 | } 222 | 223 | } 224 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Repositories/GenericEntityRepository.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.Extensions.Logging; 3 | using Digipolis.DataAccess.Entities; 4 | 5 | namespace Digipolis.DataAccess.Repositories 6 | { 7 | public class GenericEntityRepository : EntityRepositoryBase where TEntity : EntityBase, new() 8 | { 9 | public GenericEntityRepository(ILogger logger) : base(logger, null) 10 | { } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Repositories/IRepository.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace Digipolis.DataAccess.Repositories 9 | { 10 | public interface IRepository 11 | { 12 | IEnumerable GetAll(Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 13 | Task> GetAllAsync(Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 14 | 15 | IEnumerable GetPage(int startRij, int aantal, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 16 | Task> GetPageAsync(int startRij, int aantal, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 17 | 18 | TEntity Get(int id, Func, IQueryable> includes = null); 19 | Task GetAsync(int id, Func, IQueryable> includes = null); 20 | 21 | IEnumerable Query(Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 22 | Task> QueryAsync(Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 23 | 24 | IEnumerable QueryPage(int startRij, int aantal, Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 25 | Task> QueryPageAsync(int startRij, int aantal, Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 26 | 27 | void Load(Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 28 | Task LoadAsync(Expression> filter, Func, IOrderedQueryable> orderBy = null, Func, IQueryable> includes = null); 29 | 30 | void Add(TEntity entity); 31 | 32 | TEntity Update(TEntity entity); 33 | 34 | void Remove(TEntity entity); 35 | void Remove(int id); 36 | 37 | bool Any(Expression> filter = null); 38 | Task AnyAsync(Expression> filter = null); 39 | 40 | int Count(Expression> filter = null); 41 | Task CountAsync(Expression> filter = null); 42 | 43 | void SetUnchanged(TEntity entitieit); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Repositories/IRepositoryInjection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace Digipolis.DataAccess.Repositories 4 | { 5 | public interface IRepositoryInjection 6 | { 7 | IRepositoryInjection SetContext(DbContext context); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Repositories/RepositoryBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace Digipolis.DataAccess.Repositories 6 | { 7 | public abstract class RepositoryBase : IRepositoryInjection where TContext : DbContext 8 | { 9 | protected RepositoryBase(ILogger logger, TContext context) 10 | { 11 | this.Logger = logger; 12 | this.Context = context; 13 | } 14 | 15 | protected ILogger Logger { get; private set; } 16 | protected TContext Context { get; private set; } 17 | 18 | public IRepositoryInjection SetContext(DbContext context) 19 | { 20 | this.Context = (TContext)context; 21 | return this; 22 | } 23 | 24 | 25 | 26 | //IRepositoryInjection IRepositoryInjection.SetContext(TContext context) 27 | //{ 28 | // this.Context = context; 29 | // return this; 30 | //} 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Startup/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Digipolis.DataAccess.Context; 3 | using Digipolis.DataAccess.Uow; 4 | using Digipolis.DataAccess.Repositories; 5 | using Digipolis.DataAccess.Paging; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Configuration; 8 | using Microsoft.Extensions.DependencyInjection.Extensions; 9 | 10 | namespace Digipolis.DataAccess 11 | { 12 | public static class ServiceCollectionExtentions 13 | { 14 | public static IServiceCollection AddDataAccess(this IServiceCollection services) where TEntityContext : EntityContextBase 15 | { 16 | RegisterDataAccess(services); 17 | return services; 18 | } 19 | 20 | private static void RegisterDataAccess(IServiceCollection services) where TEntityContext : EntityContextBase 21 | { 22 | services.TryAddScoped(); 23 | services.TryAddTransient(); 24 | services.TryAddTransient(typeof(IRepository<>), typeof(GenericEntityRepository<>)); 25 | services.TryAddTransient(typeof(IDataPager<>), typeof(DataPager<>)); 26 | } 27 | 28 | private static void ValidateMandatoryField(string field, string fieldName) 29 | { 30 | if ( field == null ) throw new ArgumentNullException(fieldName, $"{fieldName} cannot be null."); 31 | if ( field.Trim() == String.Empty ) throw new ArgumentException($"{fieldName} cannot be empty.", fieldName); 32 | } 33 | 34 | private static void ValidateMandatoryField(object field, string fieldName) 35 | { 36 | if ( field == null ) throw new ArgumentNullException(fieldName, $"{fieldName} cannot be null."); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Uow/IUnitOfWork.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Digipolis.DataAccess.Entities; 5 | using Digipolis.DataAccess.Repositories; 6 | 7 | namespace Digipolis.DataAccess 8 | { 9 | public interface IUnitOfWork : IDisposable 10 | { 11 | int SaveChanges(); 12 | Task SaveChangesAsync(); 13 | Task SaveChangesAsync(CancellationToken cancellationToken); 14 | 15 | IRepository GetRepository(); 16 | TRepository GetCustomRepository(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Uow/IUnitOfWorkBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Digipolis.DataAccess.Entities; 5 | using Digipolis.DataAccess.Repositories; 6 | 7 | namespace Digipolis.DataAccess.Uow 8 | { 9 | public interface IUnitOfWorkBase : IDisposable 10 | { 11 | int SaveChanges(); 12 | Task SaveChangesAsync(); 13 | Task SaveChangesAsync(CancellationToken cancellationToken); 14 | 15 | IRepository GetRepository(); 16 | TRepository GetCustomRepository(); 17 | } 18 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Uow/IUowProvider.cs: -------------------------------------------------------------------------------- 1 |  2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace Digipolis.DataAccess 5 | { 6 | public interface IUowProvider 7 | { 8 | IUnitOfWork CreateUnitOfWork(bool trackChanges = true, bool enableLogging = false); 9 | IUnitOfWork CreateUnitOfWork(bool trackChanges = true, bool enableLogging = false) where TEntityContext : DbContext; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Uow/UnitOfWork.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Digipolis.DataAccess; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace Digipolis.DataAccess.Uow 6 | { 7 | public class UnitOfWork : UnitOfWorkBase, IUnitOfWork 8 | { 9 | public UnitOfWork(DbContext context, IServiceProvider provider) : base(context, provider) 10 | { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Uow/UnitOfWorkBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Digipolis.DataAccess.Exceptions; 5 | using Digipolis.DataAccess.Repositories; 6 | using Digipolis.DataAccess.Entities; 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | namespace Digipolis.DataAccess.Uow 10 | { 11 | public abstract class UnitOfWorkBase : IUnitOfWorkBase where TContext : DbContext 12 | { 13 | protected internal UnitOfWorkBase(TContext context, IServiceProvider serviceProvider) 14 | { 15 | _context = context; 16 | _serviceProvider = serviceProvider; 17 | } 18 | 19 | protected TContext _context; 20 | protected readonly IServiceProvider _serviceProvider; 21 | 22 | public int SaveChanges() 23 | { 24 | CheckDisposed(); 25 | return _context.SaveChanges(); 26 | } 27 | 28 | public Task SaveChangesAsync() 29 | { 30 | CheckDisposed(); 31 | return _context.SaveChangesAsync(); 32 | } 33 | 34 | public Task SaveChangesAsync(CancellationToken cancellationToken) 35 | { 36 | CheckDisposed(); 37 | return _context.SaveChangesAsync(cancellationToken); 38 | } 39 | 40 | public IRepository GetRepository() 41 | { 42 | CheckDisposed(); 43 | var repositoryType = typeof(IRepository); 44 | var repository = (IRepository)_serviceProvider.GetService(repositoryType); 45 | if (repository == null) 46 | { 47 | throw new RepositoryNotFoundException(repositoryType.Name, String.Format("Repository {0} not found in the IOC container. Check if it is registered during startup.", repositoryType.Name)); 48 | } 49 | 50 | ((IRepositoryInjection)repository).SetContext(_context); 51 | return repository; 52 | } 53 | 54 | public TRepository GetCustomRepository() 55 | { 56 | CheckDisposed(); 57 | var repositoryType = typeof(TRepository); 58 | var repository = (TRepository)_serviceProvider.GetService(repositoryType); 59 | if (repository == null) 60 | { 61 | throw new RepositoryNotFoundException(repositoryType.Name, String.Format("Repository {0} not found in the IOC container. Check if it is registered during startup.", repositoryType.Name)); 62 | } 63 | 64 | ((IRepositoryInjection)repository).SetContext(_context); 65 | return repository; 66 | } 67 | 68 | #region IDisposable Implementation 69 | 70 | protected bool _isDisposed; 71 | 72 | protected void CheckDisposed() 73 | { 74 | if (_isDisposed) throw new ObjectDisposedException("The UnitOfWork is already disposed and cannot be used anymore."); 75 | } 76 | 77 | protected virtual void Dispose(bool disposing) 78 | { 79 | if (!_isDisposed) 80 | { 81 | if (disposing) 82 | { 83 | if (_context != null) 84 | { 85 | _context.Dispose(); 86 | _context = null; 87 | } 88 | } 89 | } 90 | _isDisposed = true; 91 | } 92 | 93 | public void Dispose() 94 | { 95 | Dispose(true); 96 | GC.SuppressFinalize(this); 97 | } 98 | 99 | ~UnitOfWorkBase() 100 | { 101 | Dispose(false); 102 | } 103 | 104 | #endregion 105 | } 106 | } -------------------------------------------------------------------------------- /src/Digipolis.DataAccess/Uow/UowProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using Digipolis.DataAccess.Context; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | namespace Digipolis.DataAccess.Uow 7 | { 8 | public class UowProvider : IUowProvider 9 | { 10 | public UowProvider() 11 | { } 12 | 13 | public UowProvider(ILogger logger, IServiceProvider serviceProvider) 14 | { 15 | _logger = logger; 16 | _serviceProvider = serviceProvider; 17 | } 18 | 19 | private readonly ILogger _logger; 20 | private readonly IServiceProvider _serviceProvider; 21 | 22 | public IUnitOfWork CreateUnitOfWork(bool trackChanges = true, bool enableLogging = false) 23 | { 24 | var _context = (DbContext)_serviceProvider.GetService(typeof(IEntityContext)); 25 | 26 | if ( !trackChanges ) 27 | _context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; 28 | 29 | var uow = new UnitOfWork(_context, _serviceProvider); 30 | return uow; 31 | } 32 | 33 | public IUnitOfWork CreateUnitOfWork(bool trackChanges = true, bool enableLogging = false) where TEntityContext : DbContext 34 | { 35 | var _context = (TEntityContext)_serviceProvider.GetService(typeof(IEntityContext)); 36 | 37 | if (!trackChanges) 38 | _context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; 39 | 40 | var uow = new UnitOfWork(_context, _serviceProvider); 41 | return uow; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/Digipolis.DataAccess.UnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Unit tests for the DataAccess toolbox 5 | digipolis.be 6 | netcoreapp2.0 7 | Digipolis.DataAccess.UnitTests 8 | Digipolis.DataAccess.UnitTests 9 | true 10 | 2.0.0 11 | 2.0.0 12 | false 13 | false 14 | false 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/Exceptions/EntityNotFoundExceptionTests/InstantiationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Digipolis.DataAccess.Exceptions; 3 | using Xunit; 4 | 5 | namespace Digipolis.DataAccess.UnitTests.Exceptions.EntityNotFoundExceptionTests 6 | { 7 | public class InstantiationTests 8 | { 9 | [Fact] 10 | private void EntityNameIsSet() 11 | { 12 | var ex = new EntityNotFoundException("entity", 123); 13 | Assert.Equal("entity", ex.EntityName); 14 | } 15 | 16 | [Fact] 17 | private void EntityKeyIsSet() 18 | { 19 | var ex = new EntityNotFoundException("entity", 123); 20 | Assert.Equal(123, ex.EntityKey); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/Options/ConnectionStringTests/InstantiationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using Digipolis.DataAccess.Options; 4 | using Xunit; 5 | using Digipolis.DataAccess; 6 | 7 | namespace Digipolis.DataAccess.UnitTests.Options.ConnectionStringTests 8 | { 9 | public class InstantiationTests 10 | { 11 | [Fact] 12 | private void HostNullRaisesArgumentNullException() 13 | { 14 | var ex = Assert.Throws(() => new ConnectionString(null, 1234, "db", "user", "pwd")); 15 | Assert.Equal("host", ex.ParamName); 16 | } 17 | 18 | [Fact] 19 | private void HostEmptyRaisesArgumentException() 20 | { 21 | var ex = Assert.Throws(() => new ConnectionString("", 1234, "db", "user", "pwd")); 22 | Assert.Equal("host", ex.ParamName); 23 | } 24 | 25 | [Fact] 26 | private void HostWhiteSpaceRaisesArgumentException() 27 | { 28 | var ex = Assert.Throws(() => new ConnectionString(" ", 1234, "db", "user", "pwd")); 29 | Assert.Equal("host", ex.ParamName); 30 | } 31 | 32 | [Fact] 33 | private void DbNameNullRaisesArgumentNullException() 34 | { 35 | var ex = Assert.Throws(() => new ConnectionString("host", 1234, null, "user", "pwd")); 36 | Assert.Equal("dbname", ex.ParamName); 37 | } 38 | 39 | [Fact] 40 | private void DbNameEmptyRaisesArgumentException() 41 | { 42 | var ex = Assert.Throws(() => new ConnectionString("host", 1234, "", "user", "pwd")); 43 | Assert.Equal("dbname", ex.ParamName); 44 | } 45 | 46 | [Fact] 47 | private void DbNameWhiteSpaceRaisesArgumentException() 48 | { 49 | var ex = Assert.Throws(() => new ConnectionString("host", 1234, " ", "user", "pwd")); 50 | Assert.Equal("dbname", ex.ParamName); 51 | } 52 | 53 | [Fact] 54 | private void HostIsSet() 55 | { 56 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 57 | Assert.Equal("host", conn.Host); 58 | } 59 | 60 | [Fact] 61 | private void PortIsSet() 62 | { 63 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 64 | Assert.Equal(1234, conn.Port); 65 | } 66 | 67 | [Fact] 68 | private void PortZeroIsAllowed() 69 | { 70 | var conn = new ConnectionString("host", 0, "db", "user", "pwd"); 71 | Assert.Equal(0, conn.Port); 72 | } 73 | 74 | [Fact] 75 | private void DbNameIsSet() 76 | { 77 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 78 | Assert.Equal("db", conn.DbName); 79 | } 80 | 81 | [Fact] 82 | private void UserIsSet() 83 | { 84 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 85 | Assert.Equal("user", conn.User); 86 | } 87 | 88 | [Fact] 89 | private void UserNullIsAllowed() 90 | { 91 | var conn = new ConnectionString("host", 1234, "db", null, "pwd"); 92 | Assert.Null(conn.User); 93 | } 94 | 95 | [Fact] 96 | private void PasswordIsSet() 97 | { 98 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 99 | Assert.Equal("pwd", conn.Password); 100 | } 101 | 102 | [Fact] 103 | private void PasswordNullIsAllowed() 104 | { 105 | var conn = new ConnectionString("host", 1234, "db", "user", null); 106 | Assert.Null(conn.Password); 107 | } 108 | 109 | [Fact] 110 | private void DefaultHostIsLocalhost() 111 | { 112 | var conn = new ConnectionString(); 113 | Assert.Equal(Defaults.ConnectionString.Host, conn.Host); 114 | } 115 | 116 | [Fact] 117 | private void DefaultPortIsZero() 118 | { 119 | var conn = new ConnectionString(); 120 | Assert.Equal(Defaults.ConnectionString.Port, conn.Port); 121 | } 122 | 123 | [Fact] 124 | private void DefaultDbNameIsCurrentAssembly() 125 | { 126 | var conn = new ConnectionString(); 127 | Assert.Equal(Assembly.GetEntryAssembly().GetName().Name, conn.DbName); 128 | } 129 | 130 | [Fact] 131 | private void DefaultUserIsNull() 132 | { 133 | var conn = new ConnectionString(); 134 | Assert.Null(conn.User); 135 | } 136 | 137 | [Fact] 138 | private void DefaultPasswordIsNull() 139 | { 140 | var conn = new ConnectionString(); 141 | Assert.Null(conn.Password); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/Options/ConnectionStringTests/ToStringTests.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess; 2 | using System; 3 | using Xunit; 4 | 5 | namespace Digipolis.DataAccess.UnitTests.Options.ConnectionStringTests 6 | { 7 | public class ToStringTests 8 | { 9 | [Fact] 10 | private void HostIsAssignedToServer() 11 | { 12 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 13 | Assert.Contains("Server=host;", conn.ToString()); 14 | } 15 | 16 | [Fact] 17 | private void PortZeroIsNotAssigned() 18 | { 19 | var conn = new ConnectionString("host", 0, "db", "user", "pwd"); 20 | Assert.DoesNotContain("Port=0", conn.ToString()); 21 | } 22 | 23 | [Fact] 24 | private void PortIsAssignedToPort() 25 | { 26 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 27 | Assert.Contains("Port=1234;", conn.ToString()); 28 | } 29 | 30 | [Fact] 31 | private void DbNameIsAssignedToDatabase() 32 | { 33 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 34 | Assert.Contains("Database=db;", conn.ToString()); 35 | } 36 | 37 | [Fact] 38 | private void UserIsAssignedToUserId() 39 | { 40 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 41 | Assert.Contains("User Id=user;", conn.ToString()); 42 | Assert.DoesNotContain("Integrated Security", conn.ToString()); 43 | } 44 | 45 | [Fact] 46 | private void NullUserSetsIntegratedSecurity() 47 | { 48 | var conn = new ConnectionString("host", 1234, "db", null, "pwd"); 49 | Assert.Contains("Integrated Security=true;", conn.ToString()); 50 | Assert.DoesNotContain("User Id", conn.ToString()); 51 | Assert.DoesNotContain("Password", conn.ToString()); 52 | } 53 | 54 | [Fact] 55 | private void PasswordIsAssignedToPassword() 56 | { 57 | var conn = new ConnectionString("host", 1234, "db", "user", "pwd"); 58 | Assert.Contains("Password=pwd;", conn.ToString()); 59 | } 60 | 61 | [Fact] 62 | private void NullPasswordIsNotAssigned() 63 | { 64 | var conn = new ConnectionString("host", 1234, "db", "user", null); 65 | Assert.DoesNotContain("Password", conn.ToString()); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/Paging/DataPagerTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Xunit; 6 | 7 | namespace Digipolis.DataAccess.UnitTests.Paging 8 | { 9 | public class DataPagerTests 10 | { 11 | [Fact] 12 | public void GetReturnsValidDataPage() 13 | { 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("Digipolis.DataAccess.UnitTests")] 11 | [assembly: AssemblyTrademark("")] 12 | 13 | // Setting ComVisible to false makes the types in this assembly not visible 14 | // to COM components. If you need to access a type in this assembly from 15 | // COM, set the ComVisible attribute to true on that type. 16 | [assembly: ComVisible(false)] 17 | 18 | // The following GUID is for the ID of the typelib if this project is exposed to COM 19 | [assembly: Guid("ff0474ff-5844-4b0a-8b7b-47ac592bde03")] 20 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/Repositories/GenericEntityRepositoryTests.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Repositories; 2 | using Digipolis.DataAccess.UnitTests._TestObjects; 3 | using Microsoft.EntityFrameworkCore; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | using Xunit; 9 | 10 | namespace Digipolis.DataAccess.UnitTests.Repositories 11 | { 12 | public class GenericEntityRepositoryTests 13 | { 14 | private InMemoryContext _context; 15 | private IRepository _fooRepository; 16 | 17 | public GenericEntityRepositoryTests() 18 | { 19 | _fooRepository = new GenericEntityRepository(null); 20 | _context = InMemoryContext.Create(); 21 | ((IRepositoryInjection)_fooRepository).SetContext(_context); 22 | } 23 | 24 | private void AddEntitiesToContext(int count = 10) 25 | { 26 | // Add entities to context 27 | for (var i = 1; i <= count; i++) 28 | { 29 | var foo = new Foo() 30 | { 31 | Id = i 32 | }; 33 | 34 | _context.Foos.Add(foo); 35 | } 36 | 37 | _context.SaveChanges(); 38 | } 39 | 40 | [Theory] 41 | [InlineData(0)] 42 | [InlineData(10)] 43 | public void GetAllDoesNotReturnNull(int totalEntities) 44 | { 45 | // Arrange 46 | AddEntitiesToContext(totalEntities); 47 | 48 | // Act 49 | var result = _fooRepository.GetAll(); 50 | 51 | // Assert 52 | Assert.NotNull(result); 53 | } 54 | 55 | [Theory] 56 | [InlineData(0)] 57 | [InlineData(10)] 58 | public void GetAllReturnsCorrectNumberOfEntities(int totalEntities) 59 | { 60 | // Arrange 61 | AddEntitiesToContext(totalEntities); 62 | 63 | // Act 64 | var result = _fooRepository.GetAll(); 65 | 66 | // Assert 67 | Assert.Equal(totalEntities, result.Count()); 68 | } 69 | 70 | [Theory] 71 | [InlineData(0)] 72 | [InlineData(10)] 73 | public void GetAllReturnsAllEntitiesInContext(int totalEntities) 74 | { 75 | // Arrange 76 | AddEntitiesToContext(totalEntities); 77 | 78 | // Act 79 | var result = _fooRepository.GetAll(); 80 | 81 | // Assert 82 | for (int i = 1; i <= totalEntities; i++) 83 | Assert.Equal(1, result.Count(x => x.Id == i)); 84 | } 85 | 86 | [Theory] 87 | [InlineData(10)] 88 | public void GetAllSortedByIdReturnsAllEntitiesInCorrectOrder(int totalEntities) 89 | { 90 | // Arrange 91 | AddEntitiesToContext(totalEntities); 92 | 93 | // Act 94 | var result = _fooRepository.GetAll(x => x.OrderBy(y => y.Id)); 95 | 96 | // Assert 97 | var i = 0; 98 | foreach (var entity in result) 99 | { 100 | i++; 101 | Assert.Equal(i, entity.Id); 102 | } 103 | } 104 | 105 | [Theory] 106 | [InlineData(10)] 107 | public void GetAllReverseSortedByIdReturnsAllEntitiesInCorrectOrder(int totalEntities) 108 | { 109 | // Arrange 110 | AddEntitiesToContext(totalEntities); 111 | 112 | // Act 113 | var result = _fooRepository.GetAll(x => x.OrderByDescending(y => y.Id)); 114 | 115 | // Assert 116 | var i = totalEntities; 117 | foreach (var entity in result) 118 | { 119 | Assert.Equal(i, entity.Id); 120 | i--; 121 | } 122 | } 123 | 124 | [Theory] 125 | [InlineData(0, 1)] 126 | [InlineData(3, 4)] 127 | public void GetReturnsNullWhenEntityDoesNotExistInContext(int totalEntities, int id) 128 | { 129 | // Arrange 130 | AddEntitiesToContext(totalEntities); 131 | 132 | // Act 133 | var result = _fooRepository.Get(id); 134 | 135 | // Assert 136 | Assert.Null(result); 137 | } 138 | 139 | [Theory] 140 | [InlineData(3, 1)] 141 | [InlineData(3, 3)] 142 | public void GetDoesNotReturnNullWhenEntityExistsInContext(int totalEntities, int id) 143 | { 144 | // Arrange 145 | AddEntitiesToContext(totalEntities); 146 | 147 | // Act 148 | var result = _fooRepository.Get(id); 149 | 150 | // Assert 151 | Assert.NotNull(result); 152 | } 153 | 154 | [Theory] 155 | [InlineData(3, 1)] 156 | [InlineData(3, 3)] 157 | public void GetReturnsSingleEntityWithProvidedId(int totalEntities, int id) 158 | { 159 | // Arrange 160 | AddEntitiesToContext(totalEntities); 161 | 162 | // Act 163 | var result = _fooRepository.Get(id); 164 | 165 | // Assert 166 | Assert.Equal(id, result.Id); 167 | } 168 | 169 | [Theory] 170 | [InlineData(10, 0, 5)] 171 | [InlineData(10, 5, 5)] 172 | [InlineData(10, 10, 5)] 173 | public void GetPageSortedByIdDoesNotReturnNull(int totalEntities, int rowIndex, int pageSize) 174 | { 175 | // Arrange 176 | AddEntitiesToContext(totalEntities); 177 | 178 | // Act 179 | var result = _fooRepository.GetPage(rowIndex, pageSize, x => x.OrderBy(y => y.Id)); 180 | 181 | // Assert 182 | Assert.NotNull(result); 183 | } 184 | 185 | [Theory] 186 | [InlineData(10, 0, 5)] 187 | [InlineData(10, 5, 5)] 188 | [InlineData(10, 10, 5)] 189 | [InlineData(8, 5, 5)] 190 | public void GetPageSortedByIdReturnsCorrectNumberOfEntities(int totalEntities, int rowIndex, int pageSize) 191 | { 192 | // Arrange 193 | AddEntitiesToContext(totalEntities); 194 | var minId = rowIndex + 1; 195 | var maxId = Math.Min(totalEntities, minId + pageSize - 1); 196 | var expectedNumberOfEntities = Math.Max(0, maxId - minId + 1); 197 | 198 | // Act 199 | var result = _fooRepository.GetPage(rowIndex, pageSize, x => x.OrderBy(y => y.Id)); 200 | 201 | // Assert 202 | Assert.Equal(expectedNumberOfEntities, result.Count()); 203 | } 204 | 205 | [Theory] 206 | [InlineData(10, 0, 5)] 207 | [InlineData(10, 5, 5)] 208 | [InlineData(10, 10, 5)] 209 | [InlineData(8, 5, 5)] 210 | public void GetPageSortedByIdReturnsEntitiesWithCorrectIds(int totalEntities, int rowIndex, int pageSize) 211 | { 212 | // Arrange 213 | AddEntitiesToContext(totalEntities); 214 | 215 | var minId = rowIndex + 1; 216 | var maxId = Math.Min(totalEntities, minId + pageSize - 1); 217 | 218 | // Act 219 | var result = _fooRepository.GetPage(rowIndex, pageSize, x => x.OrderBy(y => y.Id)); 220 | 221 | // Assert 222 | for (int i = minId; i <= maxId; i++) 223 | Assert.Equal(1, result.Count(x => x.Id == i)); 224 | } 225 | 226 | [Theory] 227 | [InlineData(10, 1)] 228 | [InlineData(10, 5)] 229 | [InlineData(10, 10)] 230 | public void AnyByIdReturnsTrueForExistingRecord(int totalEntities, int id) 231 | { 232 | // Arrange 233 | AddEntitiesToContext(totalEntities); 234 | 235 | // Act 236 | var result = _fooRepository.Any(x => x.Id == id); 237 | 238 | // Assert 239 | Assert.True(result); 240 | } 241 | 242 | [Theory] 243 | [InlineData(10, 0)] 244 | [InlineData(10, 11)] 245 | public void AnyByIdReturnsFalseForNonExistingRecord(int totalEntities, int id) 246 | { 247 | // Arrange 248 | AddEntitiesToContext(totalEntities); 249 | 250 | // Act 251 | var result = _fooRepository.Any(x => x.Id == id); 252 | 253 | // Assert 254 | Assert.False(result); 255 | } 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/Startup/ServiceCollectionExtensionsTests/AddDataAccessOptionsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Digipolis.DataAccess.Context; 5 | using Digipolis.DataAccess.Options; 6 | using Digipolis.DataAccess.Paging; 7 | using Digipolis.DataAccess.Repositories; 8 | using Digipolis.DataAccess.Uow; 9 | using Xunit; 10 | using Digipolis.DataAccess; 11 | 12 | namespace Digipolis.DataAccess.UnitTests.Startup.ServiceCollectionExtensionsTests 13 | { 14 | public class AddDataAccessOptionsTests 15 | { 16 | [Fact] 17 | private void UowProviderIsRegisteredAsScoped() 18 | { 19 | var services = new ServiceCollection(); 20 | 21 | services.AddDataAccess(); 22 | 23 | var registrations = services.Where(sd => sd.ServiceType == typeof(IUowProvider) 24 | && sd.ImplementationType == typeof(UowProvider)) 25 | .ToArray(); 26 | Assert.Equal(1, registrations.Count()); 27 | Assert.Equal(ServiceLifetime.Scoped, registrations[0].Lifetime); 28 | } 29 | 30 | [Fact] 31 | private void GenericRepositoryIsRegisteredAsTransient() 32 | { 33 | var services = new ServiceCollection(); 34 | 35 | services.AddDataAccess(); 36 | 37 | var registrations = services.Where(sd => sd.ServiceType == typeof(IRepository<>) 38 | && sd.ImplementationType == typeof(GenericEntityRepository<>)) 39 | .ToArray(); 40 | Assert.Equal(1, registrations.Count()); 41 | Assert.Equal(ServiceLifetime.Transient, registrations[0].Lifetime); 42 | } 43 | 44 | [Fact] 45 | private void DataPagerIsRegisteredAsTransient() 46 | { 47 | var services = new ServiceCollection(); 48 | 49 | services.AddDataAccess(); 50 | 51 | var registrations = services.Where(sd => sd.ServiceType == typeof(IDataPager<>) 52 | && sd.ImplementationType == typeof(DataPager<>)) 53 | .ToArray(); 54 | Assert.Equal(1, registrations.Count()); 55 | Assert.Equal(ServiceLifetime.Transient, registrations[0].Lifetime); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/Uow/UowProviderTests.cs: -------------------------------------------------------------------------------- 1 | using Castle.Core.Logging; 2 | using Digipolis.DataAccess; 3 | using Digipolis.DataAccess.Context; 4 | using Digipolis.DataAccess.Repositories; 5 | using Digipolis.DataAccess.UnitTests._TestObjects; 6 | using Digipolis.DataAccess.Uow; 7 | using Microsoft.Extensions.Logging; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Threading.Tasks; 12 | using Xunit; 13 | 14 | namespace Digipolis.DataAccess.UnitTests.Uow 15 | { 16 | public class UowProviderTests 17 | { 18 | [Fact] 19 | public void TestGetCustomRepository() 20 | { 21 | 22 | var logger = new Moq.Mock>(); 23 | var sp = new Moq.Mock(); 24 | 25 | var myContext = new InMemoryContext(new Microsoft.EntityFrameworkCore.DbContextOptions()); 26 | 27 | sp.Setup((o) => o.GetService(typeof(IEntityContext))).Returns(myContext); 28 | sp.Setup((o) => o.GetService(typeof(IFooRepository))).Returns(new FooRepository(logger.Object, myContext)); 29 | 30 | var provider = new UowProvider(logger.Object, sp.Object); 31 | 32 | var uow = provider.CreateUnitOfWork(); 33 | 34 | uow.GetCustomRepository(); 35 | } 36 | 37 | [Fact] 38 | public void TestGetGenericRepository() 39 | { 40 | 41 | var logger = new Moq.Mock>(); 42 | var sp = new Moq.Mock(); 43 | 44 | var myContext = new InMemoryContext(new Microsoft.EntityFrameworkCore.DbContextOptions()); 45 | 46 | sp.Setup((o) => o.GetService(typeof(IEntityContext))).Returns(myContext); 47 | sp.Setup((o) => o.GetService(typeof(IRepository))).Returns(new GenericEntityRepository(logger.Object)); 48 | 49 | var provider = new UowProvider(logger.Object, sp.Object); 50 | 51 | var uow = provider.CreateUnitOfWork(); 52 | 53 | uow.GetRepository(); 54 | } 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/_TestData/dbconfig1.json: -------------------------------------------------------------------------------- 1 | { 2 | "DataAccess": { 3 | "ConnectionString": { 4 | "Host": "testhost", 5 | "Port": "5555", 6 | "DbName": "testdb", 7 | "User": "testuser", 8 | "Password": "testpwd" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/_TestData/dbconfig2.json: -------------------------------------------------------------------------------- 1 | { 2 | "DataAccess": { 3 | "ConnectionString": { 4 | "Host": "testhost", 5 | "Port": "5555", 6 | "DbName": "testdb", 7 | "User": "testuser", 8 | "Password": "testpwd" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/_TestObjects/Foo.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace Digipolis.DataAccess.UnitTests._TestObjects 8 | { 9 | public class Foo : EntityBase 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/_TestObjects/FooRepository.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Repositories; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace Digipolis.DataAccess.UnitTests._TestObjects 9 | { 10 | public class FooRepository : EntityRepositoryBase, IFooRepository 11 | { 12 | public FooRepository(ILogger logger, InMemoryContext context) : base(logger, context) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/_TestObjects/IFooRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Digipolis.DataAccess.UnitTests._TestObjects 7 | { 8 | public interface IFooRepository 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/_TestObjects/InMemoryContext.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Context; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.EntityFrameworkCore; 7 | using Microsoft.Extensions.DependencyInjection; 8 | 9 | namespace Digipolis.DataAccess.UnitTests._TestObjects 10 | { 11 | public class InMemoryContext : EntityContextBase 12 | { 13 | public InMemoryContext(DbContextOptions options) 14 | : base(options) 15 | { 16 | } 17 | 18 | public DbSet Foos { get; set; } 19 | 20 | public static InMemoryContext Create() 21 | { 22 | // Create a fresh service provider, and therefore a fresh 23 | // InMemory database instance. 24 | var serviceProvider = new ServiceCollection() 25 | .AddEntityFrameworkInMemoryDatabase() 26 | .BuildServiceProvider(); 27 | 28 | // Create a new options instance telling the context to use an 29 | // InMemory database and the new service provider. 30 | var builder = new DbContextOptionsBuilder(); 31 | builder.UseInMemoryDatabase() 32 | .UseInternalServiceProvider(serviceProvider); 33 | 34 | return new InMemoryContext(builder.Options); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/Digipolis.DataAccess.UnitTests/_TestObjects/TestContext.cs: -------------------------------------------------------------------------------- 1 | using Digipolis.DataAccess.Context; 2 | using Microsoft.EntityFrameworkCore; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace Digipolis.DataAccess.UnitTests 9 | { 10 | public class TestContext : EntityContextBase 11 | { 12 | public TestContext(DbContextOptions options) 13 | : base(options) 14 | { } 15 | } 16 | } 17 | --------------------------------------------------------------------------------