diff --git a/CSInn.sln b/CSInn.sln index 4506e73..ab87340 100644 --- a/CSInn.sln +++ b/CSInn.sln @@ -1,95 +1,102 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29306.81 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{186B0C3C-02E4-416C-9CD1-067E7662A53E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{399E33DB-3837-48F0-BFFA-B756D995BD2D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.UI", "src\CSInn.UI\CSInn.UI.csproj", "{B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Discord.Authentication", "src\CSInn.Discord.Authentication\CSInn.Discord.Authentication.csproj", "{4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Application.Tests", "tests\CSInn.Application.Tests\CSInn.Application.Tests.csproj", "{B92834CE-81D2-4E82-86CA-4940CFB8A102}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Domain.Repositories", "src\CSInn.Domain.Repositories\CSInn.Domain.Repositories.csproj", "{C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Infrastructure.Repositories", "src\CSInn.Infrastructure.Repositories\CSInn.Infrastructure.Repositories.csproj", "{68360ABC-FFEC-4A14-94EC-DCA6B96C044E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Application", "src\CSInn.Application\CSInn.Application.csproj", "{9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Discord.Authentication.Tests", "tests\CSInn.Discord.Authentication.Tests\CSInn.Discord.Authentication.Tests.csproj", "{989E16D6-A255-4AC5-BAE1-3D78B38EE258}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.UI.Tests", "tests\CSInn.UI.Tests\CSInn.UI.Tests.csproj", "{2159A971-3858-48F0-99B4-6F40C4F50863}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Infrastructure.Repositories.Tests", "tests\CSInn.Infrastructure.Repositories.Tests\CSInn.Infrastructure.Repositories.Tests.csproj", "{1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Models", "src\CSInn.Models\CSInn.Models.csproj", "{A4D369D6-4937-4BB4-8F90-89DBCADE1481}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}.Release|Any CPU.Build.0 = Release|Any CPU - {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}.Release|Any CPU.Build.0 = Release|Any CPU - {B92834CE-81D2-4E82-86CA-4940CFB8A102}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B92834CE-81D2-4E82-86CA-4940CFB8A102}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B92834CE-81D2-4E82-86CA-4940CFB8A102}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B92834CE-81D2-4E82-86CA-4940CFB8A102}.Release|Any CPU.Build.0 = Release|Any CPU - {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}.Release|Any CPU.Build.0 = Release|Any CPU - {68360ABC-FFEC-4A14-94EC-DCA6B96C044E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68360ABC-FFEC-4A14-94EC-DCA6B96C044E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68360ABC-FFEC-4A14-94EC-DCA6B96C044E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68360ABC-FFEC-4A14-94EC-DCA6B96C044E}.Release|Any CPU.Build.0 = Release|Any CPU - {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}.Release|Any CPU.Build.0 = Release|Any CPU - {989E16D6-A255-4AC5-BAE1-3D78B38EE258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {989E16D6-A255-4AC5-BAE1-3D78B38EE258}.Debug|Any CPU.Build.0 = Debug|Any CPU - {989E16D6-A255-4AC5-BAE1-3D78B38EE258}.Release|Any CPU.ActiveCfg = Release|Any CPU - {989E16D6-A255-4AC5-BAE1-3D78B38EE258}.Release|Any CPU.Build.0 = Release|Any CPU - {2159A971-3858-48F0-99B4-6F40C4F50863}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2159A971-3858-48F0-99B4-6F40C4F50863}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2159A971-3858-48F0-99B4-6F40C4F50863}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2159A971-3858-48F0-99B4-6F40C4F50863}.Release|Any CPU.Build.0 = Release|Any CPU - {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}.Release|Any CPU.Build.0 = Release|Any CPU - {A4D369D6-4937-4BB4-8F90-89DBCADE1481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A4D369D6-4937-4BB4-8F90-89DBCADE1481}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A4D369D6-4937-4BB4-8F90-89DBCADE1481}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A4D369D6-4937-4BB4-8F90-89DBCADE1481}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} - {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} - {B92834CE-81D2-4E82-86CA-4940CFB8A102} = {399E33DB-3837-48F0-BFFA-B756D995BD2D} - {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} - {68360ABC-FFEC-4A14-94EC-DCA6B96C044E} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} - {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} - {989E16D6-A255-4AC5-BAE1-3D78B38EE258} = {399E33DB-3837-48F0-BFFA-B756D995BD2D} - {2159A971-3858-48F0-99B4-6F40C4F50863} = {399E33DB-3837-48F0-BFFA-B756D995BD2D} - {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7} = {399E33DB-3837-48F0-BFFA-B756D995BD2D} - {A4D369D6-4937-4BB4-8F90-89DBCADE1481} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6BBE2057-901B-474F-9140-0D045DF18046} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29306.81 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{186B0C3C-02E4-416C-9CD1-067E7662A53E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{399E33DB-3837-48F0-BFFA-B756D995BD2D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.UI", "src\CSInn.UI\CSInn.UI.csproj", "{B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Discord.Authentication", "src\CSInn.Discord.Authentication\CSInn.Discord.Authentication.csproj", "{4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Application.Tests", "tests\CSInn.Application.Tests\CSInn.Application.Tests.csproj", "{B92834CE-81D2-4E82-86CA-4940CFB8A102}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Domain.Repositories", "src\CSInn.Domain.Repositories\CSInn.Domain.Repositories.csproj", "{C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Infrastructure.Repositories", "src\CSInn.Infrastructure.Repositories\CSInn.Infrastructure.Repositories.csproj", "{68360ABC-FFEC-4A14-94EC-DCA6B96C044E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Application", "src\CSInn.Application\CSInn.Application.csproj", "{9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Discord.Authentication.Tests", "tests\CSInn.Discord.Authentication.Tests\CSInn.Discord.Authentication.Tests.csproj", "{989E16D6-A255-4AC5-BAE1-3D78B38EE258}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.UI.Tests", "tests\CSInn.UI.Tests\CSInn.UI.Tests.csproj", "{2159A971-3858-48F0-99B4-6F40C4F50863}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Infrastructure.Repositories.Tests", "tests\CSInn.Infrastructure.Repositories.Tests\CSInn.Infrastructure.Repositories.Tests.csproj", "{1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSInn.Models", "src\CSInn.Models\CSInn.Models.csproj", "{A4D369D6-4937-4BB4-8F90-89DBCADE1481}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp1", "ConsoleApp1\ConsoleApp1.csproj", "{EBBFB2B3-35F1-4B87-B9D1-7260A3825CDC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB}.Release|Any CPU.Build.0 = Release|Any CPU + {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5}.Release|Any CPU.Build.0 = Release|Any CPU + {B92834CE-81D2-4E82-86CA-4940CFB8A102}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B92834CE-81D2-4E82-86CA-4940CFB8A102}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B92834CE-81D2-4E82-86CA-4940CFB8A102}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B92834CE-81D2-4E82-86CA-4940CFB8A102}.Release|Any CPU.Build.0 = Release|Any CPU + {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64}.Release|Any CPU.Build.0 = Release|Any CPU + {68360ABC-FFEC-4A14-94EC-DCA6B96C044E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68360ABC-FFEC-4A14-94EC-DCA6B96C044E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68360ABC-FFEC-4A14-94EC-DCA6B96C044E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68360ABC-FFEC-4A14-94EC-DCA6B96C044E}.Release|Any CPU.Build.0 = Release|Any CPU + {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73}.Release|Any CPU.Build.0 = Release|Any CPU + {989E16D6-A255-4AC5-BAE1-3D78B38EE258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {989E16D6-A255-4AC5-BAE1-3D78B38EE258}.Debug|Any CPU.Build.0 = Debug|Any CPU + {989E16D6-A255-4AC5-BAE1-3D78B38EE258}.Release|Any CPU.ActiveCfg = Release|Any CPU + {989E16D6-A255-4AC5-BAE1-3D78B38EE258}.Release|Any CPU.Build.0 = Release|Any CPU + {2159A971-3858-48F0-99B4-6F40C4F50863}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2159A971-3858-48F0-99B4-6F40C4F50863}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2159A971-3858-48F0-99B4-6F40C4F50863}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2159A971-3858-48F0-99B4-6F40C4F50863}.Release|Any CPU.Build.0 = Release|Any CPU + {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7}.Release|Any CPU.Build.0 = Release|Any CPU + {A4D369D6-4937-4BB4-8F90-89DBCADE1481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A4D369D6-4937-4BB4-8F90-89DBCADE1481}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4D369D6-4937-4BB4-8F90-89DBCADE1481}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A4D369D6-4937-4BB4-8F90-89DBCADE1481}.Release|Any CPU.Build.0 = Release|Any CPU + {EBBFB2B3-35F1-4B87-B9D1-7260A3825CDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBBFB2B3-35F1-4B87-B9D1-7260A3825CDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBBFB2B3-35F1-4B87-B9D1-7260A3825CDC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBBFB2B3-35F1-4B87-B9D1-7260A3825CDC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {B6E0D216-88C8-4BA1-A71C-7C6BDB4247BB} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} + {4BA8C0D8-A2CA-4E84-B018-644C2859F5A5} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} + {B92834CE-81D2-4E82-86CA-4940CFB8A102} = {399E33DB-3837-48F0-BFFA-B756D995BD2D} + {C0BCA68B-7CD7-4037-8DEF-3C1DFA0FFA64} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} + {68360ABC-FFEC-4A14-94EC-DCA6B96C044E} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} + {9FC69081-2A6A-4990-ACC3-4D1A1D08AA73} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} + {989E16D6-A255-4AC5-BAE1-3D78B38EE258} = {399E33DB-3837-48F0-BFFA-B756D995BD2D} + {2159A971-3858-48F0-99B4-6F40C4F50863} = {399E33DB-3837-48F0-BFFA-B756D995BD2D} + {1B2CDA69-B45A-4F95-B5C9-7AC3F834A7B7} = {399E33DB-3837-48F0-BFFA-B756D995BD2D} + {A4D369D6-4937-4BB4-8F90-89DBCADE1481} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} + {EBBFB2B3-35F1-4B87-B9D1-7260A3825CDC} = {186B0C3C-02E4-416C-9CD1-067E7662A53E} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6BBE2057-901B-474F-9140-0D045DF18046} + EndGlobalSection +EndGlobal diff --git a/ConsoleApp1/ConsoleApp1.csproj b/ConsoleApp1/ConsoleApp1.csproj new file mode 100644 index 0000000..fb4ca05 --- /dev/null +++ b/ConsoleApp1/ConsoleApp1.csproj @@ -0,0 +1,41 @@ + + + + Exe + netcoreapp3.0 + + + + + + + + + + PreserveNewest + true + PreserveNewest + + + PreserveNewest + true + PreserveNewest + + + + + + + + + + + + + + + + + + + diff --git a/ConsoleApp1/Program - Copy.cs b/ConsoleApp1/Program - Copy.cs new file mode 100644 index 0000000..c3032dc --- /dev/null +++ b/ConsoleApp1/Program - Copy.cs @@ -0,0 +1,34 @@ +using CSInn.Infrastructure.Repositories.Entities; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ConsoleApp1 +{ + class Program_old + { + static void Main_old(string[] args) + { + /* + List test_list = new List() + { + new LessonEntity() { entity_test = "1"}, + new LessonEntity() { entity_test = "2"}, + new LessonEntity() { entity_test = "3"}, + new LessonEntity() { entity_test = "4"}, + new LessonEntity() { entity_test = "5"}, + }; + + + IQueryable EntitySet = (from p in test_list select p).AsQueryable(); + + var dao = new LessonDao(EntitySet); + var dto = new LessonDto(dao); + + var result = dto.findByTest("2"); + Console.WriteLine($"cout: {result.Count}"); + Console.WriteLine($"model_test: {result[0].model_test}"); + */ + } + } +} diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs new file mode 100644 index 0000000..aac2b17 --- /dev/null +++ b/ConsoleApp1/Program.cs @@ -0,0 +1,58 @@ +using CSInn.Infrastructure.Repositories.Context; +using CSInn.Infrastructure.Repositories.Entities; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using CSInn.Infrastructure.Repositories.UoW; +using CSInn.Models; +using Microsoft.Extensions.Configuration; +using System.Configuration; +using System.IO; + +namespace ConsoleApp1 +{ + class Program + { + + static void Main(string[] args) + { + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); + + IConfigurationRoot configuration = builder.Build(); + + var options = new DbContextOptionsBuilder() + .UseSqlServer(configuration.GetConnectionString("CSINN")) + .Options; + + // .UseInMemoryDatabase(databaseName: "database_name") + // .Options; + // + + var context = new CSInnDbContext(options); + var dbSet = context.Set(); + + if (dbSet.Any()) + Console.WriteLine("has stuff"); + else + { + for (int i = 0; i < 5; ++i) + dbSet.Add(new LessonEntity() { entity_test = "" + i }); + + context.SaveChanges(); + } + + IQueryable EntitySet = dbSet; + var dao = new LessonDao(EntitySet); + var dto = new LessonDto(dao); + + var result = dto.findByTest("2", "tmp"); + + Console.WriteLine($"cout: {result.Count}"); + foreach(var r in result) + Console.WriteLine($"model_test: {r.model_test}"); + } + } +} diff --git a/ConsoleApp1/allthestuff.cs b/ConsoleApp1/allthestuff.cs new file mode 100644 index 0000000..0dd038d --- /dev/null +++ b/ConsoleApp1/allthestuff.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using AutoMapper; +using CSInn.Models; +using CSInn.Infrastructure.Repositories.Entities; + +namespace ConsoleApp1 +{ + public static class Mapper + { + #region basic + public static readonly Dictionary> classMemberMapping = new Dictionary>(); + private static IMapper mapper; + + static Mapper() + { + var config = new AutoMapper.MapperConfiguration(cfg => { + map(cfg) + .bind(src => src.entity_test, dest => dest.model_test); + }); + + mapper = config.CreateMapper(); + } + + private class Mapping + { + public AutoMapper.IMappingExpression map1; + public AutoMapper.IMappingExpression map2; + + private string getMemberName(Expression> ex) + { + if (ex.Body is MemberExpression) + return (ex.Body as MemberExpression).Member.Name; + else if (ex.Body is UnaryExpression) + return ((ex.Body as UnaryExpression).Operand as MemberExpression).Member.Name; + else + return null; + } + public Mapping bind(Expression> left, Expression> right) + { + string leftMember = getMemberName(left); + string rightMember = getMemberName(right); + Dictionary memberMapping = classMemberMapping[typeof(TSource).Name]; + memberMapping[leftMember] = rightMember; + + map2.ForMember(left, opt => opt.MapFrom(right)); + map1.ForMember(right, opt => opt.MapFrom(left)); + return this; + } + } + + private static Mapping map(AutoMapper.IMapperConfigurationExpression cfg) + { + classMemberMapping[typeof(TSource).Name] = new Dictionary(); + + return new Mapping() + { + map1 = cfg.CreateMap(), + map2 = cfg.CreateMap() + }; + } + #endregion + + + public static TModel mapEntityToModel(TEntity entity) where TModel : new() + { + TModel model = new TModel(); + mapper.Map(entity, model); + return model; + } + + public static List mapListEntityToModel(List listEntities) where TModel : new() + { + List listModel = new List(); + foreach (TEntity entity in listEntities) + { + TModel model = mapEntityToModel(entity); + listModel.Add(model); + } + return listModel; + } + + public static TEntity mapModelToEntity(TModel model) where TEntity : new() + { + TEntity entity = new TEntity(); + mapper.Map(model, entity); + return entity; + } + } + + public static class DaoLambdaExtension + { + public static string GetCacheKey() + { + return string.Concat(typeof(TSource).FullName, typeof(TDest).FullName); + } + + public static IEnumerable createMemberBinding(ParameterExpression parameterExpression) + { + string[] SourceExcludedMembers = { "Tags", "Authors" }; + string[] DestExcludedMembers = { "Tags", "Authors" }; + var sourceProperties = typeof(TSource).GetProperties().Where(src => !SourceExcludedMembers.Contains(src.Name)); + var destinationProperties = typeof(TDest).GetProperties().Where(dest => dest.CanWrite & !DestExcludedMembers.Contains(dest.Name)); + Dictionary memberMapping = Mapper.classMemberMapping[typeof(TSource).Name]; + + var bindings = destinationProperties + .Select(destinationProperty => BuildBinding(memberMapping, parameterExpression, destinationProperty, sourceProperties)) + .Where(d => d != null); + + return bindings; + } + + private static bool propertiesEqual(Dictionary memberMapping, string dest, string src) + { + string mapp; + if (!memberMapping.TryGetValue(src, out mapp)) + return false; + return dest == mapp; + } + + private static MemberAssignment BuildBinding(Dictionary memberMapping, + Expression parameterExpression, MemberInfo destinationProperty, IEnumerable sourceProperties) + { + var sourceProperty = sourceProperties.FirstOrDefault(src => src.Name.ToLower() == destinationProperty.Name.ToLower() + || (propertiesEqual(memberMapping, destinationProperty.Name, src.Name))); + + if (sourceProperty == null) + return null; + + return Expression.Bind(destinationProperty, Expression.Property(parameterExpression, sourceProperty)); + } + } + + + public class ProjectionExpression + { + private readonly IQueryable _source; + + private static readonly Dictionary ExpressionCache = new Dictionary(); + + public ProjectionExpression(IQueryable source) + { + _source = source; + } + + public IQueryable To() + { + var queryExpression = GetCachedExpression() ?? BuildExpression(); + + return _source.Select(queryExpression); + } + + private static Expression> GetCachedExpression() + { + var key = DaoLambdaExtension.GetCacheKey(); + + return ExpressionCache.ContainsKey(key) ? ExpressionCache[key] as Expression> : null; + } + + private static Expression> BuildExpression() + { + var parameterExpression = Expression.Parameter(typeof(TSource), "src"); + var bindings = DaoLambdaExtension.createMemberBinding(parameterExpression); + + var expression = Expression.Lambda>(Expression.MemberInit(Expression.New(typeof(TDest)), bindings), parameterExpression); + + var key = DaoLambdaExtension.GetCacheKey(); + ExpressionCache.Add(key, expression); + + return expression; + } + } + + public static class ObjectSetExtensions + { + public static ProjectionExpression Project( + this IQueryable source) + { + return new ProjectionExpression(source); + } + } + + public abstract class BasicDao + { + protected string entitySetName; + public IQueryable EntitySet; + } + + public class LessonDao : BasicDao + { + public LessonDao(IQueryable EntitySet) + { + this.EntitySet = EntitySet; + } + } + + + public abstract class BasicDto + where TEntity : new() + where TModel : new() + { + protected BasicDao dao; + + public BasicDto(BasicDao dao) { this.dao = dao; } + + public IQueryable get() + { + return dao.EntitySet.Project().To(); + } + } + + public class LessonDto : BasicDto + { + public LessonDto(BasicDao dao) + : base(dao) + { } + + public List findByTest(string test, string desc) + { + var lessonModelList = + /* + (from p in get() + where !p.model_test.Equals(test) + select p) + */ + get() + .Where(p => !p.model_test.Equals(test)) + .Where(p => p.Description == desc) + .ToList(); + + + return lessonModelList; + } + } +} diff --git a/ConsoleApp1/appsettings.Development.json b/ConsoleApp1/appsettings.Development.json new file mode 100644 index 0000000..e203e94 --- /dev/null +++ b/ConsoleApp1/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/ConsoleApp1/appsettings.json b/ConsoleApp1/appsettings.json new file mode 100644 index 0000000..3267a7c --- /dev/null +++ b/ConsoleApp1/appsettings.json @@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "CSINN": "Server=.;Database=CSINN;Trusted_Connection=True;MultipleActiveResultSets=true" + } +} diff --git a/src/CSInn.Domain.Repositories/Extensions/SpecificationExtensions.cs b/src/CSInn.Domain.Repositories/Extensions/SpecificationExtensions.cs new file mode 100644 index 0000000..89172d2 --- /dev/null +++ b/src/CSInn.Domain.Repositories/Extensions/SpecificationExtensions.cs @@ -0,0 +1,25 @@ +using CSInn.Domain.Repositories.Specifications.Base; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CSInn.Domain.Repositories.Extensions +{ + public static class SpecificationExtensions + { + public static ISpecification And(this ISpecification left, ISpecification right) where TVisitor : ISpecificationVisitor + { + return new AndSpecification(left, right); + } + + public static ISpecification Or(this ISpecification left, ISpecification right) where TVisitor : ISpecificationVisitor + { + return new OrSpecification(left, right); + } + + public static ISpecification Not(this ISpecification specification) where TVisitor : ISpecificationVisitor + { + return new NotSpecification(specification); + } + } +} diff --git a/src/CSInn.Domain.Repositories/ILessonsRepository.cs b/src/CSInn.Domain.Repositories/ILessonsRepository.cs deleted file mode 100644 index 874bdc2..0000000 --- a/src/CSInn.Domain.Repositories/ILessonsRepository.cs +++ /dev/null @@ -1,15 +0,0 @@ -using CSInn.Domain.Models.Content; -using System; -using System.Collections.Generic; - -namespace CSInn.Domain.Repositories -{ - public interface ILessonsRepository : IRepository - { - // TODO: Specification pattern so we can mix criterias. - IEnumerable GetByTags(params string[] tags); - IEnumerable GetByName(string name); - IEnumerable GetByAuthors(params string[] authors); - IEnumerable GetByDate(DateTime from, DateTime to); - } -} diff --git a/src/CSInn.Domain.Repositories/IRepository.cs b/src/CSInn.Domain.Repositories/IRepository.cs deleted file mode 100644 index f4f6192..0000000 --- a/src/CSInn.Domain.Repositories/IRepository.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace CSInn.Domain.Repositories -{ - public interface IRepository where TModel : class - { - void Create(TModel model); - void Update(TModel model); - void Delete(int key); - IEnumerable Get(); - TModel Get(int id); - } -} diff --git a/src/CSInn.Domain.Repositories/Repositories/ILessonsRepository.cs b/src/CSInn.Domain.Repositories/Repositories/ILessonsRepository.cs new file mode 100644 index 0000000..3cd8e13 --- /dev/null +++ b/src/CSInn.Domain.Repositories/Repositories/ILessonsRepository.cs @@ -0,0 +1,16 @@ +using CSInn.Domain.Repositories.Specifications.Lesson; +using CSInn.Models; + +namespace CSInn.Domain.Repositories.Repositories +{ + public interface ILessonsRepository : IRepository, + IRepositoryAsync + { + //// TODO: Specification pattern so we can mix criterias. + //IEnumerable GetByTags(params string[] tags); + //IEnumerable GetByName(string name); + //IEnumerable GetByAuthors(params string[] authors); + //IEnumerable GetByDate(DateTime from, DateTime to); + //IEnumerable Get(Specification specification); + } +} diff --git a/src/CSInn.Domain.Repositories/Repositories/IRepository.cs b/src/CSInn.Domain.Repositories/Repositories/IRepository.cs new file mode 100644 index 0000000..0a310de --- /dev/null +++ b/src/CSInn.Domain.Repositories/Repositories/IRepository.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using CSInn.Domain.Repositories.Specifications.Base; + +namespace CSInn.Domain.Repositories.Repositories +{ + public interface IRepository + where TModel : class + where TVisitor : ISpecificationVisitor + { + void Create(TModel model); + void Update(TModel model); + IEnumerable Get(); + IEnumerable Get(ISpecification specification); + TModel Find(ISpecification specification); + } +} diff --git a/src/CSInn.Domain.Repositories/Repositories/IRepositoryAsync.cs b/src/CSInn.Domain.Repositories/Repositories/IRepositoryAsync.cs new file mode 100644 index 0000000..97120d4 --- /dev/null +++ b/src/CSInn.Domain.Repositories/Repositories/IRepositoryAsync.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using CSInn.Domain.Repositories.Specifications.Base; + +namespace CSInn.Domain.Repositories.Repositories +{ + public interface IRepositoryAsync + where TModel : class + where TVisitor : ISpecificationVisitor + { + Task CreateAsync(TModel model, CancellationToken token = default); + Task UpdateAsync(TModel model); + Task DeleteAsync(TModel key); + Task> GetAsync(CancellationToken token = default); + Task> GetAsync(ISpecification specification, CancellationToken token = default); + Task FindAsync(ISpecification specification, CancellationToken token = default); + } +} \ No newline at end of file diff --git a/src/CSInn.Domain.Repositories/Specifications/Base/AndSpecification.cs b/src/CSInn.Domain.Repositories/Specifications/Base/AndSpecification.cs new file mode 100644 index 0000000..8b40e05 --- /dev/null +++ b/src/CSInn.Domain.Repositories/Specifications/Base/AndSpecification.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CSInn.Domain.Repositories.Specifications.Base +{ + public class AndSpecification : ISpecification + where TVisitor : ISpecificationVisitor + { + public ISpecification Left { get; } + public ISpecification Right { get; } + + public AndSpecification(ISpecification left, ISpecification right) + { + Left = left; + Right = right; + } + + public void Accept(TVisitor visitor) => visitor.Visit(this); + public bool IsSatisfiedBy(T obj) => Left.IsSatisfiedBy(obj) && Right.IsSatisfiedBy(obj); + } +} diff --git a/src/CSInn.Domain.Repositories/Specifications/Base/ISpecification.cs b/src/CSInn.Domain.Repositories/Specifications/Base/ISpecification.cs new file mode 100644 index 0000000..0360ec1 --- /dev/null +++ b/src/CSInn.Domain.Repositories/Specifications/Base/ISpecification.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CSInn.Domain.Repositories.Specifications.Base +{ + public interface ISpecification where TVisitor : ISpecificationVisitor + { + /// + /// Does the item meet specification? + /// + bool IsSatisfiedBy(T item); + void Accept(TVisitor visitor); + } +} diff --git a/src/CSInn.Domain.Repositories/Specifications/Base/ISpecificationVisitor.cs b/src/CSInn.Domain.Repositories/Specifications/Base/ISpecificationVisitor.cs new file mode 100644 index 0000000..3193e3c --- /dev/null +++ b/src/CSInn.Domain.Repositories/Specifications/Base/ISpecificationVisitor.cs @@ -0,0 +1,9 @@ +namespace CSInn.Domain.Repositories.Specifications.Base +{ + public interface ISpecificationVisitor where TVisitor : ISpecificationVisitor + { + void Visit(AndSpecification spec); + void Visit(OrSpecification spec); + void Visit(NotSpecification spec); + } +} \ No newline at end of file diff --git a/src/CSInn.Domain.Repositories/Specifications/Base/NotSpecification.cs b/src/CSInn.Domain.Repositories/Specifications/Base/NotSpecification.cs new file mode 100644 index 0000000..3029fbe --- /dev/null +++ b/src/CSInn.Domain.Repositories/Specifications/Base/NotSpecification.cs @@ -0,0 +1,16 @@ +namespace CSInn.Domain.Repositories.Specifications.Base +{ + public class NotSpecification : ISpecification + where TVisitor : ISpecificationVisitor + { + public ISpecification Specification { get; } + + public NotSpecification(ISpecification specification) + { + Specification = specification; + } + + public void Accept(TVisitor visitor) => visitor.Visit(this); + public bool IsSatisfiedBy(T item) => !Specification.IsSatisfiedBy(item); + } +} \ No newline at end of file diff --git a/src/CSInn.Domain.Repositories/Specifications/Base/OrSpecification.cs b/src/CSInn.Domain.Repositories/Specifications/Base/OrSpecification.cs new file mode 100644 index 0000000..cf626fe --- /dev/null +++ b/src/CSInn.Domain.Repositories/Specifications/Base/OrSpecification.cs @@ -0,0 +1,17 @@ +namespace CSInn.Domain.Repositories.Specifications.Base +{ + public class OrSpecification : ISpecification + where TVisitor : ISpecificationVisitor + { + public ISpecification Left { get;} + public ISpecification Right { get;} + public OrSpecification(ISpecification left, ISpecification right) + { + Left = left; + Right = right; + } + + public void Accept(TVisitor visitor) => visitor.Visit(this); + public bool IsSatisfiedBy(T item) => Left.IsSatisfiedBy(item) || Right.IsSatisfiedBy(item); + } +} \ No newline at end of file diff --git a/src/CSInn.Domain.Repositories/Specifications/Lesson/AuthorLike.cs b/src/CSInn.Domain.Repositories/Specifications/Lesson/AuthorLike.cs new file mode 100644 index 0000000..a6694c1 --- /dev/null +++ b/src/CSInn.Domain.Repositories/Specifications/Lesson/AuthorLike.cs @@ -0,0 +1,25 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using CSInn.Domain.Repositories.Specifications.Base; +using CSInn.Models; + +namespace CSInn.Domain.Repositories.Specifications.Lesson +{ + public class AuthorLike : ISpecification + { + public string Author { get; } + + public AuthorLike(string author) + { + Author = author; + } + + public void Accept(ILessonSpecificationVisitor visitor) + { + visitor.Visit(this); + } + + public bool IsSatisfiedBy(CSInn.Models.Lesson lesson) => lesson.Authors.Any(a => a.Contains(Author)); + } +} diff --git a/src/CSInn.Domain.Repositories/Specifications/Lesson/ILessonSpecificationVisitor.cs b/src/CSInn.Domain.Repositories/Specifications/Lesson/ILessonSpecificationVisitor.cs new file mode 100644 index 0000000..36aadd7 --- /dev/null +++ b/src/CSInn.Domain.Repositories/Specifications/Lesson/ILessonSpecificationVisitor.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; +using CSInn.Domain.Repositories.Specifications.Base; + +namespace CSInn.Domain.Repositories.Specifications.Lesson +{ + public interface ILessonSpecificationVisitor: ISpecificationVisitor + { + void Visit(TitleLike spec); + void Visit(TagMatches spec); + void Visit(AuthorLike authorLike); + } +} diff --git a/src/CSInn.Domain.Repositories/Specifications/Lesson/TagMatches.cs b/src/CSInn.Domain.Repositories/Specifications/Lesson/TagMatches.cs new file mode 100644 index 0000000..5eee667 --- /dev/null +++ b/src/CSInn.Domain.Repositories/Specifications/Lesson/TagMatches.cs @@ -0,0 +1,21 @@ +using CSInn.Domain.Repositories.Specifications.Base; + +namespace CSInn.Domain.Repositories.Specifications.Lesson +{ + public class TagMatches : ISpecification + { + public string Tag { get; } + + public TagMatches(string tag) + { + Tag = tag; + } + + public void Accept(ILessonSpecificationVisitor visitor) + { + visitor.Visit(this); + } + + public bool IsSatisfiedBy(CSInn.Models.Lesson lesson) => lesson.Tags.Contains(Tag); + } +} \ No newline at end of file diff --git a/src/CSInn.Domain.Repositories/Specifications/Lesson/TitleLike.cs b/src/CSInn.Domain.Repositories/Specifications/Lesson/TitleLike.cs new file mode 100644 index 0000000..9075efb --- /dev/null +++ b/src/CSInn.Domain.Repositories/Specifications/Lesson/TitleLike.cs @@ -0,0 +1,23 @@ +using System; +using System.Linq.Expressions; +using CSInn.Domain.Repositories.Specifications.Base; + +namespace CSInn.Domain.Repositories.Specifications.Lesson +{ + public class TitleLike : ISpecification + { + public string Title { get; } + + public TitleLike(string title) + { + Title = title; + } + + public bool IsSatisfiedBy(CSInn.Models.Lesson lesson) => lesson.Title.Contains(Title); + + public void Accept(ILessonSpecificationVisitor visitor) + { + visitor.Visit(this); + } + } +} diff --git a/src/CSInn.Domain.Repositories/UnitOfWork/CSInnUnitOfWork.cs b/src/CSInn.Domain.Repositories/UnitOfWork/CSInnUnitOfWork.cs new file mode 100644 index 0000000..076f899 --- /dev/null +++ b/src/CSInn.Domain.Repositories/UnitOfWork/CSInnUnitOfWork.cs @@ -0,0 +1,15 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using CSInn.Domain.Repositories.Repositories; + +namespace CSInn.Domain.Repositories.UnitOfWork +{ + public interface ICSInnUnitOfWork: IDisposable + { + ILessonsRepository Lessons { get; } + + void Save(); + Task SaveAsync(CancellationToken token = default); + } +} diff --git a/src/CSInn.Infrastructure.Repositories/CSInn.Infrastructure.Repositories.csproj b/src/CSInn.Infrastructure.Repositories/CSInn.Infrastructure.Repositories.csproj index 11f86a1..577b046 100644 --- a/src/CSInn.Infrastructure.Repositories/CSInn.Infrastructure.Repositories.csproj +++ b/src/CSInn.Infrastructure.Repositories/CSInn.Infrastructure.Repositories.csproj @@ -1,11 +1,20 @@  - netcoreapp2.2 + netcoreapp3.0 + + + + + + + + + diff --git a/src/CSInn.Infrastructure.Repositories/Entities/LessonEntity.cs b/src/CSInn.Infrastructure.Repositories/Entities/LessonEntity.cs new file mode 100644 index 0000000..17d06a4 --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/Entities/LessonEntity.cs @@ -0,0 +1,17 @@ +namespace CSInn.Infrastructure.Repositories.Entities +{ + public class LessonEntity + { + + public int Id { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string Video { get; set; } + public string Slides { get; set; } + // EF doesn't like a list- fair point, but how do we solve this? + public string Tags { get; set; } + public string Authors { get; set; } + + public string entity_test { get; set; } + } +} diff --git a/src/CSInn.Infrastructure.Repositories/Expressions/ExpressionExtensions.cs b/src/CSInn.Infrastructure.Repositories/Expressions/ExpressionExtensions.cs new file mode 100644 index 0000000..75e19fd --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/Expressions/ExpressionExtensions.cs @@ -0,0 +1,48 @@ +using System; +using System.Linq.Expressions; +using CSInn.Domain.Repositories.ExpressionVisitors; + +namespace CSInn.Infrastructure.Repositories.Expressions +{ + internal static class ExpressionExtensions + { + public static Expression> AndAlso( + this Expression> expr1, + Expression> expr2) + { + var parameter = Expression.Parameter(typeof(T)); + + var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter); + var left = leftVisitor.Visit(expr1.Body); + + var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter); + var right = rightVisitor.Visit(expr2.Body); + + return Expression.Lambda>( + Expression.AndAlso(left, right), parameter); + } + + public static Expression> OrElse( + this Expression> expr1, + Expression> expr2) + { + var parameter = Expression.Parameter(typeof(T)); + + var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter); + var left = leftVisitor.Visit(expr1.Body); + + var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter); + var right = rightVisitor.Visit(expr2.Body); + + return Expression.Lambda>( + Expression.OrElse(left, right), parameter); + } + + public static Expression> Not( + this Expression> epxr) + { + var exprBody = System.Linq.Expressions.Expression.Not(epxr.Body); + return Expression.Lambda>(exprBody, epxr.Parameters); + } + } +} diff --git a/src/CSInn.Infrastructure.Repositories/Expressions/ExpressionVisitor.cs b/src/CSInn.Infrastructure.Repositories/Expressions/ExpressionVisitor.cs new file mode 100644 index 0000000..06d00ac --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/Expressions/ExpressionVisitor.cs @@ -0,0 +1,38 @@ +using System; +using System.Linq.Expressions; +using CSInn.Domain.Repositories.Specifications.Base; + +// TODO: References should be internals visible to this one. +namespace CSInn.Infrastructure.Repositories.Expressions +{ + public abstract class ExpressionVisitor + where TVisitor : ISpecificationVisitor + { + public Expression> Expression { get; protected set; } + + public abstract Expression> ConvertSpecToExpression(ISpecification spec); + + public void Visit(AndSpecification spec) + { + var left = ConvertSpecToExpression(spec.Left); + var right = ConvertSpecToExpression(spec.Right); + + Expression = left.AndAlso(right); + } + + public void Visit(OrSpecification spec) + { + var left = ConvertSpecToExpression(spec.Left); + var right = ConvertSpecToExpression(spec.Right); + + Expression = left.OrElse(right); + } + + public void Visit(NotSpecification spec) + { + var specExpr = ConvertSpecToExpression(spec.Specification); + Expression = specExpr.Not(); + } + } +} + diff --git a/src/CSInn.Infrastructure.Repositories/Expressions/LessonExpressionVisitor.cs b/src/CSInn.Infrastructure.Repositories/Expressions/LessonExpressionVisitor.cs new file mode 100644 index 0000000..5e69ac9 --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/Expressions/LessonExpressionVisitor.cs @@ -0,0 +1,23 @@ +using System; +using System.Linq.Expressions; +using CSInn.Domain.Repositories.Specifications.Base; +using CSInn.Domain.Repositories.Specifications.Lesson; +using CSInn.Infrastructure.Repositories.Entities; +using CSInn.Models; + +namespace CSInn.Infrastructure.Repositories.Expressions +{ + public class LessonEntityExpressionVisitor : ExpressionVisitor, ILessonSpecificationVisitor + { + public override Expression> ConvertSpecToExpression(ISpecification spec) + { + var visitor = new LessonEntityExpressionVisitor(); + spec.Accept(visitor); + return visitor.Expression; + } + + public void Visit(TitleLike spec) => Expression = e => e.Title.Contains(spec.Title); + public void Visit(TagMatches spec) => Expression = e => e.Tags.Contains(spec.Tag); + public void Visit(AuthorLike authorLike) => Expression = e => e.Authors.Contains(authorLike.Author); + } +} diff --git a/src/CSInn.Infrastructure.Repositories/Expressions/ReplaceExpressionVisitor.cs b/src/CSInn.Infrastructure.Repositories/Expressions/ReplaceExpressionVisitor.cs new file mode 100644 index 0000000..2f5d6ac --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/Expressions/ReplaceExpressionVisitor.cs @@ -0,0 +1,22 @@ +using System.Linq.Expressions; + +namespace CSInn.Domain.Repositories.ExpressionVisitors +{ + internal class ReplaceExpressionVisitor + : ExpressionVisitor + { + private readonly Expression _oldValue; + private readonly Expression _newValue; + + public ReplaceExpressionVisitor(Expression oldValue, Expression newValue) + { + _oldValue = oldValue; + _newValue = newValue; + } + + public override Expression Visit(Expression node) + { + return node == _oldValue ? _newValue : base.Visit(node); + } + } +} diff --git a/src/CSInn.Infrastructure.Repositories/Extensions/LessonExtensions.cs b/src/CSInn.Infrastructure.Repositories/Extensions/LessonExtensions.cs new file mode 100644 index 0000000..1ddf9f4 --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/Extensions/LessonExtensions.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; +using CSInn.Infrastructure.Repositories.Entities; +using CSInn.Models; + +namespace CSInn.Infrastructure.Repositories.Extensions +{ + public static class LessonExtensions + { + public static Lesson ToModel(this LessonEntity entity) + { + // call to automapper + var lesson = new Lesson(entity.Title, entity.Description, entity.Tags.Split(","), entity.Authors.Split(",")) + { + Id = entity.Id, + }; + + return lesson; + } + + public static IEnumerable ToModels(this IEnumerable entities) + { + // call to automapper + var experiments = entities.Select(e => e.ToModel()); + + return experiments; + } + + public static LessonEntity ToEntity(this Lesson entity) + { + // call to automapper + var experiment = new LessonEntity() + { + Id = entity.Id, + Title = entity.Title, + Authors = string.Join(',', entity.Authors), + Description = entity.Description, + Slides = entity.Slides, + Tags = string.Join(',',entity.Tags) + }; + + return experiment; + } + } +} diff --git a/src/CSInn.Infrastructure.Repositories/Repositories/LessonsRepository.cs b/src/CSInn.Infrastructure.Repositories/Repositories/LessonsRepository.cs new file mode 100644 index 0000000..afb4b3c --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/Repositories/LessonsRepository.cs @@ -0,0 +1,50 @@ +using CSInn.Domain.Repositories.Repositories; +using CSInn.Domain.Repositories.Specifications.Lesson; +using CSInn.Infrastructure.Repositories.Context; +using CSInn.Infrastructure.Repositories.Entities; +using CSInn.Infrastructure.Repositories.Expressions; +using CSInn.Models; + +namespace CSInn.Infrastructure.Repositories.Repositories +{ + namespace CSInn.Experimental.EF.Repositories + { + public class LessonsRepository : Repository, + ILessonsRepository + { + public LessonsRepository(CSInnDbContext context) : base(context) + { + } + + protected override Lesson ToModel(LessonEntity entity) + { + // call to automapper + var lesson = new Lesson(entity.Title, entity.Description, entity.Tags.Split(","), entity.Authors.Split(",")) + { + Id = entity.Id, + }; + + return lesson; + } + + protected override LessonEntity ToEntity(Lesson model) + { + // call to automapper + var lesson = new LessonEntity() + { + Id = model.Id, + Title = model.Title, + Authors = string.Join(',', model.Authors), + Description = model.Description, + Slides = model.Slides, + Tags = string.Join(',', model.Tags) + }; + + return lesson; + } + + protected override int ExtractKey(Lesson model) => model.Id; + } + } +} + diff --git a/src/CSInn.Infrastructure.Repositories/Repositories/Repository.cs b/src/CSInn.Infrastructure.Repositories/Repositories/Repository.cs new file mode 100644 index 0000000..02bb220 --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/Repositories/Repository.cs @@ -0,0 +1,111 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using CSInn.Domain.Repositories.Repositories; +using CSInn.Domain.Repositories.Specifications.Base; +using CSInn.Infrastructure.Repositories.Context; +using CSInn.Infrastructure.Repositories.Expressions; +using Microsoft.EntityFrameworkCore; + +namespace CSInn.Infrastructure.Repositories.Repositories +{ + public abstract class Repository : IRepository, IRepositoryAsync + where TModel : class + where TEntity : class + where TDomainVisitor : ISpecificationVisitor + where TEFVisitor : ExpressionVisitor, new() + { + private readonly TEFVisitor _visitor; + + private readonly CSInnDbContext _context; + private readonly DbSet _dbSet; + + protected Repository(CSInnDbContext context) + { + _context = context; + _visitor = new TEFVisitor(); + _dbSet = _context.Set(); + } + + protected abstract TModel ToModel(TEntity entity); + protected abstract TEntity ToEntity(TModel model); + protected abstract int ExtractKey(TModel model); + + public IEnumerable Get() => _dbSet.Select(e => ToModel(e)); + public void Create(TModel model) => _dbSet.Add(ToEntity(model)); + + public void Update(TModel model) + { + var entity = _dbSet.Find(ExtractKey(model)); + + if (entity == null) + { + return; + } + + _context.Entry(entity).CurrentValues.SetValues(model); + } + + public void Delete(TModel model) + { + var entity = _dbSet.Find(ExtractKey(model)); + _dbSet.Remove(entity); + } + + public TModel Find(ISpecification specification) + { + var expression = _visitor.ConvertSpecToExpression(specification); + return ToModel(_dbSet.FirstOrDefault(expression)); + } + + public IEnumerable Get(ISpecification specification) + { + var expression = _visitor.ConvertSpecToExpression(specification); + return _dbSet.Where(expression).Select(e => ToModel(e)); + } + + public async Task CreateAsync(TModel model, CancellationToken token = default) => await _dbSet.AddAsync(ToEntity(model), token); + + public async Task UpdateAsync(TModel model) + { + var entity = await _dbSet.FindAsync(ExtractKey(model)); + + if (entity == null) + { + return; + } + + _context.Entry(entity).CurrentValues.SetValues(model); + } + + public async Task DeleteAsync(TModel model) + { + var entity = await _dbSet.FindAsync(ExtractKey(model)); + _dbSet.Remove(entity); + } + + public async Task> GetAsync(CancellationToken token = default) + { + var entities = await _dbSet.ToListAsync(token); + return entities.Select(ToModel); + } + + public async Task> GetAsync(ISpecification specification, CancellationToken token = default) + { + var expression = _visitor.ConvertSpecToExpression(specification); + var entities = await _dbSet.Where(expression).ToListAsync(token); + + return entities.Select(ToModel); + } + + public async Task FindAsync(ISpecification specification, CancellationToken token = default) + { + var expression = _visitor.ConvertSpecToExpression(specification); + var entity = await _dbSet.FirstOrDefaultAsync(expression, token); + + return ToModel(entity); + } + + } +} diff --git a/src/CSInn.Infrastructure.Repositories/UoW/CSInnDbContext.cs b/src/CSInn.Infrastructure.Repositories/UoW/CSInnDbContext.cs new file mode 100644 index 0000000..8daa0fb --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/UoW/CSInnDbContext.cs @@ -0,0 +1,18 @@ +using CSInn.Infrastructure.Repositories.Entities; +using Microsoft.EntityFrameworkCore; + +namespace CSInn.Infrastructure.Repositories.Context +{ + public class CSInnDbContext : DbContext + { + public CSInnDbContext() + { + } + + public CSInnDbContext(DbContextOptions options) + : base(options) + { + } + public virtual DbSet Lessons { get; set; } + } +} diff --git a/src/CSInn.Infrastructure.Repositories/UoW/CSInnUnitOfWork.cs b/src/CSInn.Infrastructure.Repositories/UoW/CSInnUnitOfWork.cs new file mode 100644 index 0000000..a8d2fd2 --- /dev/null +++ b/src/CSInn.Infrastructure.Repositories/UoW/CSInnUnitOfWork.cs @@ -0,0 +1,62 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using CSInn.Domain.Repositories.Repositories; +using CSInn.Domain.Repositories.UnitOfWork; +using CSInn.Infrastructure.Repositories.Context; +using CSInn.Infrastructure.Repositories.Repositories.CSInn.Experimental.EF.Repositories; + +namespace CSInn.Infrastructure.Repositories.UoW +{ + public class CSInnUnitOfWork: ICSInnUnitOfWork + { + private readonly CSInnDbContext _context; + + private ILessonsRepository _lessons; + + public ILessonsRepository Lessons + { + get + { + if (_lessons == null) + { + _lessons = new LessonsRepository(_context); + } + + return _lessons; + } + private set => _lessons = value; + } + + public CSInnUnitOfWork(CSInnDbContext context) + { + _context = context; + } + + public void Save() => _context.SaveChanges(); + + public Task SaveAsync(CancellationToken token = default) =>_context.SaveChangesAsync(); + + #region IDisposable pattern + private bool disposed; + + protected virtual void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + _context.Dispose(); + } + } + disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/src/CSInn.Models/Exceptions/InvalidLessonException.cs b/src/CSInn.Models/Exceptions/InvalidLessonException.cs index a215143..ff41c40 100644 --- a/src/CSInn.Models/Exceptions/InvalidLessonException.cs +++ b/src/CSInn.Models/Exceptions/InvalidLessonException.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; namespace CSInn.Domain.Models.Content.Exceptions { diff --git a/src/CSInn.Models/Lesson.cs b/src/CSInn.Models/Lesson.cs index 6f5bea6..4967c7b 100644 --- a/src/CSInn.Models/Lesson.cs +++ b/src/CSInn.Models/Lesson.cs @@ -1,19 +1,22 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; +using System.Runtime.CompilerServices; using CSInn.Domain.Models.Content.Exceptions; -namespace CSInn.Domain.Models.Content +[assembly: InternalsVisibleTo("CSInn.Infrastructure.Repositories")] +namespace CSInn.Models { public class Lesson { - public string Title { get; } + internal int Id { get; set; } + public string Title { get; set; } public string Description { get; set; } public string Video { get; set; } public string Slides { get; set; } public IList Tags { get; set; } - public IList Authors { get; } + public IList Authors { get; set; } + + public string model_test { get; set; } public Lesson(string title, string description, IEnumerable tags, IEnumerable authors) { @@ -25,7 +28,7 @@ public Lesson(string title, string description, IEnumerable tags, IEnume var isTitleEmpty = string.IsNullOrEmpty(title); var isDescriptionEmpty = string.IsNullOrEmpty(description); var areNoTags = Tags == null || !Tags.Any(); - var areNoAuthors = Authors == null || Authors.Any(); + var areNoAuthors = Authors == null || !Authors.Any(); if (isTitleEmpty || isDescriptionEmpty || areNoTags || areNoAuthors) { @@ -33,6 +36,8 @@ public Lesson(string title, string description, IEnumerable tags, IEnume } } + + public Lesson() { } } } diff --git a/tests/CSInn.Application.Tests/CSInn.Application.Tests.csproj b/tests/CSInn.Application.Tests/CSInn.Application.Tests.csproj index ff862c8..8938f3d 100644 --- a/tests/CSInn.Application.Tests/CSInn.Application.Tests.csproj +++ b/tests/CSInn.Application.Tests/CSInn.Application.Tests.csproj @@ -1,16 +1,19 @@ - + - netcoreapp2.1 + netcoreapp2.2 false - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/tests/CSInn.Discord.Authentication.Tests/CSInn.Discord.Authentication.Tests.csproj b/tests/CSInn.Discord.Authentication.Tests/CSInn.Discord.Authentication.Tests.csproj index 9116020..1bf18b5 100644 --- a/tests/CSInn.Discord.Authentication.Tests/CSInn.Discord.Authentication.Tests.csproj +++ b/tests/CSInn.Discord.Authentication.Tests/CSInn.Discord.Authentication.Tests.csproj @@ -7,10 +7,13 @@ - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/tests/CSInn.Infrastructure.Repositories.Tests/CSInn.Infrastructure.Repositories.Tests.csproj b/tests/CSInn.Infrastructure.Repositories.Tests/CSInn.Infrastructure.Repositories.Tests.csproj index 7bb3c40..a793555 100644 --- a/tests/CSInn.Infrastructure.Repositories.Tests/CSInn.Infrastructure.Repositories.Tests.csproj +++ b/tests/CSInn.Infrastructure.Repositories.Tests/CSInn.Infrastructure.Repositories.Tests.csproj @@ -1,18 +1,23 @@ - + - netcoreapp2.2 + netcoreapp3.0 false - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/tests/CSInn.Infrastructure.Repositories.Tests/Input/LessonsFixture.cs b/tests/CSInn.Infrastructure.Repositories.Tests/Input/LessonsFixture.cs new file mode 100644 index 0000000..5a99c45 --- /dev/null +++ b/tests/CSInn.Infrastructure.Repositories.Tests/Input/LessonsFixture.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Linq; +using CSInn.Models; + +namespace CSInn.Infrastructure.Repositories.Tests.Input +{ + public class LessonsFixture + { + public readonly IQueryable Lessons; + + public LessonsFixture() + { + var lessons = new[] + { + new Lesson("Lesson 1: Class", "What is a class, object", new List() {"OOP"}, + new List() {"Almantas Karpavičius"}), + new Lesson("Lesson 2: SOLID", "SOLID", new List() {"OOP"}, new List() {"Kaisinel"}), + new Lesson("Lesson 3: Delegates", "Delegate vs callback", new List() {"FP"}, + new List() {"Lethern"}) + }; + Lessons = new EnumerableQuery(lessons); + } + } +} diff --git a/tests/CSInn.Infrastructure.Repositories.Tests/Input/UoWFixture.cs b/tests/CSInn.Infrastructure.Repositories.Tests/Input/UoWFixture.cs new file mode 100644 index 0000000..e0a849e --- /dev/null +++ b/tests/CSInn.Infrastructure.Repositories.Tests/Input/UoWFixture.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using CSInn.Infrastructure.Repositories.Context; +using CSInn.Infrastructure.Repositories.UoW; +using CSInn.Models; +using Microsoft.EntityFrameworkCore; + +namespace CSInn.Infrastructure.Repositories.Tests.Input +{ + public class UoWFixture + { + public CSInnUnitOfWork UoW { get; set; } + public UoWFixture() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(databaseName: "database_name") + .Options; + + var context = new CSInnDbContext(options); + UoW = new CSInnUnitOfWork(context); + + UoW.Lessons.Create(new Lesson("Lesson 2: SOLID", "SOLID", new List() { "OOP" }, + new List() { "Kaisinel" })); + + UoW.Lessons.Create( + new Lesson("Lesson 3: Delegates", "Delegate vs callback", new List() { "FP" }, + new List() { "Lethern" })); + + UoW.Save(); + } + } +} diff --git a/tests/CSInn.Infrastructure.Repositories.Tests/LessonSpecificationTests.cs b/tests/CSInn.Infrastructure.Repositories.Tests/LessonSpecificationTests.cs new file mode 100644 index 0000000..be31442 --- /dev/null +++ b/tests/CSInn.Infrastructure.Repositories.Tests/LessonSpecificationTests.cs @@ -0,0 +1,43 @@ +using System.Linq; +using System.Threading.Tasks; +using CSInn.Domain.Repositories.Extensions; +using CSInn.Domain.Repositories.Specifications.Lesson; +using CSInn.Domain.Repositories.UnitOfWork; +using CSInn.Infrastructure.Repositories.Tests.Input; +using CSInn.Models; +using Xunit; + +namespace CSInn.Infrastructure.Repositories.Tests +{ + public class LessonSpecificationTests : IClassFixture + { + private readonly ICSInnUnitOfWork _uow; + + public LessonSpecificationTests(UoWFixture fixture) + { + _uow = fixture.UoW; + } + + [Fact] + public void Composite_Specification_Ok() + { + var filter = new TitleLike("Lesson 2") + .Or(new TitleLike("Lesson 1")).Not(); + + var result = _uow.Lessons.Get(filter); + + Assert.Single(result); + } + + [Fact] + public async Task Composite_Specification_Async_Ok() + { + var filter = new TitleLike("Lesson 2") + .Or(new TitleLike("Lesson 1")).Not(); + + var result = await _uow.Lessons.GetAsync(filter); + + Assert.Single(result); + } + } +}