Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
CleanArchitecture
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
CleanArchitecture
Commits
6ed7a977
Commit
6ed7a977
authored
May 16, 2019
by
Scott DePouw
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Sample code for Repository Update Experiment.
parent
36d11177
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
348 additions
and
34 deletions
+348
-34
ToDoItem.cs
src/CleanArchitecture.Core/Entities/ToDoItem.cs
+11
-0
IRepository.cs
src/CleanArchitecture.Core/Interfaces/IRepository.cs
+2
-1
AppDbContext.cs
src/CleanArchitecture.Infrastructure/Data/AppDbContext.cs
+6
-4
EfRepository.cs
src/CleanArchitecture.Infrastructure/Data/EfRepository.cs
+8
-2
20190516105250_Foo.Designer.cs
....Infrastructure/Migrations/20190516105250_Foo.Designer.cs
+80
-0
20190516105250_Foo.cs
...hitecture.Infrastructure/Migrations/20190516105250_Foo.cs
+76
-0
AppDbContextModelSnapshot.cs
...re.Infrastructure/Migrations/AppDbContextModelSnapshot.cs
+78
-0
ToDoItemsController.cs
src/CleanArchitecture.Web/Api/ToDoItemsController.cs
+1
-1
HomeController.cs
src/CleanArchitecture.Web/Controllers/HomeController.cs
+35
-5
ToDoController.cs
src/CleanArchitecture.Web/Controllers/ToDoController.cs
+1
-2
Program.cs
src/CleanArchitecture.Web/Program.cs
+21
-2
SeedData.cs
src/CleanArchitecture.Web/SeedData.cs
+12
-0
Index.cshtml
src/CleanArchitecture.Web/Views/Home/Index.cshtml
+12
-10
Index.cshtml
src/CleanArchitecture.Web/Views/ToDo/Index.cshtml
+4
-6
EfRepositoryUpdate.cs
...Architecture.Tests/Integration/Data/EfRepositoryUpdate.cs
+1
-1
No files found.
src/CleanArchitecture.Core/Entities/ToDoItem.cs
View file @
6ed7a977
...
...
@@ -3,6 +3,17 @@ using CleanArchitecture.Core.SharedKernel;
namespace
CleanArchitecture.Core.Entities
{
public
class
Bar
:
BaseEntity
{
public
int
Number
{
get
;
set
;
}
}
public
class
Foo
:
BaseEntity
{
public
Bar
Bar
{
get
;
set
;
}
public
string
Name
{
get
;
set
;
}
}
public
class
ToDoItem
:
BaseEntity
{
public
string
Title
{
get
;
set
;
}
...
...
src/CleanArchitecture.Core/Interfaces/IRepository.cs
View file @
6ed7a977
...
...
@@ -8,7 +8,8 @@ namespace CleanArchitecture.Core.Interfaces
T
GetById
<
T
>(
int
id
)
where
T
:
BaseEntity
;
List
<
T
>
List
<
T
>()
where
T
:
BaseEntity
;
T
Add
<
T
>(
T
entity
)
where
T
:
BaseEntity
;
void
Update
<
T
>(
T
entity
)
where
T
:
BaseEntity
;
void
UpdateUsingOriginalMethod
<
T
>(
T
entity
)
where
T
:
BaseEntity
;
void
UpdateUsingDbContextUpdate
<
T
>(
T
entity
)
where
T
:
BaseEntity
;
void
Delete
<
T
>(
T
entity
)
where
T
:
BaseEntity
;
}
}
src/CleanArchitecture.Infrastructure/Data/AppDbContext.cs
View file @
6ed7a977
using
CleanArchitecture.Core.Interfaces
;
using
CleanArchitecture.Core.Entities
;
using
CleanArchitecture.Core.Interfaces
;
using
CleanArchitecture.Core.SharedKernel
;
using
Microsoft.EntityFrameworkCore
;
using
System.Linq
;
using
CleanArchitecture.Core.Entities
;
using
CleanArchitecture.Core.SharedKernel
;
namespace
CleanArchitecture.Infrastructure.Data
{
...
...
@@ -17,6 +17,8 @@ namespace CleanArchitecture.Infrastructure.Data
}
public
DbSet
<
ToDoItem
>
ToDoItems
{
get
;
set
;
}
public
DbSet
<
Foo
>
Foos
{
get
;
set
;
}
public
DbSet
<
Bar
>
Bars
{
get
;
set
;
}
public
override
int
SaveChanges
()
{
...
...
src/CleanArchitecture.Infrastructure/Data/EfRepository.cs
View file @
6ed7a977
...
...
@@ -17,7 +17,7 @@ namespace CleanArchitecture.Infrastructure.Data
public
T
GetById
<
T
>(
int
id
)
where
T
:
BaseEntity
{
return
_dbContext
.
Set
<
T
>().
SingleOrDefault
(
e
=>
e
.
Id
==
id
);
return
_dbContext
.
Set
<
T
>().
Include
(
"Bar"
).
SingleOrDefault
(
e
=>
e
.
Id
==
id
);
}
public
List
<
T
>
List
<
T
>()
where
T
:
BaseEntity
...
...
@@ -39,10 +39,16 @@ namespace CleanArchitecture.Infrastructure.Data
_dbContext
.
SaveChanges
();
}
public
void
Update
<
T
>(
T
entity
)
where
T
:
BaseEntity
public
void
Update
UsingOriginalMethod
<
T
>(
T
entity
)
where
T
:
BaseEntity
{
_dbContext
.
Entry
(
entity
).
State
=
EntityState
.
Modified
;
_dbContext
.
SaveChanges
();
}
public
void
UpdateUsingDbContextUpdate
<
T
>(
T
entity
)
where
T
:
BaseEntity
{
_dbContext
.
Update
(
entity
);
_dbContext
.
SaveChanges
();
}
}
}
src/CleanArchitecture.Infrastructure/Migrations/20190516105250_Foo.Designer.cs
0 → 100644
View file @
6ed7a977
// <auto-generated />
using
System
;
using
CleanArchitecture.Infrastructure.Data
;
using
Microsoft.EntityFrameworkCore
;
using
Microsoft.EntityFrameworkCore.Infrastructure
;
using
Microsoft.EntityFrameworkCore.Metadata
;
using
Microsoft.EntityFrameworkCore.Migrations
;
using
Microsoft.EntityFrameworkCore.Storage.ValueConversion
;
namespace
CleanArchitecture.Infrastructure.Migrations
{
[
DbContext
(
typeof
(
AppDbContext
))]
[
Migration
(
"20190516105250_Foo"
)]
partial
class
Foo
{
protected
override
void
BuildTargetModel
(
ModelBuilder
modelBuilder
)
{
#pragma warning disable 612, 618
modelBuilder
.
HasAnnotation
(
"ProductVersion"
,
"2.1.11-servicing-32099"
)
.
HasAnnotation
(
"Relational:MaxIdentifierLength"
,
128
)
.
HasAnnotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
);
modelBuilder
.
Entity
(
"CleanArchitecture.Core.Entities.Bar"
,
b
=>
{
b
.
Property
<
int
>(
"Id"
)
.
ValueGeneratedOnAdd
()
.
HasAnnotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
);
b
.
Property
<
int
>(
"Number"
);
b
.
HasKey
(
"Id"
);
b
.
ToTable
(
"Bars"
);
});
modelBuilder
.
Entity
(
"CleanArchitecture.Core.Entities.Foo"
,
b
=>
{
b
.
Property
<
int
>(
"Id"
)
.
ValueGeneratedOnAdd
()
.
HasAnnotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
);
b
.
Property
<
int
?>(
"BarId"
);
b
.
Property
<
string
>(
"Name"
);
b
.
HasKey
(
"Id"
);
b
.
HasIndex
(
"BarId"
);
b
.
ToTable
(
"Foos"
);
});
modelBuilder
.
Entity
(
"CleanArchitecture.Core.Entities.ToDoItem"
,
b
=>
{
b
.
Property
<
int
>(
"Id"
)
.
ValueGeneratedOnAdd
()
.
HasAnnotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
);
b
.
Property
<
string
>(
"Description"
);
b
.
Property
<
bool
>(
"IsDone"
);
b
.
Property
<
string
>(
"Title"
);
b
.
HasKey
(
"Id"
);
b
.
ToTable
(
"ToDoItems"
);
});
modelBuilder
.
Entity
(
"CleanArchitecture.Core.Entities.Foo"
,
b
=>
{
b
.
HasOne
(
"CleanArchitecture.Core.Entities.Bar"
,
"Bar"
)
.
WithMany
()
.
HasForeignKey
(
"BarId"
);
});
#pragma warning restore 612, 618
}
}
}
src/CleanArchitecture.Infrastructure/Migrations/20190516105250_Foo.cs
0 → 100644
View file @
6ed7a977
using
Microsoft.EntityFrameworkCore.Metadata
;
using
Microsoft.EntityFrameworkCore.Migrations
;
namespace
CleanArchitecture.Infrastructure.Migrations
{
public
partial
class
Foo
:
Migration
{
protected
override
void
Up
(
MigrationBuilder
migrationBuilder
)
{
migrationBuilder
.
CreateTable
(
name
:
"Bars"
,
columns
:
table
=>
new
{
Id
=
table
.
Column
<
int
>(
nullable
:
false
)
.
Annotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
),
Number
=
table
.
Column
<
int
>(
nullable
:
false
)
},
constraints
:
table
=>
{
table
.
PrimaryKey
(
"PK_Bars"
,
x
=>
x
.
Id
);
});
migrationBuilder
.
CreateTable
(
name
:
"ToDoItems"
,
columns
:
table
=>
new
{
Id
=
table
.
Column
<
int
>(
nullable
:
false
)
.
Annotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
),
Title
=
table
.
Column
<
string
>(
nullable
:
true
),
Description
=
table
.
Column
<
string
>(
nullable
:
true
),
IsDone
=
table
.
Column
<
bool
>(
nullable
:
false
)
},
constraints
:
table
=>
{
table
.
PrimaryKey
(
"PK_ToDoItems"
,
x
=>
x
.
Id
);
});
migrationBuilder
.
CreateTable
(
name
:
"Foos"
,
columns
:
table
=>
new
{
Id
=
table
.
Column
<
int
>(
nullable
:
false
)
.
Annotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
),
BarId
=
table
.
Column
<
int
>(
nullable
:
true
),
Name
=
table
.
Column
<
string
>(
nullable
:
true
)
},
constraints
:
table
=>
{
table
.
PrimaryKey
(
"PK_Foos"
,
x
=>
x
.
Id
);
table
.
ForeignKey
(
name
:
"FK_Foos_Bars_BarId"
,
column
:
x
=>
x
.
BarId
,
principalTable
:
"Bars"
,
principalColumn
:
"Id"
,
onDelete
:
ReferentialAction
.
Restrict
);
});
migrationBuilder
.
CreateIndex
(
name
:
"IX_Foos_BarId"
,
table
:
"Foos"
,
column
:
"BarId"
);
}
protected
override
void
Down
(
MigrationBuilder
migrationBuilder
)
{
migrationBuilder
.
DropTable
(
name
:
"Foos"
);
migrationBuilder
.
DropTable
(
name
:
"ToDoItems"
);
migrationBuilder
.
DropTable
(
name
:
"Bars"
);
}
}
}
src/CleanArchitecture.Infrastructure/Migrations/AppDbContextModelSnapshot.cs
0 → 100644
View file @
6ed7a977
// <auto-generated />
using
System
;
using
CleanArchitecture.Infrastructure.Data
;
using
Microsoft.EntityFrameworkCore
;
using
Microsoft.EntityFrameworkCore.Infrastructure
;
using
Microsoft.EntityFrameworkCore.Metadata
;
using
Microsoft.EntityFrameworkCore.Storage.ValueConversion
;
namespace
CleanArchitecture.Infrastructure.Migrations
{
[
DbContext
(
typeof
(
AppDbContext
))]
partial
class
AppDbContextModelSnapshot
:
ModelSnapshot
{
protected
override
void
BuildModel
(
ModelBuilder
modelBuilder
)
{
#pragma warning disable 612, 618
modelBuilder
.
HasAnnotation
(
"ProductVersion"
,
"2.1.11-servicing-32099"
)
.
HasAnnotation
(
"Relational:MaxIdentifierLength"
,
128
)
.
HasAnnotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
);
modelBuilder
.
Entity
(
"CleanArchitecture.Core.Entities.Bar"
,
b
=>
{
b
.
Property
<
int
>(
"Id"
)
.
ValueGeneratedOnAdd
()
.
HasAnnotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
);
b
.
Property
<
int
>(
"Number"
);
b
.
HasKey
(
"Id"
);
b
.
ToTable
(
"Bars"
);
});
modelBuilder
.
Entity
(
"CleanArchitecture.Core.Entities.Foo"
,
b
=>
{
b
.
Property
<
int
>(
"Id"
)
.
ValueGeneratedOnAdd
()
.
HasAnnotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
);
b
.
Property
<
int
?>(
"BarId"
);
b
.
Property
<
string
>(
"Name"
);
b
.
HasKey
(
"Id"
);
b
.
HasIndex
(
"BarId"
);
b
.
ToTable
(
"Foos"
);
});
modelBuilder
.
Entity
(
"CleanArchitecture.Core.Entities.ToDoItem"
,
b
=>
{
b
.
Property
<
int
>(
"Id"
)
.
ValueGeneratedOnAdd
()
.
HasAnnotation
(
"SqlServer:ValueGenerationStrategy"
,
SqlServerValueGenerationStrategy
.
IdentityColumn
);
b
.
Property
<
string
>(
"Description"
);
b
.
Property
<
bool
>(
"IsDone"
);
b
.
Property
<
string
>(
"Title"
);
b
.
HasKey
(
"Id"
);
b
.
ToTable
(
"ToDoItems"
);
});
modelBuilder
.
Entity
(
"CleanArchitecture.Core.Entities.Foo"
,
b
=>
{
b
.
HasOne
(
"CleanArchitecture.Core.Entities.Bar"
,
"Bar"
)
.
WithMany
()
.
HasForeignKey
(
"BarId"
);
});
#pragma warning restore 612, 618
}
}
}
src/CleanArchitecture.Web/Api/ToDoItemsController.cs
View file @
6ed7a977
...
...
@@ -51,7 +51,7 @@ namespace CleanArchitecture.Web.Api
{
var
toDoItem
=
_repository
.
GetById
<
ToDoItem
>(
id
);
toDoItem
.
MarkComplete
();
_repository
.
Update
(
toDoItem
);
_repository
.
Update
UsingOriginalMethod
(
toDoItem
);
return
Ok
(
ToDoItemDTO
.
FromToDoItem
(
toDoItem
));
}
...
...
src/CleanArchitecture.Web/Controllers/HomeController.cs
View file @
6ed7a977
using
Microsoft.AspNetCore.Mvc
;
using
CleanArchitecture.Core.Entities
;
using
CleanArchitecture.Core.Interfaces
;
using
Microsoft.AspNetCore.Mvc
;
using
System.Threading
;
namespace
CleanArchitecture.Web.Controllers
{
public
class
HomeController
:
Controller
{
private
readonly
IRepository
_repository
;
public
HomeController
(
IRepository
repository
)
{
_repository
=
repository
;
}
public
IActionResult
Index
()
{
return
View
();
Foo
foo
=
_repository
.
GetById
<
Foo
>(
1
);
Foo
originalFoo
=
new
Foo
{
Name
=
foo
.
Name
,
Bar
=
new
Bar
{
Number
=
foo
.
Bar
.
Number
}
};
if
(
foo
==
null
)
{
throw
new
AbandonedMutexException
(
"Gotta make a foo first!"
);
}
public
IActionResult
Error
(
)
if
(
foo
.
Name
==
"Scott"
)
{
return
View
(
);
return
View
(
foo
);
}
foo
.
Name
=
"Scott"
;
foo
.
Bar
.
Number
++;
// Choose which Update method to call here.
_repository
.
UpdateUsingOriginalMethod
(
foo
);
// Original code, setting entity's state to EntityState.Modified.
// _repository.UpdateUsingDbContextUpdate(foo); // New code, calling dbContext.Update(entity).
return
View
(
originalFoo
);
}
public
IActionResult
Error
()
=>
View
();
}
}
src/CleanArchitecture.Web/Controllers/ToDoController.cs
View file @
6ed7a977
...
...
@@ -16,8 +16,7 @@ namespace CleanArchitecture.Web.Controllers
public
IActionResult
Index
()
{
var
items
=
_repository
.
List
<
ToDoItem
>();
return
View
(
items
);
return
View
(
_repository
.
GetById
<
Foo
>(
1
));
}
public
IActionResult
Populate
()
...
...
src/CleanArchitecture.Web/Program.cs
View file @
6ed7a977
using
Microsoft.AspNetCore
;
using
CleanArchitecture.Infrastructure.Data
;
using
Microsoft.AspNetCore
;
using
Microsoft.AspNetCore.Hosting
;
using
Microsoft.Extensions.DependencyInjection
;
using
System
;
namespace
CleanArchitecture.Web
{
...
...
@@ -7,7 +10,23 @@ namespace CleanArchitecture.Web
{
public
static
void
Main
(
string
[]
args
)
{
CreateWebHostBuilder
(
args
).
Build
().
Run
();
IWebHost
host
=
CreateWebHostBuilder
(
args
).
Build
();
using
(
var
scope
=
host
.
Services
.
CreateScope
())
{
var
services
=
scope
.
ServiceProvider
;
try
{
var
dbContext
=
services
.
GetRequiredService
<
AppDbContext
>();
SeedData
.
PopulateTestData
(
dbContext
);
}
catch
(
Exception
ex
)
{
Console
.
WriteLine
(
$"Error:
{
ex
}
"
);
}
}
host
.
Run
();
}
public
static
IWebHostBuilder
CreateWebHostBuilder
(
string
[]
args
)
=>
...
...
src/CleanArchitecture.Web/SeedData.cs
View file @
6ed7a977
using
CleanArchitecture.Core.Entities
;
using
CleanArchitecture.Infrastructure.Data
;
using
Microsoft.EntityFrameworkCore
;
using
System.Linq
;
namespace
CleanArchitecture.Web
{
...
...
@@ -7,6 +9,14 @@ namespace CleanArchitecture.Web
{
public
static
void
PopulateTestData
(
AppDbContext
dbContext
)
{
if
(
dbContext
.
ToDoItems
.
Any
())
{
Foo
single
=
dbContext
.
Foos
.
Include
(
"Bar"
).
Single
();
single
.
Name
=
"Steve"
;
single
.
Bar
.
Number
=
5
;
dbContext
.
SaveChanges
();
return
;
}
var
toDos
=
dbContext
.
ToDoItems
;
foreach
(
var
item
in
toDos
)
{
...
...
@@ -23,6 +33,8 @@ namespace CleanArchitecture.Web
Title
=
"Test Item 2"
,
Description
=
"Test Description Two"
});
dbContext
.
Foos
.
Add
(
new
Foo
{
Name
=
"Steve"
,
Bar
=
new
Bar
{
Number
=
5
}
});
dbContext
.
SaveChanges
();
}
...
...
src/CleanArchitecture.Web/Views/Home/Index.cshtml
View file @
6ed7a977
@{
@model CleanArchitecture.Core.Entities.Foo
@{
ViewData["Title"] = "Clean DDD Architecture Sample";
}
<div class="row">
<div class="col-md-6">
<h2>
To Do Items (MVC)
</h2>
<h2>
Update Experiment
</h2>
<ul>
<li><a asp-area="" asp-controller="ToDo" asp-action="Populate">Load Sample To Do Items</a> (API call returning just a number)</li>
<li><a asp-area="" asp-controller="ToDo" asp-action="Index">List To Do Items</a></li>
<li><a href="/swagger">API Documentation (Swagger)</a></li>
</ul>
<h2>To Do Items (Razor Pages)</h2>
<ul>
<li><a asp-page="/ToDoRazorPage/Populate">Load Sample To Do Items</a></li>
<li><a asp-page="/ToDoRazorPage/Index">List To Do Items</a></li>
@if (Model.Name == "Scott")
{
<li>Experiment already run. To see again, restart application.</li>
}
else
{
<li>Model with nested entity original state: (Foo.Name - @Model.Name | Foo.Bar.Number: @Model.Bar.Number)</li>
<li><a asp-area="" asp-controller="ToDo" asp-action="Index">Click here to see if update worked</a></li>
}
</ul>
</div>
<div class="col-md-6">
...
...
src/CleanArchitecture.Web/Views/ToDo/Index.cshtml
View file @
6ed7a977
@{
ViewData["Title"] = "ToDo List";
}
@model
IEnumerable<CleanArchitecture.Core.Entities.ToDoItem>
<h2>
To Do Items (MVC View)
</h2>
@model
CleanArchitecture.Core.Entities.Foo
<h2>
Update Experiment
</h2>
<ul>
@foreach (var item in Model)
{
<li>@item.Title<br/>@item.Description</li>
}
<li>Updated Entity State. If update worked, then Name should go from Steve to Scott, and if nested update worked, then Bar.Number should have increased from 5 to 6.</li>
<li>(Foo.Name - @Model.Name | Foo.Bar.Number: @Model.Bar.Number)</li>
</ul>
tests/CleanArchitecture.Tests/Integration/Data/EfRepositoryUpdate.cs
View file @
6ed7a977
...
...
@@ -30,7 +30,7 @@ namespace CleanArchitecture.Tests.Integration.Data
newItem
.
Title
=
newTitle
;
// Update the item
repository
.
Update
(
newItem
);
repository
.
Update
UsingOriginalMethod
(
newItem
);
var
updatedItem
=
repository
.
List
<
ToDoItem
>()
.
FirstOrDefault
(
i
=>
i
.
Title
==
newTitle
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment