├── .gitattributes
├── .gitignore
├── CHANGELOG.md
├── EFRepository.Tests
├── App.config
├── EFRepository.Tests.csproj
├── Hooks
│ ├── SoftDelete.feature
│ ├── SoftDelete.feature.cs
│ ├── SoftDeleteSteps.cs
│ ├── SystemInfo.feature
│ ├── SystemInfo.feature.cs
│ └── SystemInfoSteps.cs
├── Properties
│ └── AssemblyInfo.cs
├── Repositories
│ ├── GenericRepository.feature
│ ├── GenericRepository.feature.cs
│ └── GenericRepositorySteps.cs
├── TestClasses
│ ├── SoftDeleteData.cs
│ ├── SoftDeleteRepository.cs
│ ├── SystemInfoData.cs
│ ├── SystemInfoRepository.cs
│ ├── TestData.cs
│ ├── TestDbContext.cs
│ └── TestRepository.cs
└── packages.config
├── EFRepository.sln
├── EFRepository
├── App.config
├── DatetimeHelper.cs
├── EFRepository.csproj
├── GenericRepository.cs
├── Hooks
│ ├── HookContext.cs
│ ├── IPostActionHook.cs
│ ├── IPostLoadHook.cs
│ ├── SoftDeletePostActionHook.cs
│ ├── SoftDeletePostLoadHook.cs
│ └── SystemInfoPostActionHook.cs
├── IDatetimeHelper.cs
├── IEntity.cs
├── IRepository.cs
├── ISoftDelete.cs
├── ISystemInfo.cs
├── IUserHelper.cs
├── Properties
│ └── AssemblyInfo.cs
├── UnitOfWork.cs
└── packages.config
├── LICENSE
├── README.md
├── appveyor.yml
├── nuget
└── KirkChen.EFRepository.nuspec
├── package.json
└── tools
├── build.bat
├── buildfinish.bat
├── buildpullrequest.bat
├── generateDocs.bat
├── packNuget.bat
├── packPrereleaseNuget.bat
└── pushDocs.ps1
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 | [Tt]estDocs/
34 |
35 | # NUNIT
36 | *.VisualState.xml
37 | TestResult.xml
38 |
39 | # OpenCover
40 | CodeCoverage.xml
41 |
42 | # SonarQube
43 | .sonarqube/
44 |
45 | # Build Results of an ATL Project
46 | [Dd]ebugPS/
47 | [Rr]eleasePS/
48 | dlldata.c
49 |
50 | # DNX
51 | project.lock.json
52 | artifacts/
53 |
54 | *_i.c
55 | *_p.c
56 | *_i.h
57 | *.ilk
58 | *.meta
59 | *.obj
60 | *.pch
61 | *.pdb
62 | *.pgc
63 | *.pgd
64 | *.rsp
65 | *.sbr
66 | *.tlb
67 | *.tli
68 | *.tlh
69 | *.tmp
70 | *.tmp_proj
71 | *.log
72 | *.vspscc
73 | *.vssscc
74 | .builds
75 | *.pidb
76 | *.svclog
77 | *.scc
78 |
79 | # Chutzpah Test files
80 | _Chutzpah*
81 |
82 | # Visual C++ cache files
83 | ipch/
84 | *.aps
85 | *.ncb
86 | *.opendb
87 | *.opensdf
88 | *.sdf
89 | *.cachefile
90 | *.VC.db
91 |
92 | # Visual Studio profiler
93 | *.psess
94 | *.vsp
95 | *.vspx
96 | *.sap
97 |
98 | # TFS 2012 Local Workspace
99 | $tf/
100 |
101 | # Guidance Automation Toolkit
102 | *.gpState
103 |
104 | # ReSharper is a .NET coding add-in
105 | _ReSharper*/
106 | *.[Rr]e[Ss]harper
107 | *.DotSettings.user
108 |
109 | # JustCode is a .NET coding add-in
110 | .JustCode
111 |
112 | # TeamCity is a build add-in
113 | _TeamCity*
114 |
115 | # DotCover is a Code Coverage Tool
116 | *.dotCover
117 |
118 | # NCrunch
119 | _NCrunch_*
120 | .*crunch*.local.xml
121 | nCrunchTemp_*
122 |
123 | # MightyMoose
124 | *.mm.*
125 | AutoTest.Net/
126 |
127 | # Web workbench (sass)
128 | .sass-cache/
129 |
130 | # Installshield output folder
131 | [Ee]xpress/
132 |
133 | # DocProject is a documentation generator add-in
134 | DocProject/buildhelp/
135 | DocProject/Help/*.HxT
136 | DocProject/Help/*.HxC
137 | DocProject/Help/*.hhc
138 | DocProject/Help/*.hhk
139 | DocProject/Help/*.hhp
140 | DocProject/Help/Html2
141 | DocProject/Help/html
142 |
143 | # Click-Once directory
144 | publish/
145 |
146 | # Publish Web Output
147 | *.[Pp]ublish.xml
148 | *.azurePubxml
149 |
150 | # TODO: Un-comment the next line if you do not want to checkin
151 | # your web deploy settings because they may include unencrypted
152 | # passwords
153 | #*.pubxml
154 | *.publishproj
155 |
156 | # NuGet Packages
157 | *.nupkg
158 | # The packages folder can be ignored because of Package Restore
159 | **/packages/*
160 | # except build/, which is used as an MSBuild target.
161 | !**/packages/build/
162 | # Uncomment if necessary however generally it will be regenerated when needed
163 | #!**/packages/repositories.config
164 | # NuGet v3's project.json files produces more ignoreable files
165 | *.nuget.props
166 | *.nuget.targets
167 |
168 | # Microsoft Azure Build Output
169 | csx/
170 | *.build.csdef
171 |
172 | # Microsoft Azure Emulator
173 | ecf/
174 | rcf/
175 |
176 | # Microsoft Azure ApplicationInsights config file
177 | ApplicationInsights.config
178 |
179 | # Windows Store app package directory
180 | AppPackages/
181 | BundleArtifacts/
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | [Ss]tyle[Cc]op.*
192 | ~$*
193 | *~
194 | *.dbmdl
195 | *.dbproj.schemaview
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # RIA/Silverlight projects
202 | Generated_Code/
203 |
204 | # Backup & report files from converting an old project file
205 | # to a newer Visual Studio version. Backup files are not needed,
206 | # because we have git ;-)
207 | _UpgradeReport_Files/
208 | Backup*/
209 | UpgradeLog*.XML
210 | UpgradeLog*.htm
211 |
212 | # SQL Server files
213 | *.mdf
214 | *.ldf
215 |
216 | # Business Intelligence projects
217 | *.rdl.data
218 | *.bim.layout
219 | *.bim_*.settings
220 |
221 | # Microsoft Fakes
222 | FakesAssemblies/
223 |
224 | # GhostDoc plugin setting file
225 | *.GhostDoc.xml
226 |
227 | # Node.js Tools for Visual Studio
228 | .ntvs_analysis.dat
229 |
230 | # Visual Studio 6 build log
231 | *.plg
232 |
233 | # Visual Studio 6 workspace options file
234 | *.opt
235 |
236 | # Visual Studio LightSwitch build output
237 | **/*.HTMLClient/GeneratedArtifacts
238 | **/*.DesktopClient/GeneratedArtifacts
239 | **/*.DesktopClient/ModelManifest.xml
240 | **/*.Server/GeneratedArtifacts
241 | **/*.Server/ModelManifest.xml
242 | _Pvt_Extensions
243 |
244 | # LightSwitch generated files
245 | GeneratedArtifacts/
246 | ModelManifest.xml
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 |
251 | # FAKE - F# Make
252 | .fake/
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 | # 1.0.0 (2016-08-07)
3 |
4 |
5 | ### Features
6 |
7 | * **hook:** Implement system infomation hook ([400c0dd](https://github.com/kirkchen/EFRepository/commit/400c0dd))
8 | * **hook:** Implement soft delete ([9c7f7cb](https://github.com/kirkchen/EFRepository/commit/9c7f7cb))
9 | * **library:** Initial project ([48d7abe](https://github.com/kirkchen/EFRepository/commit/48d7abe))
10 | * **library:** Install required packages ([30438c5](https://github.com/kirkchen/EFRepository/commit/30438c5))
11 | * **repository:** Add add range funciton to interface ([78324bb](https://github.com/kirkchen/EFRepository/commit/78324bb))
12 | * **repository:** Implement add range ([8191654](https://github.com/kirkchen/EFRepository/commit/8191654))
13 | * **repository:** Implement delete feature ([bf32d82](https://github.com/kirkchen/EFRepository/commit/bf32d82))
14 | * **repository:** Implement get data by id feature ([86a7993](https://github.com/kirkchen/EFRepository/commit/86a7993))
15 | * **repository:** Implement get data with condition feature ([f4f16a9](https://github.com/kirkchen/EFRepository/commit/f4f16a9))
16 | * **repository:** Implement get list feature ([5a6aae0](https://github.com/kirkchen/EFRepository/commit/5a6aae0))
17 | * **repository:** Implement get list with condition feature ([2df7800](https://github.com/kirkchen/EFRepository/commit/2df7800))
18 | * **repository:** Implement repository add ([a7d7dcf](https://github.com/kirkchen/EFRepository/commit/a7d7dcf))
19 | * **repository:** Implement update data feature ([d504caa](https://github.com/kirkchen/EFRepository/commit/d504caa))
20 | * **repository:** Make repository key generic ([2490cb1](https://github.com/kirkchen/EFRepository/commit/2490cb1))
21 | * **unitofwork:** Add unitofwork class to support unit of work ([4b3fe72](https://github.com/kirkchen/EFRepository/commit/4b3fe72))
22 | * **unitofwork:** Remove dbcontext reference when disposing ([3456ca9](https://github.com/kirkchen/EFRepository/commit/3456ca9))
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/EFRepository.Tests/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/EFRepository.Tests/EFRepository.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {BC65819A-550B-4DA1-9AD4-A29EE244AD21}
7 | Library
8 | Properties
9 | EFRepository.Tests
10 | EFRepository.Tests
11 | v4.6.1
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 | ..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll
40 | True
41 |
42 |
43 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll
44 | True
45 |
46 |
47 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll
48 | True
49 |
50 |
51 | ..\packages\Moq.4.5.16\lib\net45\Moq.dll
52 | True
53 |
54 |
55 |
56 |
57 | ..\packages\SpecFlow.2.1.0\lib\net45\TechTalk.SpecFlow.dll
58 | True
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | True
76 | True
77 | GenericRepository.feature
78 |
79 |
80 |
81 |
82 | True
83 | True
84 | SoftDelete.feature
85 |
86 |
87 |
88 | True
89 | True
90 | SystemInfo.feature
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | SpecFlowSingleFileGenerator
105 | GenericRepository.feature.cs
106 |
107 |
108 |
109 | SpecFlowSingleFileGenerator
110 | SoftDelete.feature.cs
111 |
112 |
113 | SpecFlowSingleFileGenerator
114 | SystemInfo.feature.cs
115 |
116 |
117 |
118 |
119 | {3d6fc108-03ab-47e5-96c5-401cb8793bd7}
120 | EFRepository
121 |
122 |
123 |
124 |
125 |
126 |
127 | False
128 |
129 |
130 | False
131 |
132 |
133 | False
134 |
135 |
136 | False
137 |
138 |
139 |
140 |
141 |
142 |
143 |
150 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Hooks/SoftDelete.feature:
--------------------------------------------------------------------------------
1 | @Hook
2 | Feature: SoftDelete
3 |
4 | As a programmer
5 | In order to update IsDelete property in data class instead of delete data in the database
6 | I would like to use soft delete hook to handle soft delete logic
7 |
8 | How to use?
9 | --------
10 |
11 | 1. Create data class inherits **ISoftDelete**
12 |
13 | public class SoftDeleteData : IEntity, ISoftDelete
14 | {
15 | [Key]
16 | public int Id { get; set; }
17 |
18 | public string Content { get; set; }
19 |
20 | public bool IsDelete { get; set; }
21 | }
22 |
23 | 1. Create repository inherits **Generic repository** and register **Soft delete hook**
24 |
25 | public class SoftDeleteRepository : GenericRepository, IRepository
26 | {
27 | public SoftDeleteRepository(MyDbContext context)
28 | : base(context)
29 | {
30 | this.RegisterPostLoadHook(new SoftDeletePostLoadHook());
31 | this.RegisterPostActionHook(new SoftDeletePostActionHook());
32 | }
33 | }
34 |
35 | 1. Use repository
36 |
37 | using(var dbContext = new MyDbContext())
38 | {
39 | var repository = new SoftDeleteRepository(dbContext);
40 |
41 | //// Will update IsDelete to true
42 | repository.Delete(1);
43 |
44 | or
45 |
46 | //// Will only get data with IsDelete=false
47 | var myData = repository.Get(1);
48 | }
49 |
50 | Scenarios
51 | --------
52 |
53 | Scenario: Get datalist from database should filter IsDelete=true if data is soft delete
54 | Given database has soft delete datas
55 | | Id | Content | IsDelete |
56 | | 1 | TestData | true |
57 | | 2 | TestData 2 | false |
58 | And Register soft delete hook in generic repository
59 | When I use generic repository get data list from database
60 | Then the data list I get should be
61 | | Id | Content |
62 | | 2 | TestData 2 |
63 |
64 | Scenario: Get datalist from database with condition content should contains "2" should filter IsDelete=true if data is soft delete
65 | Given database has soft delete datas
66 | | Id | Content | IsDelete |
67 | | 1 | TestData | true |
68 | | 2 | TestData 2 | false |
69 | | 3 | TestData 2 | true |
70 | And test datas content field should contains "2"
71 | And Register soft delete hook in generic repository
72 | When I use generic repository get data list with condition from database
73 | Then the data list I get should be
74 | | Id | Content |
75 | | 2 | TestData 2 |
76 |
77 | Scenario: Get data from database should filter IsDelete=true if data is soft delete
78 | Given database has soft delete datas
79 | | Id | Content | IsDelete |
80 | | 1 | TestData | true |
81 | | 2 | TestData 2 | false |
82 | And Register soft delete hook in generic repository
83 | When I use generic repository get data from database by id "1"
84 | Then the data list I get should be empty
85 |
86 | Scenario: Get data from database with condition content should contains "2" should filter IsDelete=true if data is soft delete
87 | Given database has soft delete datas
88 | | Id | Content | IsDelete |
89 | | 1 | TestData | true |
90 | | 2 | TestData 2 | true |
91 | | 3 | TestData 2 | false |
92 | And test datas content field should contains "2"
93 | And Register soft delete hook in generic repository
94 | When I use generic repository get data from database with conditon
95 | Then the data list I get should be
96 | | Id | Content |
97 | | 3 | TestData 2 |
98 |
99 | Scenario: Delete data will be replaced by update IsDelete field
100 | Given database has soft delete datas
101 | | Id | Content | IsDelete |
102 | | 1 | TestData | false |
103 | | 2 | TestData 2 | false |
104 | And Register soft delete hook in generic repository
105 | When I use generic repository delete data with id "1"
106 | And I save the changes
107 | Then database should exists test datas
108 | | Id | Content | Is delete |
109 | | 1 | TestData | true |
110 | | 2 | TestData 2 | false |
111 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Hooks/SoftDelete.feature.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------------
2 | //
3 | // This code was generated by SpecFlow (http://www.specflow.org/).
4 | // SpecFlow Version:2.1.0.0
5 | // SpecFlow Generator Version:2.0.0.0
6 | //
7 | // Changes to this file may cause incorrect behavior and will be lost if
8 | // the code is regenerated.
9 | //
10 | // ------------------------------------------------------------------------------
11 | #region Designer generated code
12 | #pragma warning disable
13 | namespace EFRepository.Tests.Hooks
14 | {
15 | using TechTalk.SpecFlow;
16 |
17 |
18 | [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.1.0.0")]
19 | [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
20 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute()]
21 | public partial class SoftDeleteFeature
22 | {
23 |
24 | private static TechTalk.SpecFlow.ITestRunner testRunner;
25 |
26 | #line 1 "SoftDelete.feature"
27 | #line hidden
28 |
29 | [Microsoft.VisualStudio.TestTools.UnitTesting.ClassInitializeAttribute()]
30 | public static void FeatureSetup(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext testContext)
31 | {
32 | testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(null, 0);
33 | TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "SoftDelete", @"As a programmer
34 | In order to update IsDelete property in data class instead of delete data in the database
35 | I would like to use soft delete hook to handle soft delete logic
36 |
37 | How to use?
38 | --------
39 |
40 | 1. Create data class inherits **ISoftDelete**
41 |
42 | public class SoftDeleteData : IEntity, ISoftDelete
43 | {
44 | [Key]
45 | public int Id { get; set; }
46 |
47 | public string Content { get; set; }
48 |
49 | public bool IsDelete { get; set; }
50 | }
51 |
52 | 1. Create repository inherits **Generic repository** and register **Soft delete hook**
53 |
54 | public class SoftDeleteRepository : GenericRepository, IRepository
55 | {
56 | public SoftDeleteRepository(MyDbContext context)
57 | : base(context)
58 | {
59 | this.RegisterPostLoadHook(new SoftDeletePostLoadHook());
60 | this.RegisterPostActionHook(new SoftDeletePostActionHook());
61 | }
62 | }
63 |
64 | 1. Use repository
65 |
66 | using(var dbContext = new MyDbContext())
67 | {
68 | var repository = new SoftDeleteRepository(dbContext);
69 |
70 | //// Will update IsDelete to true
71 | repository.Delete(1);
72 |
73 | or
74 |
75 | //// Will only get data with IsDelete=false
76 | var myData = repository.Get(1);
77 | }
78 |
79 | Scenarios
80 | --------", ProgrammingLanguage.CSharp, new string[] {
81 | "Hook"});
82 | testRunner.OnFeatureStart(featureInfo);
83 | }
84 |
85 | [Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupAttribute()]
86 | public static void FeatureTearDown()
87 | {
88 | testRunner.OnFeatureEnd();
89 | testRunner = null;
90 | }
91 |
92 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute()]
93 | public virtual void TestInitialize()
94 | {
95 | if (((testRunner.FeatureContext != null)
96 | && (testRunner.FeatureContext.FeatureInfo.Title != "SoftDelete")))
97 | {
98 | EFRepository.Tests.Hooks.SoftDeleteFeature.FeatureSetup(null);
99 | }
100 | }
101 |
102 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCleanupAttribute()]
103 | public virtual void ScenarioTearDown()
104 | {
105 | testRunner.OnScenarioEnd();
106 | }
107 |
108 | public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo)
109 | {
110 | testRunner.OnScenarioStart(scenarioInfo);
111 | }
112 |
113 | public virtual void ScenarioCleanup()
114 | {
115 | testRunner.CollectScenarioErrors();
116 | }
117 |
118 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
119 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Get datalist from database should filter IsDelete=true if data is soft delete")]
120 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SoftDelete")]
121 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Hook")]
122 | public virtual void GetDatalistFromDatabaseShouldFilterIsDeleteTrueIfDataIsSoftDelete()
123 | {
124 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Get datalist from database should filter IsDelete=true if data is soft delete", ((string[])(null)));
125 | #line 53
126 | this.ScenarioSetup(scenarioInfo);
127 | #line hidden
128 | TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] {
129 | "Id",
130 | "Content",
131 | "IsDelete"});
132 | table1.AddRow(new string[] {
133 | "1",
134 | "TestData",
135 | "true"});
136 | table1.AddRow(new string[] {
137 | "2",
138 | "TestData 2",
139 | "false"});
140 | #line 54
141 | testRunner.Given("database has soft delete datas", ((string)(null)), table1, "Given ");
142 | #line 58
143 | testRunner.And("Register soft delete hook in generic repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
144 | #line 59
145 | testRunner.When("I use generic repository get data list from database", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
146 | #line hidden
147 | TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] {
148 | "Id",
149 | "Content"});
150 | table2.AddRow(new string[] {
151 | "2",
152 | "TestData 2"});
153 | #line 60
154 | testRunner.Then("the data list I get should be", ((string)(null)), table2, "Then ");
155 | #line hidden
156 | this.ScenarioCleanup();
157 | }
158 |
159 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
160 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Get datalist from database with condition content should contains \"2\" should filt" +
161 | "er IsDelete=true if data is soft delete")]
162 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SoftDelete")]
163 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Hook")]
164 | public virtual void GetDatalistFromDatabaseWithConditionContentShouldContains2ShouldFilterIsDeleteTrueIfDataIsSoftDelete()
165 | {
166 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Get datalist from database with condition content should contains \"2\" should filt" +
167 | "er IsDelete=true if data is soft delete", ((string[])(null)));
168 | #line 64
169 | this.ScenarioSetup(scenarioInfo);
170 | #line hidden
171 | TechTalk.SpecFlow.Table table3 = new TechTalk.SpecFlow.Table(new string[] {
172 | "Id",
173 | "Content",
174 | "IsDelete"});
175 | table3.AddRow(new string[] {
176 | "1",
177 | "TestData",
178 | "true"});
179 | table3.AddRow(new string[] {
180 | "2",
181 | "TestData 2",
182 | "false"});
183 | table3.AddRow(new string[] {
184 | "3",
185 | "TestData 2",
186 | "true"});
187 | #line 65
188 | testRunner.Given("database has soft delete datas", ((string)(null)), table3, "Given ");
189 | #line 70
190 | testRunner.And("test datas content field should contains \"2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
191 | #line 71
192 | testRunner.And("Register soft delete hook in generic repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
193 | #line 72
194 | testRunner.When("I use generic repository get data list with condition from database", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
195 | #line hidden
196 | TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] {
197 | "Id",
198 | "Content"});
199 | table4.AddRow(new string[] {
200 | "2",
201 | "TestData 2"});
202 | #line 73
203 | testRunner.Then("the data list I get should be", ((string)(null)), table4, "Then ");
204 | #line hidden
205 | this.ScenarioCleanup();
206 | }
207 |
208 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
209 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Get data from database should filter IsDelete=true if data is soft delete")]
210 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SoftDelete")]
211 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Hook")]
212 | public virtual void GetDataFromDatabaseShouldFilterIsDeleteTrueIfDataIsSoftDelete()
213 | {
214 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Get data from database should filter IsDelete=true if data is soft delete", ((string[])(null)));
215 | #line 77
216 | this.ScenarioSetup(scenarioInfo);
217 | #line hidden
218 | TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] {
219 | "Id",
220 | "Content",
221 | "IsDelete"});
222 | table5.AddRow(new string[] {
223 | "1",
224 | "TestData",
225 | "true"});
226 | table5.AddRow(new string[] {
227 | "2",
228 | "TestData 2",
229 | "false"});
230 | #line 78
231 | testRunner.Given("database has soft delete datas", ((string)(null)), table5, "Given ");
232 | #line 82
233 | testRunner.And("Register soft delete hook in generic repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
234 | #line 83
235 | testRunner.When("I use generic repository get data from database by id \"1\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
236 | #line 84
237 | testRunner.Then("the data list I get should be empty", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
238 | #line hidden
239 | this.ScenarioCleanup();
240 | }
241 |
242 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
243 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Get data from database with condition content should contains \"2\" should filter I" +
244 | "sDelete=true if data is soft delete")]
245 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SoftDelete")]
246 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Hook")]
247 | public virtual void GetDataFromDatabaseWithConditionContentShouldContains2ShouldFilterIsDeleteTrueIfDataIsSoftDelete()
248 | {
249 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Get data from database with condition content should contains \"2\" should filter I" +
250 | "sDelete=true if data is soft delete", ((string[])(null)));
251 | #line 86
252 | this.ScenarioSetup(scenarioInfo);
253 | #line hidden
254 | TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] {
255 | "Id",
256 | "Content",
257 | "IsDelete"});
258 | table6.AddRow(new string[] {
259 | "1",
260 | "TestData",
261 | "true"});
262 | table6.AddRow(new string[] {
263 | "2",
264 | "TestData 2",
265 | "true"});
266 | table6.AddRow(new string[] {
267 | "3",
268 | "TestData 2",
269 | "false"});
270 | #line 87
271 | testRunner.Given("database has soft delete datas", ((string)(null)), table6, "Given ");
272 | #line 92
273 | testRunner.And("test datas content field should contains \"2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
274 | #line 93
275 | testRunner.And("Register soft delete hook in generic repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
276 | #line 94
277 | testRunner.When("I use generic repository get data from database with conditon", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
278 | #line hidden
279 | TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] {
280 | "Id",
281 | "Content"});
282 | table7.AddRow(new string[] {
283 | "3",
284 | "TestData 2"});
285 | #line 95
286 | testRunner.Then("the data list I get should be", ((string)(null)), table7, "Then ");
287 | #line hidden
288 | this.ScenarioCleanup();
289 | }
290 |
291 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
292 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Delete data will be replaced by update IsDelete field")]
293 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SoftDelete")]
294 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Hook")]
295 | public virtual void DeleteDataWillBeReplacedByUpdateIsDeleteField()
296 | {
297 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Delete data will be replaced by update IsDelete field", ((string[])(null)));
298 | #line 99
299 | this.ScenarioSetup(scenarioInfo);
300 | #line hidden
301 | TechTalk.SpecFlow.Table table8 = new TechTalk.SpecFlow.Table(new string[] {
302 | "Id",
303 | "Content",
304 | "IsDelete"});
305 | table8.AddRow(new string[] {
306 | "1",
307 | "TestData",
308 | "false"});
309 | table8.AddRow(new string[] {
310 | "2",
311 | "TestData 2",
312 | "false"});
313 | #line 100
314 | testRunner.Given("database has soft delete datas", ((string)(null)), table8, "Given ");
315 | #line 104
316 | testRunner.And("Register soft delete hook in generic repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
317 | #line 105
318 | testRunner.When("I use generic repository delete data with id \"1\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
319 | #line 106
320 | testRunner.And("I save the changes", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
321 | #line hidden
322 | TechTalk.SpecFlow.Table table9 = new TechTalk.SpecFlow.Table(new string[] {
323 | "Id",
324 | "Content",
325 | "Is delete"});
326 | table9.AddRow(new string[] {
327 | "1",
328 | "TestData",
329 | "true"});
330 | table9.AddRow(new string[] {
331 | "2",
332 | "TestData 2",
333 | "false"});
334 | #line 107
335 | testRunner.Then("database should exists test datas", ((string)(null)), table9, "Then ");
336 | #line hidden
337 | this.ScenarioCleanup();
338 | }
339 | }
340 | }
341 | #pragma warning restore
342 | #endregion
343 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Hooks/SoftDeleteSteps.cs:
--------------------------------------------------------------------------------
1 | using EFRepository.Hooks;
2 | using EFRepository.Tests.TestClasses;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Linq.Expressions;
8 | using TechTalk.SpecFlow;
9 | using TechTalk.SpecFlow.Assist;
10 |
11 | namespace EFRepository.Tests.Hooks
12 | {
13 | [Binding]
14 | [Scope(Feature = "SoftDelete")]
15 | public class SoftDeleteSteps
16 | {
17 | public string ConnectionString { get; private set; }
18 |
19 | public TestDbContext DbContext { get; private set; }
20 |
21 | public SoftDeleteRepository Repository { get; private set; }
22 |
23 | public Expression> Condition { get; set; }
24 |
25 | public SoftDeleteData DataItem { get; private set; }
26 |
27 | public IEnumerable DataList { get; private set; }
28 |
29 | [BeforeScenario]
30 | public void BeforeScenario()
31 | {
32 | this.ConnectionString = Environment.GetEnvironmentVariable("TestDb") ?? "TestDb";
33 |
34 | this.DbContext = new TestDbContext(ConnectionString);
35 | this.DbContext.Database.Delete();
36 |
37 | this.Repository = new SoftDeleteRepository(this.DbContext);
38 | }
39 |
40 | [AfterScenario]
41 | public void AfterScenario()
42 | {
43 | this.DbContext.Dispose();
44 | }
45 |
46 | [Given(@"database has soft delete datas")]
47 | public void GivenDatabaseHasSoftDeleteDatas(Table table)
48 | {
49 | var dataList = table.CreateSet();
50 |
51 | using (var dbContext = new TestDbContext(this.ConnectionString))
52 | {
53 | dbContext.SoftDeleteDatas.AddRange(dataList);
54 | dbContext.SaveChanges();
55 | }
56 | }
57 |
58 | [Given(@"Register soft delete hook in generic repository")]
59 | public void GivenRegisterSoftDeleteHookInGenericRepository()
60 | {
61 | this.Repository.RegisterPostLoadHook(new SoftDeletePostLoadHook());
62 | this.Repository.RegisterPostActionHook(new SoftDeletePostActionHook());
63 | }
64 |
65 | [Given(@"test datas content field should contains ""(.*)""")]
66 | public void GivenTestDatasContentFieldShouldContains(string condition)
67 | {
68 | this.Condition = (data) => data.Content.Contains(condition);
69 | }
70 |
71 | [When(@"I use generic repository delete data with id ""(.*)""")]
72 | public void WhenIUseGenericRepositoryDeleteDataWithId(int id)
73 | {
74 | this.Repository.Delete(id);
75 | }
76 |
77 | [When(@"I use generic repository get data list from database")]
78 | public void WhenIUseGenericRepositoryGetDataListFromDatabase()
79 | {
80 | this.DataList = this.Repository.GetList();
81 | }
82 |
83 | [When(@"I use generic repository get data list with condition from database")]
84 | public void WhenIUseGenericRepositoryGetDataListWithConditionFromDatabase()
85 | {
86 | this.DataList = this.Repository.GetList(this.Condition);
87 | }
88 |
89 | [When(@"I use generic repository get data from database by id ""(.*)""")]
90 | public void WhenIUseGenericRepositoryGetDataFromDatabaseById(int id)
91 | {
92 | this.DataItem = this.Repository.Get(id);
93 |
94 | if (this.DataItem != null)
95 | {
96 | this.DataList = new List() { this.DataItem };
97 | }
98 | }
99 |
100 | [When(@"I use generic repository get data from database with conditon")]
101 | public void WhenIUseGenericRepositoryGetDataFromDatabaseWithConditon()
102 | {
103 | this.DataItem = this.Repository.Get(this.Condition);
104 |
105 | if (this.DataItem != null)
106 | {
107 | this.DataList = new List() { this.DataItem };
108 | }
109 | }
110 |
111 |
112 | [When(@"I save the changes")]
113 | public void WhenISaveTheChanges()
114 | {
115 | this.Repository.SaveChanges();
116 | }
117 |
118 | [Then(@"database should exists test datas")]
119 | public void ThenDatabaseShouldExistsTestDatas(Table table)
120 | {
121 | using (var dbContext = new TestDbContext(this.ConnectionString))
122 | {
123 | var datalist = dbContext.SoftDeleteDatas.ToList();
124 |
125 | table.CompareToSet(datalist);
126 | }
127 | }
128 |
129 | [Then(@"the data list I get should be")]
130 | public void ThenTheDataListIGetShouldBe(Table table)
131 | {
132 | table.CompareToSet(this.DataList);
133 | }
134 |
135 | [Then(@"the data list I get should be empty")]
136 | public void ThenTheDataListIGetShouldBeEmpty()
137 | {
138 | Assert.IsNull(this.DataList);
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Hooks/SystemInfo.feature:
--------------------------------------------------------------------------------
1 | @Hook
2 | Feature: SystemInfo
3 |
4 | As a programmer
5 | In order to auto assign required system information when insert or update data
6 | I would like to use use system info hook to handle assign system infomation logic
7 |
8 | How to use?
9 | --------
10 |
11 | 1. Create data class inherits **ISystemInfo**
12 |
13 | public class SystemInfoData : IEntity, ISystemInfo
14 | {
15 | [Key]
16 | public int Id { get; set; }
17 |
18 | public string Content { get; set; }
19 |
20 | public DateTime CreatedAt { get; set; }
21 |
22 | public string CreatedBy { get; set; }
23 |
24 | public DateTime UpdatedAt { get; set; }
25 |
26 | public string UpdatedBy { get; set; }
27 | }
28 |
29 | 1. Create **UserHelper** class to get current username in your system
30 |
31 | public class UserHelper: IUserHelper
32 | {
33 | public string GetUserName()
34 | {
35 | //// Implement your system user name logic
36 | return HttpContext.Current.User.Name;
37 | }
38 | }
39 |
40 | 1. Create repository inherits **Generic repository** and register **System info hook**
41 |
42 | public class SystemInfoRepository : GenericRepository, IRepository
43 | {
44 | public SystemInfoRepository(MyDbContext context)
45 | : base(context)
46 | {
47 | this.Repository.RegisterPostActionHook(new SystemInfoPostActionHook(new UserHelper(), new DatetimeHelper()));
48 | }
49 | }
50 |
51 | 1. Use repository
52 |
53 | using(var dbContext = new MyDbContext())
54 | {
55 | var repository = new SoftDeleteRepository(dbContext);
56 |
57 | //// Will auto update required system info field
58 | repository.Add(myData);
59 |
60 | or
61 |
62 | //// Will auto update required system info field
63 | repository.Update(myData);
64 | }
65 |
66 | Scenarios
67 | --------
68 |
69 | Scenario: Add data into database should be success and auto assign system required infomation
70 | Given I have systemInfo datas
71 | | Id | Content |
72 | | 1 | TestData |
73 | And Current user is "John"
74 | And Current datetime is "2016/08/05 16:00:00"
75 | And Register system info hook in generic repository
76 | When I use generic repository to add data
77 | And I save the changes
78 | Then database should exists test datas
79 | | Id | Content | CreatedAt | CreatedBy | UpdatedAt | UpdatedBy |
80 | | 1 | TestData | 2016/08/05 16:00:00 | John | 2016/08/05 16:00:00 | John |
81 |
82 | Scenario: Add datalist into database should be success and auto assign system required infomation
83 | Given I have systemInfo datas
84 | | Id | Content |
85 | | 1 | TestData |
86 | | 2 | TestData 2 |
87 | And Current user is "John"
88 | And Current datetime is "2016/08/05 16:00:00"
89 | And Register system info hook in generic repository
90 | When I use generic repository to add datalist
91 | And I save the changes
92 | Then database should exists test datas
93 | | Id | Content | CreatedAt | CreatedBy | UpdatedAt | UpdatedBy |
94 | | 1 | TestData | 2016/08/05 16:00:00 | John | 2016/08/05 16:00:00 | John |
95 | | 2 | TestData 2 | 2016/08/05 16:00:00 | John | 2016/08/05 16:00:00 | John |
96 |
97 | Scenario: Update data which is exists in database should be success and auto assign system required infomation
98 | Given database has systemInfo datas
99 | | Id | Content | CreatedAt | CreatedBy | UpdatedAt | UpdatedBy |
100 | | 1 | TestData | 2016/08/05 16:00:00 | John | 2016/08/05 16:00:00 | John |
101 | | 2 | TestData 2 | 2016/08/05 16:00:00 | John | 2016/08/05 16:00:00 | John |
102 | And the data I want to update is
103 | | Id | Content | CreatedAt | CreatedBy | UpdatedAt | UpdatedBy |
104 | | 1 | TestData Modified | 2016/08/05 16:00:00 | John | 2016/08/05 16:00:00 | John |
105 | And Current user is "David"
106 | And Current datetime is "2016/08/06 09:00:00"
107 | And Register system info hook in generic repository
108 | When I use generic repository update data
109 | And I save the changes
110 | Then database should exists test datas
111 | | Id | Content | CreatedAt | CreatedBy | UpdatedAt | UpdatedBy |
112 | | 1 | TestData Modified | 2016/08/05 16:00:00 | John | 2016/08/06 09:00:00 | David |
113 | | 2 | TestData 2 | 2016/08/05 16:00:00 | John | 2016/08/05 16:00:00 | John |
114 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Hooks/SystemInfo.feature.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------------
2 | //
3 | // This code was generated by SpecFlow (http://www.specflow.org/).
4 | // SpecFlow Version:2.1.0.0
5 | // SpecFlow Generator Version:2.0.0.0
6 | //
7 | // Changes to this file may cause incorrect behavior and will be lost if
8 | // the code is regenerated.
9 | //
10 | // ------------------------------------------------------------------------------
11 | #region Designer generated code
12 | #pragma warning disable
13 | namespace EFRepository.Tests.Hooks
14 | {
15 | using TechTalk.SpecFlow;
16 |
17 |
18 | [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.1.0.0")]
19 | [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
20 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute()]
21 | public partial class SystemInfoFeature
22 | {
23 |
24 | private static TechTalk.SpecFlow.ITestRunner testRunner;
25 |
26 | #line 1 "SystemInfo.feature"
27 | #line hidden
28 |
29 | [Microsoft.VisualStudio.TestTools.UnitTesting.ClassInitializeAttribute()]
30 | public static void FeatureSetup(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext testContext)
31 | {
32 | testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(null, 0);
33 | TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "SystemInfo", "As a programmer
\r\nIn order to auto assign required system information when " +
34 | "insert or update data
\r\nI would like to use use system info hook to handle" +
35 | " assign system infomation logic
\r\n\r\nHow to use?\r\n--------\r\n\r\n1. Create dat" +
36 | "a class inherits **ISystemInfo**\r\n\t\t\r\n\t\tpublic class SystemInfoData : IEntity, ISystemInfo\r\n\t\t{ \r\n\t\t\t[Key]\r\n\t\t\tpublic int Id { get; set; }\r\n \r" +
38 | "\n\t\t\tpublic string Content { get; set; }\r\n \r\n\t\t\tpublic DateTime CreatedAt { " +
39 | "get; set; }\r\n\r\n\t public string CreatedBy { get; set; }\r\n\r\n\t\t\tpublic DateT" +
40 | "ime UpdatedAt { get; set; }\r\n\r\n\t\t\tpublic string UpdatedBy { get; set; }\r\n\t\t}\t\r\n\r" +
41 | "\n1. Create **UserHelper** class to get current username in your system\r\n\r\n\t\tpubl" +
42 | "ic class UserHelper: IUserHelper\r\n\t\t{\r\n\t\t\tpublic string GetUserName()\r\n\t\t\t{\r\n\t\t\t" +
43 | "\t//// Implement your system user name logic\r\n\t\t\t\treturn HttpContext.Current.User" +
44 | ".Name;\r\n\t\t\t}\r\n\t\t}\r\n\r\n1. Create repository inherits **Generic repository** and re" +
45 | "gister **System info hook**\r\n\r\n\t\tpublic class SystemInfoRepository : GenericRepo" +
46 | "sitory, IRepository\r\n\t\t{ \r\n\t\t\tp" +
47 | "ublic SystemInfoRepository(MyDbContext context)\r\n\t\t\t\t: base(context)\r\n\t\t\t{\r\n\t\t\t\t" +
48 | "this.Repository.RegisterPostActionHook(new SystemInfoPostActionHook(new UserHelper(), new DatetimeHelper()));\r\n\t\t\t}\r\n\t\t}\r\n\r\n1. Use repository\r\n\r" +
50 | "\n\t\tusing(var dbContext = new MyDbContext())\r\n\t\t{\r\n\t\t\tvar repository = new SoftDe" +
51 | "leteRepository(dbContext);\r\n\r\n\t\t\t//// Will auto update required system info fiel" +
52 | "d\r\n\t\t\trepository.Add(myData);\r\n\r\n\t\t\tor\r\n\r\n\t\t\t//// Will auto update required syst" +
53 | "em info field\r\n\t\t\trepository.Update(myData);\r\n\t\t}\r\n\r\nScenarios\r\n--------", ProgrammingLanguage.CSharp, new string[] {
54 | "Hook"});
55 | testRunner.OnFeatureStart(featureInfo);
56 | }
57 |
58 | [Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupAttribute()]
59 | public static void FeatureTearDown()
60 | {
61 | testRunner.OnFeatureEnd();
62 | testRunner = null;
63 | }
64 |
65 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute()]
66 | public virtual void TestInitialize()
67 | {
68 | if (((testRunner.FeatureContext != null)
69 | && (testRunner.FeatureContext.FeatureInfo.Title != "SystemInfo")))
70 | {
71 | EFRepository.Tests.Hooks.SystemInfoFeature.FeatureSetup(null);
72 | }
73 | }
74 |
75 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCleanupAttribute()]
76 | public virtual void ScenarioTearDown()
77 | {
78 | testRunner.OnScenarioEnd();
79 | }
80 |
81 | public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo)
82 | {
83 | testRunner.OnScenarioStart(scenarioInfo);
84 | }
85 |
86 | public virtual void ScenarioCleanup()
87 | {
88 | testRunner.CollectScenarioErrors();
89 | }
90 |
91 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
92 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Add data into database should be success and auto assign system required infomati" +
93 | "on")]
94 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SystemInfo")]
95 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Hook")]
96 | public virtual void AddDataIntoDatabaseShouldBeSuccessAndAutoAssignSystemRequiredInfomation()
97 | {
98 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Add data into database should be success and auto assign system required infomati" +
99 | "on", ((string[])(null)));
100 | #line 69
101 | this.ScenarioSetup(scenarioInfo);
102 | #line hidden
103 | TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] {
104 | "Id",
105 | "Content"});
106 | table1.AddRow(new string[] {
107 | "1",
108 | "TestData"});
109 | #line 70
110 | testRunner.Given("I have systemInfo datas", ((string)(null)), table1, "Given ");
111 | #line 73
112 | testRunner.And("Current user is \"John\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
113 | #line 74
114 | testRunner.And("Current datetime is \"2016/08/05 16:00:00\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
115 | #line 75
116 | testRunner.And("Register system info hook in generic repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
117 | #line 76
118 | testRunner.When("I use generic repository to add data", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
119 | #line 77
120 | testRunner.And("I save the changes", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
121 | #line hidden
122 | TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] {
123 | "Id",
124 | "Content",
125 | "CreatedAt",
126 | "CreatedBy",
127 | "UpdatedAt",
128 | "UpdatedBy"});
129 | table2.AddRow(new string[] {
130 | "1",
131 | "TestData",
132 | "2016/08/05 16:00:00",
133 | "John",
134 | "2016/08/05 16:00:00",
135 | "John"});
136 | #line 78
137 | testRunner.Then("database should exists test datas", ((string)(null)), table2, "Then ");
138 | #line hidden
139 | this.ScenarioCleanup();
140 | }
141 |
142 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
143 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Add datalist into database should be success and auto assign system required info" +
144 | "mation")]
145 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SystemInfo")]
146 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Hook")]
147 | public virtual void AddDatalistIntoDatabaseShouldBeSuccessAndAutoAssignSystemRequiredInfomation()
148 | {
149 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Add datalist into database should be success and auto assign system required info" +
150 | "mation", ((string[])(null)));
151 | #line 82
152 | this.ScenarioSetup(scenarioInfo);
153 | #line hidden
154 | TechTalk.SpecFlow.Table table3 = new TechTalk.SpecFlow.Table(new string[] {
155 | "Id",
156 | "Content"});
157 | table3.AddRow(new string[] {
158 | "1",
159 | "TestData"});
160 | table3.AddRow(new string[] {
161 | "2",
162 | "TestData 2"});
163 | #line 83
164 | testRunner.Given("I have systemInfo datas", ((string)(null)), table3, "Given ");
165 | #line 87
166 | testRunner.And("Current user is \"John\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
167 | #line 88
168 | testRunner.And("Current datetime is \"2016/08/05 16:00:00\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
169 | #line 89
170 | testRunner.And("Register system info hook in generic repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
171 | #line 90
172 | testRunner.When("I use generic repository to add datalist", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
173 | #line 91
174 | testRunner.And("I save the changes", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
175 | #line hidden
176 | TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] {
177 | "Id",
178 | "Content",
179 | "CreatedAt",
180 | "CreatedBy",
181 | "UpdatedAt",
182 | "UpdatedBy"});
183 | table4.AddRow(new string[] {
184 | "1",
185 | "TestData",
186 | "2016/08/05 16:00:00",
187 | "John",
188 | "2016/08/05 16:00:00",
189 | "John"});
190 | table4.AddRow(new string[] {
191 | "2",
192 | "TestData 2",
193 | "2016/08/05 16:00:00",
194 | "John",
195 | "2016/08/05 16:00:00",
196 | "John"});
197 | #line 92
198 | testRunner.Then("database should exists test datas", ((string)(null)), table4, "Then ");
199 | #line hidden
200 | this.ScenarioCleanup();
201 | }
202 |
203 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
204 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Update data which is exists in database should be success and auto assign system " +
205 | "required infomation")]
206 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SystemInfo")]
207 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Hook")]
208 | public virtual void UpdateDataWhichIsExistsInDatabaseShouldBeSuccessAndAutoAssignSystemRequiredInfomation()
209 | {
210 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Update data which is exists in database should be success and auto assign system " +
211 | "required infomation", ((string[])(null)));
212 | #line 97
213 | this.ScenarioSetup(scenarioInfo);
214 | #line hidden
215 | TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] {
216 | "Id",
217 | "Content",
218 | "CreatedAt",
219 | "CreatedBy",
220 | "UpdatedAt",
221 | "UpdatedBy"});
222 | table5.AddRow(new string[] {
223 | "1",
224 | "TestData",
225 | "2016/08/05 16:00:00",
226 | "John",
227 | "2016/08/05 16:00:00",
228 | "John"});
229 | table5.AddRow(new string[] {
230 | "2",
231 | "TestData 2",
232 | "2016/08/05 16:00:00",
233 | "John",
234 | "2016/08/05 16:00:00",
235 | "John"});
236 | #line 98
237 | testRunner.Given("database has systemInfo datas", ((string)(null)), table5, "Given ");
238 | #line hidden
239 | TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] {
240 | "Id",
241 | "Content",
242 | "CreatedAt",
243 | "CreatedBy",
244 | "UpdatedAt",
245 | "UpdatedBy"});
246 | table6.AddRow(new string[] {
247 | "1",
248 | "TestData Modified",
249 | "2016/08/05 16:00:00",
250 | "John",
251 | "2016/08/05 16:00:00",
252 | "John"});
253 | #line 102
254 | testRunner.And("the data I want to update is", ((string)(null)), table6, "And ");
255 | #line 105
256 | testRunner.And("Current user is \"David\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
257 | #line 106
258 | testRunner.And("Current datetime is \"2016/08/06 09:00:00\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
259 | #line 107
260 | testRunner.And("Register system info hook in generic repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
261 | #line 108
262 | testRunner.When("I use generic repository update data", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
263 | #line 109
264 | testRunner.And("I save the changes", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
265 | #line hidden
266 | TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] {
267 | "Id",
268 | "Content",
269 | "CreatedAt",
270 | "CreatedBy",
271 | "UpdatedAt",
272 | "UpdatedBy"});
273 | table7.AddRow(new string[] {
274 | "1",
275 | "TestData Modified",
276 | "2016/08/05 16:00:00",
277 | "John",
278 | "2016/08/06 09:00:00",
279 | "David"});
280 | table7.AddRow(new string[] {
281 | "2",
282 | "TestData 2",
283 | "2016/08/05 16:00:00",
284 | "John",
285 | "2016/08/05 16:00:00",
286 | "John"});
287 | #line 110
288 | testRunner.Then("database should exists test datas", ((string)(null)), table7, "Then ");
289 | #line hidden
290 | this.ScenarioCleanup();
291 | }
292 | }
293 | }
294 | #pragma warning restore
295 | #endregion
296 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Hooks/SystemInfoSteps.cs:
--------------------------------------------------------------------------------
1 | using EFRepository.Hooks;
2 | using EFRepository.Tests.TestClasses;
3 | using Moq;
4 | using Moq.Protected;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using TechTalk.SpecFlow;
9 | using TechTalk.SpecFlow.Assist;
10 |
11 | namespace EFRepository.Tests.Hooks
12 | {
13 | [Binding]
14 | [Scope(Feature = "SystemInfo")]
15 | public class SystemInfoSteps
16 | {
17 | public string ConnectionString { get; private set; }
18 |
19 | public TestDbContext DbContext { get; private set; }
20 |
21 | public SystemInfoRepository Repository { get; private set; }
22 |
23 | public SystemInfoData DataItem { get; private set; }
24 |
25 | public IEnumerable DataList { get; private set; }
26 |
27 | public Mock UserHelperMock { get; private set; }
28 |
29 | public Mock DatetimeHelperMock { get; private set; }
30 |
31 | [BeforeScenario]
32 | public void BeforeScenario()
33 | {
34 | this.ConnectionString = Environment.GetEnvironmentVariable("TestDb") ?? "TestDb";
35 |
36 | this.DbContext = new TestDbContext(ConnectionString);
37 | this.DbContext.Database.Delete();
38 |
39 | this.Repository = new SystemInfoRepository(this.DbContext);
40 |
41 | this.UserHelperMock = new Mock();
42 | this.DatetimeHelperMock = new Mock();
43 | }
44 |
45 | [AfterScenario]
46 | public void AfterScenario()
47 | {
48 | this.DbContext.Dispose();
49 | }
50 |
51 | [Given(@"I have systemInfo datas")]
52 | public void GivenIHaveSystemInfoDatas(Table table)
53 | {
54 | this.DataList = table.CreateSet();
55 | }
56 |
57 | [Given(@"database has systemInfo datas")]
58 | public void GivenDatabaseHasSystemInfoDatas(Table table)
59 | {
60 | var dataList = table.CreateSet();
61 |
62 | using (var dbContext = new TestDbContext(this.ConnectionString))
63 | {
64 | dbContext.SystemInfoDatas.AddRange(dataList);
65 | dbContext.SaveChanges();
66 | }
67 | }
68 |
69 | [Given(@"the data I want to update is")]
70 | public void GivenTheDataIWantToUpdateIs(Table table)
71 | {
72 | this.DataItem = table.CreateInstance();
73 | }
74 |
75 | [Given(@"Current user is ""(.*)""")]
76 | public void GivenCurrentUserIs(string userName)
77 | {
78 | this.UserHelperMock.Setup(i => i.GetUserName()).Returns(userName);
79 | }
80 |
81 | [Given(@"Current datetime is ""(.*)""")]
82 | public void GivenCurrentDatetimeIs(DateTime currentDatetime)
83 | {
84 | this.DatetimeHelperMock.Setup(i => i.GetCurrentTime()).Returns(currentDatetime);
85 | }
86 |
87 | [Given(@"Register system info hook in generic repository")]
88 | public void GivenRegisterSystemInfoHookInGenericRepository()
89 | {
90 | this.Repository.RegisterPostActionHook(new SystemInfoPostActionHook(this.UserHelperMock.Object, this.DatetimeHelperMock.Object));
91 | }
92 |
93 | [When(@"I use generic repository to add data")]
94 | public void WhenIUseGenericRepositoryToAddData()
95 | {
96 | this.Repository.Add(this.DataList.First());
97 | }
98 |
99 | [When(@"I use generic repository to add datalist")]
100 | public void WhenIUseGenericRepositoryToAddDatalist()
101 | {
102 | this.Repository.AddRange(this.DataList);
103 | }
104 |
105 | [When(@"I use generic repository update data")]
106 | public void WhenIUseGenericRepositoryUpdateData()
107 | {
108 | this.Repository.Update(this.DataItem);
109 | }
110 |
111 | [When(@"I save the changes")]
112 | public void WhenISaveTheChanges()
113 | {
114 | this.Repository.SaveChanges();
115 | }
116 |
117 | [Then(@"database should exists test datas")]
118 | public void ThenDatabaseShouldExistsTestDatas(Table table)
119 | {
120 | using (var dbContext = new TestDbContext(this.ConnectionString))
121 | {
122 | var datalist = dbContext.SystemInfoDatas.ToList();
123 |
124 | table.CompareToSet(datalist);
125 | }
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("EFRepository.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("EFRepository.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("bc65819a-550b-4da1-9ad4-a29ee244ad21")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Repositories/GenericRepository.feature:
--------------------------------------------------------------------------------
1 | @Repository
2 | Feature: GenericRepository
3 |
4 | As a programmer
5 | In order to reduce the work of writing repository
6 | I would like to create a GenericRepository to process database related logic
7 |
8 | How to use?
9 | --------
10 |
11 | 1. Create data class inherits **IEntity**
12 |
13 | public class TestData : IEntity
14 | {
15 | [Key]
16 | public int Id { get; set; }
17 |
18 | public string Content { get; set; }
19 | }
20 |
21 | 1. Create repository inherits **Generic repository**
22 |
23 | public class TestRepository : GenericRepository, IRepository
24 | {
25 | public TestRepository(TestDbContext context)
26 | : base(context)
27 | {
28 | }
29 | }
30 |
31 | 1. Use repository
32 |
33 | using(var dbContext = new MyDbContext())
34 | {
35 | var repository = new TestRepository(dbContext);
36 |
37 | //// Support basic CRUD operation
38 | var data = repository.Get(1)
39 | repository.Add(myData);
40 | repository.Update(myData);
41 | repository.Delete(1)
42 | }
43 |
44 | Scenarios
45 | --------
46 |
47 | Scenario: Add data into database should be success
48 | Given I have test datas
49 | | Id | Content |
50 | | 1 | TestData |
51 | When I use generic repository to add data
52 | And I save the changes
53 | Then database should exists test datas
54 | | Id | Content |
55 | | 1 | TestData |
56 |
57 | Scenario: Add datalist into database should be success
58 | Given I have test datas
59 | | Id | Content |
60 | | 1 | TestData |
61 | | 2 | TestData 2 |
62 | When I use generic repository to add datalist
63 | And I save the changes
64 | Then database should exists test datas
65 | | Id | Content |
66 | | 1 | TestData |
67 | | 2 | TestData 2 |
68 |
69 | Scenario: Get datalist from database should be success
70 | Given database has test datas
71 | | Id | Content |
72 | | 1 | TestData |
73 | | 2 | TestData 2 |
74 | When I use generic repository get data list from database
75 | Then the data list I get should be
76 | | Id | Content |
77 | | 1 | TestData |
78 | | 2 | TestData 2 |
79 |
80 | Scenario: Get datalist from database with condition content should contains "2" should be success
81 | Given database has test datas
82 | | Id | Content |
83 | | 1 | TestData |
84 | | 2 | TestData 2 |
85 | And test datas content field should contains "2"
86 | When I use generic repository get data list with condition from database
87 | Then the data list I get should be
88 | | Id | Content |
89 | | 2 | TestData 2 |
90 |
91 | Scenario: Get data from database should be success
92 | Given database has test datas
93 | | Id | Content |
94 | | 1 | TestData |
95 | | 2 | TestData 2 |
96 | When I use generic repository get data from database by id "1"
97 | Then the data list I get should be
98 | | Id | Content |
99 | | 1 | TestData |
100 |
101 | Scenario: Get data from database with condition content should contains "2" should be success
102 | Given database has test datas
103 | | Id | Content |
104 | | 1 | TestData |
105 | | 2 | TestData 2 |
106 | And test datas content field should contains "2"
107 | When I use generic repository get data from database with conditon
108 | Then the data list I get should be
109 | | Id | Content |
110 | | 2 | TestData 2 |
111 |
112 | Scenario: Update data which is exists in database should be success
113 | Given database has test datas
114 | | Id | Content |
115 | | 1 | TestData |
116 | | 2 | TestData 2 |
117 | And the data I want to update is
118 | | Id | Content |
119 | | 1 | TestData Modified |
120 | When I use generic repository update data
121 | And I save the changes
122 | Then database should exists test datas
123 | | Id | Content |
124 | | 1 | TestData Modified |
125 | | 2 | TestData 2 |
126 |
127 | Scenario: Delete data which is exists in database should be success
128 | Given database has test datas
129 | | Id | Content |
130 | | 1 | TestData |
131 | | 2 | TestData 2 |
132 | When I use generic repository delete data with id "1"
133 | And I save the changes
134 | Then database should exists test datas
135 | | Id | Content |
136 | | 2 | TestData 2 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Repositories/GenericRepository.feature.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------------
2 | //
3 | // This code was generated by SpecFlow (http://www.specflow.org/).
4 | // SpecFlow Version:2.1.0.0
5 | // SpecFlow Generator Version:2.0.0.0
6 | //
7 | // Changes to this file may cause incorrect behavior and will be lost if
8 | // the code is regenerated.
9 | //
10 | // ------------------------------------------------------------------------------
11 | #region Designer generated code
12 | #pragma warning disable
13 | namespace EFRepository.Tests.Repositories
14 | {
15 | using TechTalk.SpecFlow;
16 |
17 |
18 | [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.1.0.0")]
19 | [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
20 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute()]
21 | public partial class GenericRepositoryFeature
22 | {
23 |
24 | private static TechTalk.SpecFlow.ITestRunner testRunner;
25 |
26 | #line 1 "GenericRepository.feature"
27 | #line hidden
28 |
29 | [Microsoft.VisualStudio.TestTools.UnitTesting.ClassInitializeAttribute()]
30 | public static void FeatureSetup(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext testContext)
31 | {
32 | testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(null, 0);
33 | TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "GenericRepository", @"As a programmer
34 | In order to reduce the work of writing repository
35 | I would like to create a GenericRepository to process database related logic
36 |
37 | How to use?
38 | --------
39 |
40 | 1. Create data class inherits **IEntity**
41 |
42 | public class TestData : IEntity
43 | {
44 | [Key]
45 | public int Id { get; set; }
46 |
47 | public string Content { get; set; }
48 | }
49 |
50 | 1. Create repository inherits **Generic repository**
51 |
52 | public class TestRepository : GenericRepository, IRepository
53 | {
54 | public TestRepository(TestDbContext context)
55 | : base(context)
56 | {
57 | }
58 | }
59 |
60 | 1. Use repository
61 |
62 | using(var dbContext = new MyDbContext())
63 | {
64 | var repository = new TestRepository(dbContext);
65 |
66 | //// Support basic CRUD operation
67 | var data = repository.Get(1)
68 | repository.Add(myData);
69 | repository.Update(myData);
70 | repository.Delete(1)
71 | }
72 |
73 | Scenarios
74 | --------", ProgrammingLanguage.CSharp, new string[] {
75 | "Repository"});
76 | testRunner.OnFeatureStart(featureInfo);
77 | }
78 |
79 | [Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupAttribute()]
80 | public static void FeatureTearDown()
81 | {
82 | testRunner.OnFeatureEnd();
83 | testRunner = null;
84 | }
85 |
86 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute()]
87 | public virtual void TestInitialize()
88 | {
89 | if (((testRunner.FeatureContext != null)
90 | && (testRunner.FeatureContext.FeatureInfo.Title != "GenericRepository")))
91 | {
92 | EFRepository.Tests.Repositories.GenericRepositoryFeature.FeatureSetup(null);
93 | }
94 | }
95 |
96 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCleanupAttribute()]
97 | public virtual void ScenarioTearDown()
98 | {
99 | testRunner.OnScenarioEnd();
100 | }
101 |
102 | public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo)
103 | {
104 | testRunner.OnScenarioStart(scenarioInfo);
105 | }
106 |
107 | public virtual void ScenarioCleanup()
108 | {
109 | testRunner.CollectScenarioErrors();
110 | }
111 |
112 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
113 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Add data into database should be success")]
114 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "GenericRepository")]
115 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Repository")]
116 | public virtual void AddDataIntoDatabaseShouldBeSuccess()
117 | {
118 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Add data into database should be success", ((string[])(null)));
119 | #line 47
120 | this.ScenarioSetup(scenarioInfo);
121 | #line hidden
122 | TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] {
123 | "Id",
124 | "Content"});
125 | table1.AddRow(new string[] {
126 | "1",
127 | "TestData"});
128 | #line 48
129 | testRunner.Given("I have test datas", ((string)(null)), table1, "Given ");
130 | #line 51
131 | testRunner.When("I use generic repository to add data", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
132 | #line 52
133 | testRunner.And("I save the changes", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
134 | #line hidden
135 | TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] {
136 | "Id",
137 | "Content"});
138 | table2.AddRow(new string[] {
139 | "1",
140 | "TestData"});
141 | #line 53
142 | testRunner.Then("database should exists test datas", ((string)(null)), table2, "Then ");
143 | #line hidden
144 | this.ScenarioCleanup();
145 | }
146 |
147 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
148 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Add datalist into database should be success")]
149 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "GenericRepository")]
150 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Repository")]
151 | public virtual void AddDatalistIntoDatabaseShouldBeSuccess()
152 | {
153 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Add datalist into database should be success", ((string[])(null)));
154 | #line 57
155 | this.ScenarioSetup(scenarioInfo);
156 | #line hidden
157 | TechTalk.SpecFlow.Table table3 = new TechTalk.SpecFlow.Table(new string[] {
158 | "Id",
159 | "Content"});
160 | table3.AddRow(new string[] {
161 | "1",
162 | "TestData"});
163 | table3.AddRow(new string[] {
164 | "2",
165 | "TestData 2"});
166 | #line 58
167 | testRunner.Given("I have test datas", ((string)(null)), table3, "Given ");
168 | #line 62
169 | testRunner.When("I use generic repository to add datalist", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
170 | #line 63
171 | testRunner.And("I save the changes", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
172 | #line hidden
173 | TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] {
174 | "Id",
175 | "Content"});
176 | table4.AddRow(new string[] {
177 | "1",
178 | "TestData"});
179 | table4.AddRow(new string[] {
180 | "2",
181 | "TestData 2"});
182 | #line 64
183 | testRunner.Then("database should exists test datas", ((string)(null)), table4, "Then ");
184 | #line hidden
185 | this.ScenarioCleanup();
186 | }
187 |
188 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
189 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Get datalist from database should be success")]
190 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "GenericRepository")]
191 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Repository")]
192 | public virtual void GetDatalistFromDatabaseShouldBeSuccess()
193 | {
194 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Get datalist from database should be success", ((string[])(null)));
195 | #line 69
196 | this.ScenarioSetup(scenarioInfo);
197 | #line hidden
198 | TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] {
199 | "Id",
200 | "Content"});
201 | table5.AddRow(new string[] {
202 | "1",
203 | "TestData"});
204 | table5.AddRow(new string[] {
205 | "2",
206 | "TestData 2"});
207 | #line 70
208 | testRunner.Given("database has test datas", ((string)(null)), table5, "Given ");
209 | #line 74
210 | testRunner.When("I use generic repository get data list from database", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
211 | #line hidden
212 | TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] {
213 | "Id",
214 | "Content"});
215 | table6.AddRow(new string[] {
216 | "1",
217 | "TestData"});
218 | table6.AddRow(new string[] {
219 | "2",
220 | "TestData 2"});
221 | #line 75
222 | testRunner.Then("the data list I get should be", ((string)(null)), table6, "Then ");
223 | #line hidden
224 | this.ScenarioCleanup();
225 | }
226 |
227 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
228 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Get datalist from database with condition content should contains \"2\" should be s" +
229 | "uccess")]
230 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "GenericRepository")]
231 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Repository")]
232 | public virtual void GetDatalistFromDatabaseWithConditionContentShouldContains2ShouldBeSuccess()
233 | {
234 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Get datalist from database with condition content should contains \"2\" should be s" +
235 | "uccess", ((string[])(null)));
236 | #line 80
237 | this.ScenarioSetup(scenarioInfo);
238 | #line hidden
239 | TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] {
240 | "Id",
241 | "Content"});
242 | table7.AddRow(new string[] {
243 | "1",
244 | "TestData"});
245 | table7.AddRow(new string[] {
246 | "2",
247 | "TestData 2"});
248 | #line 81
249 | testRunner.Given("database has test datas", ((string)(null)), table7, "Given ");
250 | #line 85
251 | testRunner.And("test datas content field should contains \"2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
252 | #line 86
253 | testRunner.When("I use generic repository get data list with condition from database", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
254 | #line hidden
255 | TechTalk.SpecFlow.Table table8 = new TechTalk.SpecFlow.Table(new string[] {
256 | "Id",
257 | "Content"});
258 | table8.AddRow(new string[] {
259 | "2",
260 | "TestData 2"});
261 | #line 87
262 | testRunner.Then("the data list I get should be", ((string)(null)), table8, "Then ");
263 | #line hidden
264 | this.ScenarioCleanup();
265 | }
266 |
267 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
268 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Get data from database should be success")]
269 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "GenericRepository")]
270 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Repository")]
271 | public virtual void GetDataFromDatabaseShouldBeSuccess()
272 | {
273 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Get data from database should be success", ((string[])(null)));
274 | #line 91
275 | this.ScenarioSetup(scenarioInfo);
276 | #line hidden
277 | TechTalk.SpecFlow.Table table9 = new TechTalk.SpecFlow.Table(new string[] {
278 | "Id",
279 | "Content"});
280 | table9.AddRow(new string[] {
281 | "1",
282 | "TestData"});
283 | table9.AddRow(new string[] {
284 | "2",
285 | "TestData 2"});
286 | #line 92
287 | testRunner.Given("database has test datas", ((string)(null)), table9, "Given ");
288 | #line 96
289 | testRunner.When("I use generic repository get data from database by id \"1\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
290 | #line hidden
291 | TechTalk.SpecFlow.Table table10 = new TechTalk.SpecFlow.Table(new string[] {
292 | "Id",
293 | "Content"});
294 | table10.AddRow(new string[] {
295 | "1",
296 | "TestData"});
297 | #line 97
298 | testRunner.Then("the data list I get should be", ((string)(null)), table10, "Then ");
299 | #line hidden
300 | this.ScenarioCleanup();
301 | }
302 |
303 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
304 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Get data from database with condition content should contains \"2\" should be succe" +
305 | "ss")]
306 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "GenericRepository")]
307 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Repository")]
308 | public virtual void GetDataFromDatabaseWithConditionContentShouldContains2ShouldBeSuccess()
309 | {
310 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Get data from database with condition content should contains \"2\" should be succe" +
311 | "ss", ((string[])(null)));
312 | #line 101
313 | this.ScenarioSetup(scenarioInfo);
314 | #line hidden
315 | TechTalk.SpecFlow.Table table11 = new TechTalk.SpecFlow.Table(new string[] {
316 | "Id",
317 | "Content"});
318 | table11.AddRow(new string[] {
319 | "1",
320 | "TestData"});
321 | table11.AddRow(new string[] {
322 | "2",
323 | "TestData 2"});
324 | #line 102
325 | testRunner.Given("database has test datas", ((string)(null)), table11, "Given ");
326 | #line 106
327 | testRunner.And("test datas content field should contains \"2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
328 | #line 107
329 | testRunner.When("I use generic repository get data from database with conditon", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
330 | #line hidden
331 | TechTalk.SpecFlow.Table table12 = new TechTalk.SpecFlow.Table(new string[] {
332 | "Id",
333 | "Content"});
334 | table12.AddRow(new string[] {
335 | "2",
336 | "TestData 2"});
337 | #line 108
338 | testRunner.Then("the data list I get should be", ((string)(null)), table12, "Then ");
339 | #line hidden
340 | this.ScenarioCleanup();
341 | }
342 |
343 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
344 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Update data which is exists in database should be success")]
345 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "GenericRepository")]
346 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Repository")]
347 | public virtual void UpdateDataWhichIsExistsInDatabaseShouldBeSuccess()
348 | {
349 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Update data which is exists in database should be success", ((string[])(null)));
350 | #line 112
351 | this.ScenarioSetup(scenarioInfo);
352 | #line hidden
353 | TechTalk.SpecFlow.Table table13 = new TechTalk.SpecFlow.Table(new string[] {
354 | "Id",
355 | "Content"});
356 | table13.AddRow(new string[] {
357 | "1",
358 | "TestData"});
359 | table13.AddRow(new string[] {
360 | "2",
361 | "TestData 2"});
362 | #line 113
363 | testRunner.Given("database has test datas", ((string)(null)), table13, "Given ");
364 | #line hidden
365 | TechTalk.SpecFlow.Table table14 = new TechTalk.SpecFlow.Table(new string[] {
366 | "Id",
367 | "Content"});
368 | table14.AddRow(new string[] {
369 | "1",
370 | "TestData Modified"});
371 | #line 117
372 | testRunner.And("the data I want to update is", ((string)(null)), table14, "And ");
373 | #line 120
374 | testRunner.When("I use generic repository update data", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
375 | #line 121
376 | testRunner.And("I save the changes", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
377 | #line hidden
378 | TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] {
379 | "Id",
380 | "Content"});
381 | table15.AddRow(new string[] {
382 | "1",
383 | "TestData Modified"});
384 | table15.AddRow(new string[] {
385 | "2",
386 | "TestData 2"});
387 | #line 122
388 | testRunner.Then("database should exists test datas", ((string)(null)), table15, "Then ");
389 | #line hidden
390 | this.ScenarioCleanup();
391 | }
392 |
393 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
394 | [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Delete data which is exists in database should be success")]
395 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "GenericRepository")]
396 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("Repository")]
397 | public virtual void DeleteDataWhichIsExistsInDatabaseShouldBeSuccess()
398 | {
399 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Delete data which is exists in database should be success", ((string[])(null)));
400 | #line 127
401 | this.ScenarioSetup(scenarioInfo);
402 | #line hidden
403 | TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] {
404 | "Id",
405 | "Content"});
406 | table16.AddRow(new string[] {
407 | "1",
408 | "TestData"});
409 | table16.AddRow(new string[] {
410 | "2",
411 | "TestData 2"});
412 | #line 128
413 | testRunner.Given("database has test datas", ((string)(null)), table16, "Given ");
414 | #line 132
415 | testRunner.When("I use generic repository delete data with id \"1\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
416 | #line 133
417 | testRunner.And("I save the changes", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
418 | #line hidden
419 | TechTalk.SpecFlow.Table table17 = new TechTalk.SpecFlow.Table(new string[] {
420 | "Id",
421 | "Content"});
422 | table17.AddRow(new string[] {
423 | "2",
424 | "TestData 2"});
425 | #line 134
426 | testRunner.Then("database should exists test datas", ((string)(null)), table17, "Then ");
427 | #line hidden
428 | this.ScenarioCleanup();
429 | }
430 | }
431 | }
432 | #pragma warning restore
433 | #endregion
434 |
--------------------------------------------------------------------------------
/EFRepository.Tests/Repositories/GenericRepositorySteps.cs:
--------------------------------------------------------------------------------
1 | using EFRepository.Tests.TestClasses;
2 | using System;
3 | using System.Linq;
4 | using TechTalk.SpecFlow;
5 | using TechTalk.SpecFlow.Assist;
6 | using System.Collections.Generic;
7 | using System.Linq.Expressions;
8 |
9 | namespace EFRepository.Tests.Repositories
10 | {
11 | [Binding]
12 | [Scope(Feature = "GenericRepository")]
13 | public class GenericRepositorySteps
14 | {
15 | public string ConnectionString { get; private set; }
16 |
17 | public TestDbContext DbContext { get; private set; }
18 |
19 | public TestRepository Repository { get; private set; }
20 |
21 | public Expression> Condition { get; set; }
22 |
23 | public TestData DataItem { get; private set; }
24 |
25 | public IEnumerable DataList { get; private set; }
26 |
27 | [BeforeScenario]
28 | public void BeforeScenario()
29 | {
30 | this.ConnectionString = Environment.GetEnvironmentVariable("TestDb") ?? "TestDb";
31 |
32 | this.DbContext = new TestDbContext(ConnectionString);
33 | this.DbContext.Database.Delete();
34 |
35 | this.Repository = new TestRepository(this.DbContext);
36 | }
37 |
38 | [AfterScenario]
39 | public void AfterScenario()
40 | {
41 | this.DbContext.Dispose();
42 | }
43 |
44 | [Given(@"I have test datas")]
45 | public void GivenIHaveTestDatas(Table table)
46 | {
47 | this.DataList = table.CreateSet();
48 | }
49 |
50 | [Given(@"database has test datas")]
51 | public void GivenDatabaseHasTestDatas(Table table)
52 | {
53 | var dataList = table.CreateSet();
54 |
55 | using (var dbContext = new TestDbContext(this.ConnectionString))
56 | {
57 | dbContext.TestDatas.AddRange(dataList);
58 | dbContext.SaveChanges();
59 | }
60 | }
61 |
62 | [Given(@"test datas content field should contains ""(.*)""")]
63 | public void GivenTestDatasContentFieldShouldContains(string condition)
64 | {
65 | this.Condition = (data) => data.Content.Contains(condition);
66 | }
67 |
68 | [Given(@"the data I want to update is")]
69 | public void GivenTheDataIWantToUpdateIs(Table table)
70 | {
71 | this.DataItem = table.CreateInstance();
72 | }
73 |
74 | [When(@"I use generic repository to add data")]
75 | public void WhenIUseGenericRepositoryToAddData()
76 | {
77 | this.Repository.Add(this.DataList.First());
78 | }
79 |
80 | [When(@"I use generic repository to add datalist")]
81 | public void WhenIUseGenericRepositoryToAddDatalist()
82 | {
83 | this.Repository.AddRange(this.DataList);
84 | }
85 |
86 | [When(@"I save the changes")]
87 | public void WhenISaveTheChanges()
88 | {
89 | this.Repository.SaveChanges();
90 | }
91 |
92 | [When(@"I use generic repository get data list from database")]
93 | public void WhenIUseGenericRepositoryGetDataListFromDatabase()
94 | {
95 | this.DataList = this.Repository.GetList();
96 | }
97 |
98 | [When(@"I use generic repository get data from database by id ""(.*)""")]
99 | public void WhenIUseGenericRepositoryGetDataFromDatabaseById(int id)
100 | {
101 | this.DataItem = this.Repository.Get(id);
102 |
103 | this.DataList = new List() { this.DataItem };
104 | }
105 |
106 | [When(@"I use generic repository get data list with condition from database")]
107 | public void WhenIUseGenericRepositoryGetDataListWithConditionFromDatabase()
108 | {
109 | this.DataList = this.Repository.GetList(this.Condition);
110 | }
111 |
112 | [When(@"I use generic repository get data from database with conditon")]
113 | public void WhenIUseGenericRepositoryGetDataFromDatabaseWithConditon()
114 | {
115 | this.DataItem = this.Repository.Get(this.Condition);
116 |
117 | this.DataList = new List() { this.DataItem };
118 | }
119 |
120 | [When(@"I use generic repository update data")]
121 | public void WhenIUseGenericRepositoryUpdateData()
122 | {
123 | this.Repository.Update(this.DataItem);
124 | }
125 |
126 | [When(@"I use generic repository delete data with id ""(.*)""")]
127 | public void WhenIUseGenericRepositoryDeleteDataWithId(int id)
128 | {
129 | this.Repository.Delete(id);
130 | }
131 |
132 | [Then(@"database should exists test datas")]
133 | public void ThenDatabaseShouldExistsTestDatas(Table table)
134 | {
135 | using (var dbContext = new TestDbContext(this.ConnectionString))
136 | {
137 | var datalist = dbContext.TestDatas.ToList();
138 |
139 | table.CompareToSet(datalist);
140 | }
141 | }
142 |
143 | [Then(@"the data list I get should be")]
144 | public void ThenTheDataListIGetShouldBe(Table table)
145 | {
146 | table.CompareToSet(this.DataList);
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/EFRepository.Tests/TestClasses/SoftDeleteData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace EFRepository.Tests.TestClasses
9 | {
10 | public class SoftDeleteData : IEntity, ISoftDelete
11 | {
12 | ///
13 | /// Gets or sets the identifier.
14 | ///
15 | ///
16 | /// The identifier.
17 | ///
18 | [Key]
19 | public int Id { get; set; }
20 |
21 | ///
22 | /// Gets or sets the content.
23 | ///
24 | ///
25 | /// The content.
26 | ///
27 | public string Content { get; set; }
28 |
29 | ///
30 | /// Gets or sets a value indicating whether this instance is delete.
31 | ///
32 | ///
33 | /// true if this instance is delete; otherwise, false.
34 | ///
35 | public bool IsDelete { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/EFRepository.Tests/TestClasses/SoftDeleteRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EFRepository.Tests.TestClasses
8 | {
9 | ///
10 | /// SoftDeleteRepository
11 | ///
12 | ///
13 | public class SoftDeleteRepository : GenericRepository, IRepository
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The context.
19 | public SoftDeleteRepository(TestDbContext context)
20 | : base(context)
21 | {
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/EFRepository.Tests/TestClasses/SystemInfoData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace EFRepository.Tests.TestClasses
9 | {
10 | public class SystemInfoData : IEntity, ISystemInfo
11 | {
12 | ///
13 | /// Gets or sets the identifier.
14 | ///
15 | ///
16 | /// The identifier.
17 | ///
18 | [Key]
19 | public int Id { get; set; }
20 |
21 | ///
22 | /// Gets or sets the content.
23 | ///
24 | ///
25 | /// The content.
26 | ///
27 | public string Content { get; set; }
28 |
29 | ///
30 | /// Gets or sets the created at.
31 | ///
32 | ///
33 | /// The created at.
34 | ///
35 | public DateTime CreatedAt { get; set; }
36 |
37 | ///
38 | /// Gets or sets the created by.
39 | ///
40 | ///
41 | /// The created by.
42 | ///
43 | public string CreatedBy { get; set; }
44 |
45 | ///
46 | /// Gets or sets the updated at.
47 | ///
48 | ///
49 | /// The updated at.
50 | ///
51 | public DateTime UpdatedAt { get; set; }
52 |
53 | ///
54 | /// Gets or sets the updated by.
55 | ///
56 | ///
57 | /// The updated by.
58 | ///
59 | public string UpdatedBy { get; set; }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/EFRepository.Tests/TestClasses/SystemInfoRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EFRepository.Tests.TestClasses
8 | {
9 | ///
10 | /// SystemInfoRepository
11 | ///
12 | ///
13 | ///
14 | public class SystemInfoRepository : GenericRepository, IRepository
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The context.
20 | public SystemInfoRepository(TestDbContext context)
21 | : base(context)
22 | {
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/EFRepository.Tests/TestClasses/TestData.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace EFRepository.Tests.TestClasses
4 | {
5 | ///
6 | /// TestData
7 | ///
8 | public class TestData : IEntity
9 | {
10 | ///
11 | /// Gets or sets the identifier.
12 | ///
13 | ///
14 | /// The identifier.
15 | ///
16 | [Key]
17 | public int Id { get; set; }
18 |
19 | ///
20 | /// Gets or sets the content.
21 | ///
22 | ///
23 | /// The content.
24 | ///
25 | public string Content { get; set; }
26 | }
27 | }
--------------------------------------------------------------------------------
/EFRepository.Tests/TestClasses/TestDbContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Entity;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace EFRepository.Tests.TestClasses
9 | {
10 | ///
11 | /// TestDbContext
12 | ///
13 | ///
14 | public class TestDbContext: DbContext
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public TestDbContext(string nameOrConnectionString)
20 | : base(nameOrConnectionString)
21 | {
22 | }
23 |
24 | ///
25 | /// Gets or sets the test datas.
26 | ///
27 | ///
28 | /// The test datas.
29 | ///
30 | public DbSet TestDatas { get; set; }
31 |
32 | ///
33 | /// Gets or sets the soft delete datas.
34 | ///
35 | ///
36 | /// The soft delete datas.
37 | ///
38 | public DbSet SoftDeleteDatas { get; set; }
39 |
40 | ///
41 | /// Gets or sets the system information datas.
42 | ///
43 | ///
44 | /// The system information datas.
45 | ///
46 | public DbSet SystemInfoDatas { get; set; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/EFRepository.Tests/TestClasses/TestRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EFRepository.Tests.TestClasses
8 | {
9 | ///
10 | /// TestRepository
11 | ///
12 | ///
13 | public class TestRepository : GenericRepository, IRepository
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The context.
19 | public TestRepository(TestDbContext context)
20 | : base(context)
21 | {
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/EFRepository.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/EFRepository.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25123.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFRepository", "EFRepository\EFRepository.csproj", "{3D6FC108-03AB-47E5-96C5-401CB8793BD7}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFRepository.Tests", "EFRepository.Tests\EFRepository.Tests.csproj", "{BC65819A-550B-4DA1-9AD4-A29EE244AD21}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {3D6FC108-03AB-47E5-96C5-401CB8793BD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {3D6FC108-03AB-47E5-96C5-401CB8793BD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {3D6FC108-03AB-47E5-96C5-401CB8793BD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {3D6FC108-03AB-47E5-96C5-401CB8793BD7}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {BC65819A-550B-4DA1-9AD4-A29EE244AD21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {BC65819A-550B-4DA1-9AD4-A29EE244AD21}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {BC65819A-550B-4DA1-9AD4-A29EE244AD21}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {BC65819A-550B-4DA1-9AD4-A29EE244AD21}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/EFRepository/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/EFRepository/DatetimeHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EFRepository
8 | {
9 | ///
10 | /// DatetimeHelper
11 | ///
12 | ///
13 | public class DatetimeHelper : IDatetimeHelper
14 | {
15 | ///
16 | /// Gets the current time.
17 | ///
18 | /// current time
19 | public DateTime GetCurrentTime()
20 | {
21 | return DateTime.Now;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/EFRepository/EFRepository.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {3D6FC108-03AB-47E5-96C5-401CB8793BD7}
8 | Library
9 | Properties
10 | EFRepository
11 | EFRepository
12 | v4.6.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll
35 | True
36 |
37 |
38 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll
39 | True
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
81 |
--------------------------------------------------------------------------------
/EFRepository/GenericRepository.cs:
--------------------------------------------------------------------------------
1 | using EFRepository.Hooks;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Data.Entity;
5 | using System.Linq;
6 | using System.Linq.Expressions;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace EFRepository
11 | {
12 | ///
13 | /// GenericRepository
14 | ///
15 | /// The type of the entity.
16 | public class GenericRepository : IRepository where TEntity : class, IEntity where TKey : IEquatable
17 | {
18 | ///
19 | /// Gets the database context.
20 | ///
21 | ///
22 | /// The database context.
23 | ///
24 | internal DbContext DbContext { get; set; }
25 |
26 | ///
27 | /// Gets or sets the post action hooks.
28 | ///
29 | ///
30 | /// The post action hooks.
31 | ///
32 | public ICollection> PostActionHooks { get; set; }
33 |
34 | ///
35 | /// Gets or sets the post load hooks.
36 | ///
37 | ///
38 | /// The post load hooks.
39 | ///
40 | public ICollection> PostLoadHooks { get; set; }
41 |
42 | ///
43 | /// Initializes a new instance of the class.
44 | ///
45 | /// The context.
46 | public GenericRepository(DbContext context)
47 | {
48 | this.DbContext = context;
49 | this.PostActionHooks = new List>();
50 | this.PostLoadHooks = new List>();
51 | }
52 |
53 | ///
54 | /// Registers the post load hook.
55 | ///
56 | /// The hook.
57 | public void RegisterPostLoadHook(IPostLoadHook hook)
58 | {
59 | this.PostLoadHooks.Add(hook);
60 | }
61 |
62 | ///
63 | /// Registers the post action hook.
64 | ///
65 | /// The hook.
66 | public void RegisterPostActionHook(IPostActionHook hook)
67 | {
68 | this.PostActionHooks.Add(hook);
69 | }
70 |
71 | ///
72 | /// Adds the specified data.
73 | ///
74 | /// The data.
75 | public virtual void Add(TEntity data)
76 | {
77 | this.DbContext.Set().Add(data);
78 |
79 | foreach (var hook in this.PostActionHooks)
80 | {
81 | hook.Execute(data, new HookContext()
82 | {
83 | DbContext = this.DbContext,
84 | Entity = data
85 | });
86 | }
87 | }
88 |
89 | ///
90 | /// Adds the range.
91 | ///
92 | /// The datalist.
93 | public virtual void AddRange(IEnumerable datalist)
94 | {
95 | foreach (var data in datalist)
96 | {
97 | this.Add(data);
98 | }
99 | }
100 |
101 | ///
102 | /// Gets the list.
103 | ///
104 | /// data list
105 | public virtual IEnumerable GetList()
106 | {
107 | var query = this.DbContext.Set()
108 | .AsQueryable();
109 |
110 | foreach (var hook in this.PostLoadHooks)
111 | {
112 | query = hook.Execute(query, new HookContext()
113 | {
114 | DbContext = this.DbContext,
115 | Entity = query
116 | });
117 | }
118 |
119 | return query.ToList();
120 | }
121 |
122 | ///
123 | /// Gets the list.
124 | ///
125 | /// The where.
126 | /// data list
127 | public virtual IEnumerable GetList(Expression> condition)
128 | {
129 | var query = this.DbContext.Set()
130 | .Where(condition);
131 |
132 | foreach (var hook in this.PostLoadHooks)
133 | {
134 | query = hook.Execute(query, new HookContext()
135 | {
136 | DbContext = this.DbContext,
137 | Entity = query
138 | });
139 | }
140 |
141 | return query.ToList();
142 | }
143 |
144 | ///
145 | /// Gets the specified identifier.
146 | ///
147 | /// The type of the key.
148 | /// The identifier.
149 | /// data
150 | public virtual TEntity Get(TKey id)
151 | {
152 | var query = this.DbContext.Set()
153 | .Where(i => i.Id.Equals(id));
154 |
155 | foreach (var hook in this.PostLoadHooks)
156 | {
157 | query = hook.Execute(query, new HookContext()
158 | {
159 | DbContext = this.DbContext,
160 | Entity = query
161 | });
162 | }
163 |
164 | return query.FirstOrDefault();
165 | }
166 |
167 | ///
168 | /// Gets the specified where.
169 | ///
170 | /// The where.
171 | /// data
172 | public virtual TEntity Get(Expression> condition)
173 | {
174 | var query = this.DbContext.Set()
175 | .Where(condition);
176 |
177 | foreach (var hook in this.PostLoadHooks)
178 | {
179 | query = hook.Execute(query, new HookContext()
180 | {
181 | DbContext = this.DbContext,
182 | Entity = query
183 | });
184 | }
185 |
186 | return query.FirstOrDefault();
187 | }
188 |
189 | ///
190 | /// Updates the specified data.
191 | ///
192 | /// The data.
193 | public virtual void Update(TEntity data)
194 | {
195 | this.DbContext.Set().Attach(data);
196 |
197 | var entry = this.DbContext.Entry(data);
198 | entry.State = EntityState.Modified;
199 |
200 | foreach (var hook in this.PostActionHooks)
201 | {
202 | hook.Execute(data, new HookContext()
203 | {
204 | DbContext = this.DbContext,
205 | Entity = data
206 | });
207 | }
208 | }
209 |
210 | ///
211 | /// Deletes the specified identifier.
212 | ///
213 | /// The identifier.
214 | public virtual void Delete(TKey id)
215 | {
216 | var data = this.Get(id);
217 |
218 | this.DbContext.Set()
219 | .Remove(data);
220 |
221 | foreach (var hook in this.PostActionHooks)
222 | {
223 | hook.Execute(data, new HookContext()
224 | {
225 | DbContext = this.DbContext,
226 | Entity = data
227 | });
228 | };
229 | }
230 |
231 | ///
232 | /// Saves the changes.
233 | ///
234 | /// the count of effected rows
235 | public int SaveChanges()
236 | {
237 | var result = this.DbContext.SaveChanges();
238 |
239 | return result;
240 | }
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/EFRepository/Hooks/HookContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Data.Entity;
4 |
5 | namespace EFRepository.Hooks
6 | {
7 | public class HookContext
8 | {
9 | public object Entity { get; set; }
10 |
11 | public DbContext DbContext { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/EFRepository/Hooks/IPostActionHook.cs:
--------------------------------------------------------------------------------
1 | namespace EFRepository.Hooks
2 | {
3 | public interface IPostActionHook where TEntity : class
4 | {
5 | void Execute(TEntity entity, HookContext context);
6 | }
7 | }
--------------------------------------------------------------------------------
/EFRepository/Hooks/IPostLoadHook.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace EFRepository.Hooks
9 | {
10 | public interface IPostLoadHook where TEntity: class
11 | {
12 | IQueryable Execute(IQueryable entity, HookContext context);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/EFRepository/Hooks/SoftDeletePostActionHook.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Data.Entity;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace EFRepository.Hooks
10 | {
11 | public class SoftDeletePostActionHook : IPostActionHook where TEntity : class
12 | {
13 | public void Execute(TEntity entity, HookContext context)
14 | {
15 | if (!(entity is ISoftDelete))
16 | {
17 | return;
18 | }
19 |
20 | var entry = context.DbContext.Entry(entity);
21 | if (entry.State == EntityState.Deleted)
22 | {
23 | entry.State = EntityState.Modified;
24 |
25 | var softDeleteData = entity as ISoftDelete;
26 | softDeleteData.IsDelete = true;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/EFRepository/Hooks/SoftDeletePostLoadHook.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace EFRepository.Hooks
9 | {
10 | public class SoftDeletePostLoadHook : IPostLoadHook where TEntity : class
11 | {
12 | public IQueryable Execute(IQueryable query, HookContext context)
13 | {
14 | if (query is IQueryable)
15 | {
16 | var softDeleteQuery = query as IQueryable;
17 | softDeleteQuery = softDeleteQuery.Where(i => !i.IsDelete);
18 |
19 | query = softDeleteQuery.OfType().AsQueryable();
20 | }
21 |
22 | return query;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/EFRepository/Hooks/SystemInfoPostActionHook.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Entity;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace EFRepository.Hooks
9 | {
10 | ///
11 | /// SystemInfoPostActionHook
12 | ///
13 | /// The type of the entity.
14 | ///
15 | public class SystemInfoPostActionHook : IPostActionHook where TEntity : class
16 | {
17 | ///
18 | /// Gets the user helper.
19 | ///
20 | ///
21 | /// The user helper.
22 | ///
23 | public IUserHelper UserHelper { get; private set; }
24 |
25 | public IDatetimeHelper DatetimeHelper { get; private set; }
26 |
27 | ///
28 | /// Initializes a new instance of the class.
29 | ///
30 | /// The user helper.
31 | public SystemInfoPostActionHook(IUserHelper userHelper, IDatetimeHelper datetimeHelper)
32 | {
33 | this.UserHelper = userHelper;
34 | this.DatetimeHelper = datetimeHelper;
35 | }
36 |
37 | ///
38 | /// Executes the specified entity.
39 | ///
40 | /// The entity.
41 | /// The context.
42 | public void Execute(TEntity entity, HookContext context)
43 | {
44 | if (!(entity is ISystemInfo))
45 | {
46 | return;
47 | }
48 |
49 | var systemInfoData = entity as ISystemInfo;
50 | var entry = context.DbContext.Entry(entity);
51 |
52 | if (entry.State == EntityState.Added)
53 | {
54 | var currentTime = this.DatetimeHelper.GetCurrentTime();
55 | var userName = this.UserHelper.GetUserName();
56 |
57 | systemInfoData.CreatedAt = currentTime;
58 | systemInfoData.CreatedBy = userName;
59 | systemInfoData.UpdatedAt = currentTime;
60 | systemInfoData.UpdatedBy = userName;
61 | }
62 |
63 | if (entry.State == EntityState.Modified)
64 | {
65 | var currentTime = this.DatetimeHelper.GetCurrentTime();
66 | var userName = this.UserHelper.GetUserName();
67 |
68 | systemInfoData.UpdatedAt = currentTime;
69 | systemInfoData.UpdatedBy = userName;
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/EFRepository/IDatetimeHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EFRepository
8 | {
9 | ///
10 | /// IDatetimeHelper
11 | ///
12 | public interface IDatetimeHelper
13 | {
14 | ///
15 | /// Gets the current time.
16 | ///
17 | ///
18 | DateTime GetCurrentTime();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/EFRepository/IEntity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EFRepository
8 | {
9 | ///
10 | /// IEntity
11 | ///
12 | /// The type of the key.
13 | public interface IEntity where TKey: IEquatable
14 | {
15 | ///
16 | /// Gets or sets the identifier.
17 | ///
18 | ///
19 | /// The identifier.
20 | ///
21 | TKey Id { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/EFRepository/IRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq.Expressions;
4 |
5 | namespace EFRepository
6 | {
7 | ///
8 | /// IRepository
9 | ///
10 | /// The type of the entity.
11 | public interface IRepository where TEntity : class, IEntity where TKey : IEquatable
12 | {
13 | ///
14 | /// Adds the specified data.
15 | ///
16 | /// The data.
17 | void Add(TEntity data);
18 |
19 | ///
20 | /// Adds the range.
21 | ///
22 | /// The datalist.
23 | void AddRange(IEnumerable datalist);
24 |
25 | ///
26 | /// Gets the list.
27 | ///
28 | /// data list
29 | IEnumerable GetList();
30 |
31 | ///
32 | /// Gets the list.
33 | ///
34 | /// The where.
35 | /// data list
36 | IEnumerable GetList(Expression> condition);
37 |
38 | ///
39 | /// Gets the specified identifier.
40 | ///
41 | /// The type of the key.
42 | /// The identifier.
43 | /// data
44 | TEntity Get(TKey id);
45 |
46 | ///
47 | /// Gets the specified where.
48 | ///
49 | /// The where.
50 | /// data
51 | TEntity Get(Expression> condition);
52 |
53 | ///
54 | /// Updates the specified data.
55 | ///
56 | /// The data.
57 | void Update(TEntity data);
58 |
59 | ///
60 | /// Deletes the specified identifier.
61 | ///
62 | /// The identifieTKeyr.
63 | void Delete(TKey id);
64 |
65 | ///
66 | /// Saves the changes.
67 | ///
68 | ///
69 | int SaveChanges();
70 | }
71 | }
--------------------------------------------------------------------------------
/EFRepository/ISoftDelete.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EFRepository
8 | {
9 | ///
10 | /// ISoftDelete
11 | ///
12 | public interface ISoftDelete
13 | {
14 | ///
15 | /// Gets or sets a value indicating whether this instance is delete.
16 | ///
17 | ///
18 | /// true if this instance is delete; otherwise, false.
19 | ///
20 | bool IsDelete { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/EFRepository/ISystemInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EFRepository
8 | {
9 | ///
10 | /// ISystemInfo
11 | ///
12 | public interface ISystemInfo
13 | {
14 | ///
15 | /// Gets or sets the created at.
16 | ///
17 | ///
18 | /// The created at.
19 | ///
20 | DateTime CreatedAt { get; set; }
21 |
22 | ///
23 | /// Gets or sets the created by.
24 | ///
25 | ///
26 | /// The created by.
27 | ///
28 | string CreatedBy { get; set; }
29 |
30 | ///
31 | /// Gets or sets the updated at.
32 | ///
33 | ///
34 | /// The updated at.
35 | ///
36 | DateTime UpdatedAt { get; set; }
37 |
38 | ///
39 | /// Gets or sets the updated by.
40 | ///
41 | ///
42 | /// The updated by.
43 | ///
44 | string UpdatedBy { get; set; }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/EFRepository/IUserHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EFRepository
8 | {
9 | ///
10 | /// IUserHelper
11 | ///
12 | public interface IUserHelper
13 | {
14 | ///
15 | /// Gets the name of the user.
16 | ///
17 | /// User name
18 | string GetUserName();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/EFRepository/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("EFRepository")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("EFRepository")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("3d6fc108-03ab-47e5-96c5-401cb8793bd7")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/EFRepository/UnitOfWork.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Entity;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace EFRepository
9 | {
10 | ///
11 | /// UnitOfWork
12 | ///
13 | ///
14 | public class UnitOfWork : IDisposable
15 | {
16 | ///
17 | /// Gets the database context.
18 | ///
19 | ///
20 | /// The database context.
21 | ///
22 | public DbContext DbContext { get; private set; }
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | /// The context.
28 | public UnitOfWork(DbContext context)
29 | {
30 | this.DbContext = context;
31 | }
32 |
33 | ///
34 | /// Saves the changes.
35 | ///
36 | /// the count of effected rows
37 | public int SaveChanges()
38 | {
39 | var result = this.DbContext.SaveChanges();
40 |
41 | return result;
42 | }
43 |
44 | ///
45 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
46 | ///
47 | public void Dispose()
48 | {
49 | this.DbContext = null;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/EFRepository/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Kirk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EFRepository
2 |
3 | [](https://ci.appveyor.com/project/kirkchen/efrepository)
4 | [](https://sonarqube.com/overview?id=EFRepository)
5 | [](https://sonarqube.com/overview?id=EFRepository)
6 | [](https://www.nuget.org/packages/KirkChen.EFRepository/)
7 | [](https://www.nuget.org/packages/KirkChen.EFRepository/)
8 | [](https://gitter.im/efrepository/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
9 |
10 | Generic repository and pattern "Unit of work" for Entity framework
11 |
12 | [Read more samples...](https://kirkchen.github.io/EFRepository/sample.html)
13 |
14 | ## Requirements
15 |
16 | * .Net Framework 4.6.1
17 | * EntityFramework 6.1.3
18 |
19 | ## Features
20 |
21 | * [Generic Repository](https://kirkchen.github.io/EFRepository/sample.html?feature=Repositories\GenericRepository.feature)
22 | * Basic operation
23 | * Add
24 | * Add range
25 | * Get list
26 | * Get list with condition
27 | * Get by id
28 | * Get with condition
29 | * Update
30 | * Delete
31 | * Support generic identity
32 | * Asynchronous operation
33 | * Add async
34 | * Add range async
35 | * Get list async
36 | * Get list with condition async
37 | * Get by id async
38 | * Get with condition async
39 | * Update async
40 | * Delete async
41 | * Hooks Supports
42 | * Nested object save changes
43 | * [Soft delete](https://kirkchen.github.io/EFRepository/sample.html?feature=Hooks\SoftDelete.feature)
44 | * [Auto system infomation](https://kirkchen.github.io/EFRepository/sample.html?feature=Hooks\SystemInfo.feature)
45 | * Audit log
46 | * Global query filter
47 | * Unit of work
48 |
49 | ## Quick Start
50 |
51 | 1. Install nuget package
52 |
53 | ```
54 | Install-Package KirkChen.EFRepository
55 | ```
56 |
57 | 1. Create data class with interface IEntity
58 |
59 | ``` csharp
60 | public class MyData : IEntity
61 | {
62 | [Key]
63 | public int Id { get; set; }
64 |
65 | public string Content { get; set; }
66 | }
67 | ```
68 |
69 | 1. Create dbContext
70 |
71 | ``` csharp
72 | public class MyDbContext: DbContext
73 | {
74 | public DbSet MyDatas { get; set; }
75 | }
76 | ```
77 |
78 | 1. Create repository for data class
79 |
80 | ``` csharp
81 | public class MyDataRepository : GenericRepository, IRepository
82 | {
83 | public MyDataRepository(MyDbContext context)
84 | : base(context)
85 | {
86 | // Enable soft delete
87 | this.RegisterPostLoadHook(new SoftDeletePostLoadHook());
88 | this.RegisterPostActionHook(new SoftDeletePostActionHook());
89 | }
90 | }
91 | ```
92 |
93 | 1. Use reository
94 |
95 | ``` csharp
96 | var dbContext = new MyDbContext();
97 | var repository = new MyDataRepository(dbContext);
98 | var myData = repository.Get(1);
99 | ```
100 |
101 | ## Unit of work
102 |
103 | Using unit of work to handle transaction
104 |
105 | ``` csharp
106 | using(var dbContext = new MyDbContext())
107 | using(var unitOfWork = new UnitOfWork(dbContext))
108 | {
109 | var repository = new MyDataRepository(dbContext);
110 | repository.Add(data);
111 |
112 | var anotherRepository = new OtherDataRepository(dbContext);
113 | repository.Add(anotherdata);
114 |
115 | unitOfWork.SaveChanges();
116 | }
117 | ```
118 |
119 | ## Roadmap
120 |
121 | - [ ] Generic Repository
122 | - [x] Basic operation
123 | - [x] Add
124 | - [x] Add range
125 | - [x] Get list
126 | - [x] Get list with condition
127 | - [x] Get by id
128 | - [x] Get with condition
129 | - [x] Update
130 | - [x] Delete
131 | - [x] Support generic identity
132 | - [ ] Asynchronous operation
133 | - [ ] Add async
134 | - [ ] Add range async
135 | - [ ] Get list async
136 | - [ ] Get list with condition async
137 | - [ ] Get by id async
138 | - [ ] Get with condition async
139 | - [ ] Update async
140 | - [ ] Delete async
141 | - [ ] Hooks Supports
142 | - [ ] Nested object save changes
143 | - [x] Soft delete
144 | - [x] Auto system infomation
145 | - [ ] Audit log
146 | - [ ] Global query filter
147 | - [x] Unit of work
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.0.{build}
2 | configuration: Release
3 |
4 | environment:
5 | TestDb: Server=(local)\SQL2016;Database=efrepositorytest;User ID=sa;Password=Password12!
6 | SONAR_TOKEN:
7 | secure: obPgeJ9AhOuWX6WhYKEQGKxiiMT6nZZbPrHnIKRPr9vE1Mg1BHv2TxBrgHBUPjGG
8 | GITHUB_EMAIL: rwk0119@yahoo.com.tw
9 | GITHUB_USERNAME: kirkchen
10 | GITHUB_TOKEN:
11 | secure: YF0+KGcrx/A/5UkgdBvm2tPmoQtusFvzhQwxAfg64DW7qWiUXNb8yszDycqErx1h
12 |
13 | services:
14 | - mssql2016
15 |
16 | matrix:
17 | fast_finish: true
18 |
19 | cache:
20 | - C:\Users\appveyor\AppData\Local\NuGet\Cache
21 |
22 | assembly_info:
23 | patch: true
24 | file: AssemblyInfo.*
25 | assembly_version: "1.0.{build}"
26 | assembly_file_version: "{version}"
27 | assembly_informational_version: "{version}"
28 |
29 | install:
30 | - cinst msbuild-sonarqube-runner
31 | - cinst pickles
32 |
33 | before_build:
34 | - nuget restore
35 | - ps: if (-Not $env:APPVEYOR_PULL_REQUEST_NUMBER -And $env:APPVEYOR_REPO_BRANCH -eq "master") { .\tools\build.bat }
36 | - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { .\tools\buildpullrequest.bat }
37 |
38 | build:
39 | parallel: true
40 | publish_wap: true
41 | verbosity: minimal
42 | project: EFRepository.sln
43 |
44 | test_script:
45 | - packages\OpenCover.4.6.519\tools\OpenCover.Console.exe -register:user -target:vstest.console.exe -targetargs:"/logger:Appveyor EFRepository.Tests\bin\Release\EFRepository.Tests.dll" -output:CodeCoverage.xml
46 |
47 | after_test:
48 | - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -Or $env:APPVEYOR_REPO_BRANCH -eq "master") { .\tools\buildfinish.bat }
49 | - ps: if ($env:APPVEYOR_REPO_BRANCH -eq "develop") { .\tools\packPrereleaseNuget.bat }
50 | - ps: if ($env:APPVEYOR_REPO_TAG -eq "true") { .\tools\packNuget.bat }
51 | - ps: if (-Not $env:APPVEYOR_PULL_REQUEST_NUMBER -And $env:APPVEYOR_REPO_BRANCH -eq "master") { .\tools\generateDocs.bat }
52 | - ps: if (-Not $env:APPVEYOR_PULL_REQUEST_NUMBER -And $env:APPVEYOR_REPO_BRANCH -eq "master") { .\tools\pushDocs.ps1 $env:APPVEYOR_BUILD_FOLDER $env:GITHUB_EMAIL $env:GITHUB_USERNAME $env:GITHUB_TOKEN }
53 |
54 | artifacts:
55 | - path: 'KirkChen.EFRepository*.nupkg'
56 |
57 | deploy:
58 | - provider: NuGet
59 | api_key:
60 | secure: P4/mzIswMzqvWjuucHnGxP5duV/aBk7AnsQpCKp6R+ztVxfRocPsB5dVIIt24OGE
61 | skip_symbols: true
62 | artifact: /.*\.nupkg/
63 | on:
64 | appveyor_repo_tag: true
65 |
66 | - provider: NuGet
67 | api_key:
68 | secure: P4/mzIswMzqvWjuucHnGxP5duV/aBk7AnsQpCKp6R+ztVxfRocPsB5dVIIt24OGE
69 | skip_symbols: true
70 | artifact: /.*\.nupkg/
71 | on:
72 | branch:
73 | - develop
74 |
75 | notifications:
76 | - provider: Webhook
77 | url: https://webhooks.gitter.im/e/7967db8e1538fa067706
78 | on_build_success: true
79 | on_build_failure: true
80 | on_build_status_changed: true
81 |
--------------------------------------------------------------------------------
/nuget/KirkChen.EFRepository.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | KirkChen.EFRepository
5 | 1.0.0
6 | KirkChen.EFRepository
7 | Kirk Chen
8 | https://github.com/kirkchen/EFRepository
9 | false
10 | Generic repository and pattern "Unit of work" for Entity framework.
11 | en-US
12 | EF, Database, Data, Repository
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "efrepository",
3 | "version": "1.0.0",
4 | "description": "Generic repository and pattern \"Unit of work\" for Entity framework",
5 | "scripts": {
6 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w"
7 | },
8 | "repository": {
9 | "type": "git",
10 | "url": "git+https://github.com/kirkchen/EFRepository.git"
11 | },
12 | "keywords": [
13 | "EF",
14 | "Database",
15 | "Data",
16 | "Repository"
17 | ],
18 | "author": "Kirk Chen",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/kirkchen/EFRepository/issues"
22 | },
23 | "homepage": "https://github.com/kirkchen/EFRepository#readme",
24 | "devDependencies": {
25 | "conventional-changelog-cli": "^1.2.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tools/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | MSBuild.SonarQube.Runner.exe begin /k:EFRepository /n:EFRepository /d:sonar.host.url=https://sonarqube.com /d:sonar.login=%SONAR_TOKEN% /d:sonar.cs.opencover.reportsPaths="%CD%\CodeCoverage.xml" /version:%APPVEYOR_BUILD_NUMBER%
--------------------------------------------------------------------------------
/tools/buildfinish.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | MSBuild.SonarQube.Runner.exe end /d:sonar.login=%SONAR_TOKEN%
--------------------------------------------------------------------------------
/tools/buildpullrequest.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | MSBuild.SonarQube.Runner.exe begin /k:EFRepository /n:EFRepository /d:sonar.analysis.mode=issues /d:sonar.issuesReport.console.enable=true /d:sonar.host.url=https://sonarqube.com /d:sonar.login=%SONAR_TOKEN% /d:sonar.cs.opencover.reportsPaths="%CD%\CodeCoverage.xml" /d:sonar.github.pullRequest=%APPVEYOR_PULL_REQUEST_NUMBER% /d:sonar.github.repository=kirkchen/EFRepository /d:sonar.github.oauth=%GITHUB_TOKEN% /version:%APPVEYOR_BUILD_NUMBER%
--------------------------------------------------------------------------------
/tools/generateDocs.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | pickles run --feature-directory=EFRepository.Tests --output-directory=TestDocs --documentation-format=dhtml --sn=EFRepository
--------------------------------------------------------------------------------
/tools/packNuget.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | nuget pack nuget\KirkChen.EFRepository.nuspec -Version %APPVEYOR_REPO_TAG_NAME%
--------------------------------------------------------------------------------
/tools/packPrereleaseNuget.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | nuget pack nuget\KirkChen.EFRepository.nuspec -Version %APPVEYOR_BUILD_VERSION%-pre
--------------------------------------------------------------------------------
/tools/pushDocs.ps1:
--------------------------------------------------------------------------------
1 | param([string]$buildFolder, [string]$email, [string]$username, [string]$personalAccessToken)
2 |
3 | Write-Host "- Set config settings...."
4 | git config --global user.email $email
5 | git config --global user.name $username
6 | git config --global push.default matching
7 |
8 | Write-Host "- Clone gh-pages branch...."
9 | cd "$($buildFolder)\..\"
10 | mkdir gh-pages
11 | git clone --quiet --branch=gh-pages https://$($username):$($personalAccessToken)@github.com/kirkchen/EFRepository.git .\gh-pages\
12 | cd gh-pages
13 | git status
14 |
15 | Write-Host "Rename TestDocs index.html to sample.html"
16 | Rename-Item $buildFolder\TestDocs\index.html sample.html
17 |
18 | Write-Host "- Copy contents of static-site folder into gh-pages folder...."
19 | copy-item -path $buildFolder\TestDocs\* -Destination $pwd.Path -Recurse -Force
20 |
21 | git status
22 | $thereAreChanges = git status | select-string -pattern "Changes not staged for commit:","Untracked files:" -simplematch
23 | if ($thereAreChanges -ne $null) {
24 | Write-host "- Committing changes to documentation..."
25 | git add --all
26 | git status
27 | git commit -m "skip ci - static site regeneration"
28 | git status
29 | Write-Host "- Push it...."
30 | git push --quiet
31 | Write-Host "- Pushed it good!"
32 | }
33 | else {
34 | write-host "- No changes to documentation to commit"
35 | }
--------------------------------------------------------------------------------