diff --git a/README.md b/README.md index fcb33d2..d53b0b7 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,21 @@ -

Logo

+

Logo

-# Repositories +
+

Repositories

+
-[![Build Status](https://dev.azure.com/dimesoftware/Utilities/_apis/build/status/dimesoftware.repository?branchName=master)](https://dev.azure.com/dimesoftware/Utilities/_build/latest?definitionId=182&branchName=master) +Implementation of the repository pattern with Entity Framework. -## Introduction - -Implementation of the repository pattern with Entity Framework (Core). - -## Getting Started - -- You must have Visual Studio 2019 Community or higher. -- The dotnet cli is also highly recommended. ## About this project Generic repository pattern with an implementation using Entity Framework. This project revolves around the `IRepository` interface. This interfaces defines the capabilities of a repository which - rather unsurprisingly - are simple CRUD operations. -In addition, this project is also concerned with instantiating the repositories. Rather than accessing the repository's implementation directly, a repository factory (defined by `IRepositoryFactory`) can be used and injected into the application. Support for multi-tenancy is built-in with the `IMultiTenantRepositoryFactory` interface. +In addition, this project is also concerned with instantiating the repositories. Rather than accessing the repository's implementation directly, a repository factory (defined by `IRepositoryFactory`) can be used and injected into the application. The projects in the `Providers` folder provide the implementation of the contracts defined in the Dime.Repositories assembly. -## Build and Test - -- Run dotnet restore -- Run dotnet build -- Run dotnet test - -## Installation +## Getting started Use the package manager NuGet to install Dime.Repositories: @@ -39,55 +27,33 @@ Here's a simple example which demonstrates the usage of the repository. ``` csharp using Dime.Repositories; -... public class CustomerService { - private readonly IRepositoryFactory _repositoryFactory; - - public CustomerService(IRepositoryFactory repositoryFactory) + private readonly IRepository _repository; + public CustomerService(IRepository repository) { - _repositoryFactory = repositoryFactory; + _repository = repository; } public async IEnumerable GetCustomers() - { - using IRepository customerRepository = _repositoryFactory.Create(); - return await customerRepository.FindAllAsync(x => x.IsActive == true); - } + => await _repository_.FindAllAsync(x => x.IsActive == true); } ``` -This is an example of the dependency injection registration in Unity: +## Build and Test -```csharp -public sealed class UnityConfig -{ - public static void RegisterTypes(IUnityContainer container) - { - container.RegisterType>( - new PerRequestOrTransientLifeTimeManager(), - new InjectionConstructor(new MyDbContextEfContextFactory())); - } -} +To run the solution, you will need: -public class MyDbContextEfContextFactory : MultiTenantContextFactory -{ - ... - - protected override SchedulerContext ConstructContext() - { - MyDbContext ctx = new MyDbContext(); - ctx.Configuration.ProxyCreationEnabled = false; - ctx.Configuration.LazyLoadingEnabled = false; - ctx.Configuration.AutoDetectChangesEnabled = false; - ctx.Configuration.UseDatabaseNullSemantics = true; - ctx.Database.CommandTimeout = 60; - return ctx; - } -} -``` +- You must have Visual Studio 2022 Community or higher. +- The dotnet cli is also highly recommended. + +To run the tests, you can use the trustee dotnet cli commands: +- Run dotnet restore +- Run dotnet build +- Run dotnet test + ## Contributing ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square) diff --git a/assets/db.svg b/assets/db.svg deleted file mode 100644 index ad486de..0000000 --- a/assets/db.svg +++ /dev/null @@ -1 +0,0 @@ -server status \ No newline at end of file diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..6b236fa Binary files /dev/null and b/assets/logo.png differ diff --git a/azure-pipelines.yaml b/azure-pipelines.yaml deleted file mode 100644 index 5ec55e0..0000000 --- a/azure-pipelines.yaml +++ /dev/null @@ -1,28 +0,0 @@ -trigger: - - master - -pool: - vmImage: windows-latest - -variables: - BuildConfiguration: 'Release' - -steps: -- task: DotNetCoreCLI@2 - displayName: Restore - inputs: - command: restore - projects: '**/*.csproj' - -- task: DotNetCoreCLI@2 - displayName: Build - inputs: - projects: '**/*.csproj' - arguments: '--configuration $(BuildConfiguration)' - -- task: DotNetCoreCLI@2 - displayName: Test - inputs: - command: test - projects: '**/*.csproj' - arguments: '--configuration $(BuildConfiguration) --collect "Code coverage" -s "src/test.runsettings"' \ No newline at end of file diff --git a/src/Dime.Repositories.sln b/src/Dime.Repositories.sln index 42628a5..0d2e866 100644 --- a/src/Dime.Repositories.sln +++ b/src/Dime.Repositories.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30011.22 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34031.279 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dime.Repositories", "core\Dime.Repositories\Dime.Repositories.csproj", "{72A74CEB-EC06-43A8-85C2-E4CFDA8DFCE9}" EndProject @@ -9,23 +9,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{F753A01F EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dime.Repositories.Sql", "core\Dime.Repositories.Sql\Dime.Repositories.Sql.csproj", "{0FB51C4F-7198-40CF-8442-9A09BF016C42}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dime.Repositories.Sql.EntityFramework.NetCore", "providers\EntityFramework.NetCore\Dime.Repositories.Sql.EntityFramework.NetCore.csproj", "{B501E673-CC10-4BFF-A086-CFF1DF482816}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dime.Repositories.Sql.EntityFramework", "providers\EntityFramework\Dime.Repositories.Sql.EntityFramework.csproj", "{B501E673-CC10-4BFF-A086-CFF1DF482816}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dime.Repositories.Sql.EntityFramework.NetFramework", "providers\EntityFramework.NetFramework\Dime.Repositories.Sql.EntityFramework.NetFramework.csproj", "{4536C116-0C7B-40AD-A2FC-3ED6D0EB1149}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dime.Repositories.Sql.EntityFramework.NetCore.Tests", "test\Dime.Repositories.Sql.EntityFramework.NetCore.Tests\Dime.Repositories.Sql.EntityFramework.NetCore.Tests.csproj", "{4C40805D-D4F3-4D49-B2C4-F464FE4CD833}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dime.Repositories.Sql.EntityFramework.Tests", "test\Dime.Repositories.Sql.EntityFramework.Tests\Dime.Repositories.Sql.EntityFramework.Tests.csproj", "{4C40805D-D4F3-4D49-B2C4-F464FE4CD833}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "providers", "providers", "{BF5B6AB2-33CF-494B-9D49-1A00ACF42729}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Dime.Repositories.Sql.EntityFramework.Shared", "providers\EntityFramework.Shared\Dime.Repositories.Sql.EntityFramework.Shared.shproj", "{E2C7ADE6-23D8-4897-A156-05DCD901E2D0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dime.Repositories.Sql.EntityFramework.NetFramework.Tests", "test\Dime.Repositories.Sql.EntityFramework.NetFramework.Tests\Dime.Repositories.Sql.EntityFramework.NetFramework.Tests.csproj", "{719B5ACC-8EA5-47B7-A8DA-B54A47E5ACA4}" -EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - providers\EntityFramework.Shared\Dime.Repositories.Sql.EntityFramework.Shared.projitems*{b501e673-cc10-4bff-a086-cff1df482816}*SharedItemsImports = 5 - providers\EntityFramework.Shared\Dime.Repositories.Sql.EntityFramework.Shared.projitems*{e2c7ade6-23d8-4897-a156-05dcd901e2d0}*SharedItemsImports = 13 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU @@ -43,28 +33,17 @@ Global {B501E673-CC10-4BFF-A086-CFF1DF482816}.Debug|Any CPU.Build.0 = Debug|Any CPU {B501E673-CC10-4BFF-A086-CFF1DF482816}.Release|Any CPU.ActiveCfg = Release|Any CPU {B501E673-CC10-4BFF-A086-CFF1DF482816}.Release|Any CPU.Build.0 = Release|Any CPU - {4536C116-0C7B-40AD-A2FC-3ED6D0EB1149}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4536C116-0C7B-40AD-A2FC-3ED6D0EB1149}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4536C116-0C7B-40AD-A2FC-3ED6D0EB1149}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4536C116-0C7B-40AD-A2FC-3ED6D0EB1149}.Release|Any CPU.Build.0 = Release|Any CPU {4C40805D-D4F3-4D49-B2C4-F464FE4CD833}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4C40805D-D4F3-4D49-B2C4-F464FE4CD833}.Debug|Any CPU.Build.0 = Debug|Any CPU {4C40805D-D4F3-4D49-B2C4-F464FE4CD833}.Release|Any CPU.ActiveCfg = Release|Any CPU {4C40805D-D4F3-4D49-B2C4-F464FE4CD833}.Release|Any CPU.Build.0 = Release|Any CPU - {719B5ACC-8EA5-47B7-A8DA-B54A47E5ACA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {719B5ACC-8EA5-47B7-A8DA-B54A47E5ACA4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {719B5ACC-8EA5-47B7-A8DA-B54A47E5ACA4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {719B5ACC-8EA5-47B7-A8DA-B54A47E5ACA4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {B501E673-CC10-4BFF-A086-CFF1DF482816} = {BF5B6AB2-33CF-494B-9D49-1A00ACF42729} - {4536C116-0C7B-40AD-A2FC-3ED6D0EB1149} = {BF5B6AB2-33CF-494B-9D49-1A00ACF42729} {4C40805D-D4F3-4D49-B2C4-F464FE4CD833} = {F753A01F-2E0C-4036-9DEF-6047253255D2} - {E2C7ADE6-23D8-4897-A156-05DCD901E2D0} = {BF5B6AB2-33CF-494B-9D49-1A00ACF42729} - {719B5ACC-8EA5-47B7-A8DA-B54A47E5ACA4} = {F753A01F-2E0C-4036-9DEF-6047253255D2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {EFEF8275-DA5B-4493-8BB7-32E760B05267} diff --git a/src/Dime.Repositories.sln.DotSettings.user b/src/Dime.Repositories.sln.DotSettings.user deleted file mode 100644 index 1d8a50f..0000000 --- a/src/Dime.Repositories.sln.DotSettings.user +++ /dev/null @@ -1,20 +0,0 @@ - - C:\Users\hendr\AppData\Local\Temp\JetBrains\ReSharperPlatformVs16\vAny_16eaa788\CoverageData\_Dime.Repositories.288376933\Snapshot\snapshot.utdcvr - <SessionState ContinuousTestingMode="0" IsActive="True" Name="Repository_Count_NoPredicate_ShouldCountAll #4" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <Solution /> -</SessionState> - <SessionState ContinuousTestingMode="0" Name="Repository_Count_NoPredicate_ShouldCountAll #3" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <TestAncestor> - <TestId>MSTest::4C40805D-D4F3-4D49-B2C4-F464FE4CD833::.NETCoreApp,Version=v3.1::Dime.Repositories.Sql.EntityFramework.NetCore.Tests.RepositoryTests.Repository_Count_NoPredicate_ShouldCountAll</TestId> - </TestAncestor> -</SessionState> - <SessionState ContinuousTestingMode="0" Name="Repository_Count_NoPredicate_ShouldCountAll #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <TestAncestor> - <TestId>MSTest::4C40805D-D4F3-4D49-B2C4-F464FE4CD833::.NETCoreApp,Version=v3.1::Dime.Repositories.Sql.EntityFramework.NetCore.Tests.RepositoryTests.Repository_Count_NoPredicate_ShouldCountAll</TestId> - </TestAncestor> -</SessionState> - <SessionState ContinuousTestingMode="0" Name="Repository_Count_NoPredicate_ShouldCountAll" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <TestAncestor> - <TestId>MSTest::4C40805D-D4F3-4D49-B2C4-F464FE4CD833::.NETCoreApp,Version=v3.1::Dime.Repositories.Sql.EntityFramework.NetCore.Tests.RepositoryTests.Repository_Count_NoPredicate_ShouldCountAll</TestId> - </TestAncestor> -</SessionState> \ No newline at end of file diff --git a/src/NuGet.Config b/src/NuGet.Config deleted file mode 100644 index 3f0e003..0000000 --- a/src/NuGet.Config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/core/Dime.Repositories.Sql/Dime.Repositories.Sql.csproj b/src/core/Dime.Repositories.Sql/Dime.Repositories.Sql.csproj index 3ac1eaf..227acf9 100644 --- a/src/core/Dime.Repositories.Sql/Dime.Repositories.Sql.csproj +++ b/src/core/Dime.Repositories.Sql/Dime.Repositories.Sql.csproj @@ -5,9 +5,9 @@ 2.0.0.0 2.0.0.0 Dime Software - 2.0.0.0-alpha.38 + 2.0.0.0 Dime Software - net461;net7.0 + net8.0 Dime.Repositories.Sql Dime.Repositories.Sql https://cdn.dime-software.com/dime-software/logo-shape.png @@ -19,7 +19,7 @@ Repository contracts with support for SQL databases True True - Copyright © 2022 + Copyright © 2023 https://github.com/dimesoftware/repository https://github.com/dimesoftware/repository @@ -31,17 +31,7 @@ - - - - - - - - - - - + + - diff --git a/src/core/Dime.Repositories.Sql/IStoredProcedureRepository.cs b/src/core/Dime.Repositories.Sql/IStoredProcedureRepository.cs index c13f3ba..50d45a9 100644 --- a/src/core/Dime.Repositories.Sql/IStoredProcedureRepository.cs +++ b/src/core/Dime.Repositories.Sql/IStoredProcedureRepository.cs @@ -1,16 +1,7 @@ using System.Collections.Generic; using System.Data.Common; - -#if NET461 - -using System.Data.SqlClient; - -#else - using Microsoft.Data.SqlClient; -#endif - namespace Dime.Repositories { public interface IStoredProcedureRepository diff --git a/src/core/Dime.Repositories/Dime.Repositories.csproj b/src/core/Dime.Repositories/Dime.Repositories.csproj index fe07a13..00a0a6a 100644 --- a/src/core/Dime.Repositories/Dime.Repositories.csproj +++ b/src/core/Dime.Repositories/Dime.Repositories.csproj @@ -4,8 +4,8 @@ 2.0.0.0 2.0.0.0 Dime Software - 2.0.0.0-alpha.48 - net461;net7.0 + 2.0.0.0 + net8.0 Dime.Repositories Dime.Repositories https://cdn.dime-software.com/dime-software/logo-shape.png @@ -17,7 +17,7 @@ true True True - Copyright © 2022 + Copyright © 2023 https://github.com/dimesoftware/repository https://github.com/dimesoftware/repository git @@ -25,9 +25,4 @@ MIT - - - - - diff --git a/src/core/Dime.Repositories/Models/Order.cs b/src/core/Dime.Repositories/Models/Order.cs index 4ac5650..686fc56 100644 --- a/src/core/Dime.Repositories/Models/Order.cs +++ b/src/core/Dime.Repositories/Models/Order.cs @@ -1,9 +1,5 @@ namespace Dime.Repositories { - /// - /// - /// - /// public class Order : IOrder { public Order(string property, bool isAscending) @@ -12,14 +8,8 @@ public Order(string property, bool isAscending) IsAscending = isAscending; } - /// - /// Gets or sets the sorting property - /// public string Property { get; set; } - /// - /// Gets or sets the sorting direction - /// public bool IsAscending { get; set; } public void Deconstruct(out string property, out bool isAscending) diff --git a/src/core/Dime.Repositories/Models/Page.cs b/src/core/Dime.Repositories/Models/Page.cs index b47c761..d8c75d4 100644 --- a/src/core/Dime.Repositories/Models/Page.cs +++ b/src/core/Dime.Repositories/Models/Page.cs @@ -4,84 +4,43 @@ namespace Dime.Repositories { - /// - /// - /// - /// [KnownType(typeof(Page<>))] public class Page : IPage { - /// - /// Default constructor - /// public Page() { } - /// - /// - /// - /// public Page(IEnumerable data) { Data = data; Summary = new List(); } - /// - /// - /// - /// - /// public Page(IEnumerable data, int total) : this(data) { Total = total; } - /// - /// - /// - /// - /// - /// public Page(IEnumerable data, int total, string message) : this(data, total) { Message = message; } - /// - /// - /// - /// - /// - /// - /// public Page(IEnumerable data, int total, string message, IEnumerable summary) : this(data, total, message) { Summary = summary != null ? summary.ToList() : new List(); } - /// - /// - /// public IEnumerable Data { get; set; } - /// - /// - /// public int Total { get; set; } - /// - /// - /// public string Message { get; set; } - /// - /// - /// public List Summary { get; } } } \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Configuration/RepositoryConfiguration.cs b/src/providers/EntityFramework.NetFramework/Configuration/RepositoryConfiguration.cs deleted file mode 100644 index d58c617..0000000 --- a/src/providers/EntityFramework.NetFramework/Configuration/RepositoryConfiguration.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Dime.Repositories -{ - /// - /// Represents a repository configuration object - /// - public class RepositoryConfiguration - { - /// - /// Gets or sets the identifier of the tenant - /// - public string Tenant { get; set; } - - /// - /// Gets or sets the database connection - /// - public string Connection { get; set; } - - /// - /// Gets or sets the flag to indicate whether to leverage the UOW pattern and save in batch - /// - public bool SaveInBatch { get; set; } - - /// - /// Gets or sets the database save strategy - /// - public ConcurrencyStrategy SaveStrategy { get; set; } - - /// - /// Gets or sets the flag to indicate whether to leverage the caching mechanism - /// - public bool Cached { get; set; } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/DbContext Factory/CachedNamedDbContextFactory.cs b/src/providers/EntityFramework.NetFramework/DbContext Factory/CachedNamedDbContextFactory.cs deleted file mode 100644 index 1c9ce86..0000000 --- a/src/providers/EntityFramework.NetFramework/DbContext Factory/CachedNamedDbContextFactory.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Data.Common; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Diagnostics.CodeAnalysis; - -namespace Dime.Repositories -{ - /// - /// - /// - /// - [ExcludeFromCodeCoverage] - public abstract class CachedNamedDbContextFactory : INamedDbContextFactory where TContext : DbContext - { - /// - /// Initializes a new instance of the class - /// - protected CachedNamedDbContextFactory() - { - } - - /// - /// Initializes a new instance of the class - /// - /// The connection string - protected CachedNamedDbContextFactory(string connectionString) : this() - { - Connection = connectionString; - } - - /// - /// - /// - /// - /// - protected CachedNamedDbContextFactory(string connectionString, string tenant) : this(connectionString) - { - Tenant = tenant; - } - - protected static ConcurrentDictionary, DbCompiledModel> ModelCache = new(); - protected static ConcurrentDictionary, DbCompiledModel> NamedModelCache = new(); - - protected string Connection { get; } - protected string Tenant { get; } - - /// - /// Creates the instance of with the default settings - /// - /// - public virtual TContext Create() - => !string.IsNullOrEmpty(Tenant) && !string.IsNullOrEmpty(Connection) ? - Create(Tenant, Connection) : - Create("dbo", Connection); - - /// - /// Creates the specified connection. - /// - /// The connection. - /// - public virtual TContext Create(string nameOrConnectionString) => Create("dbo", nameOrConnectionString); - - /// - /// Creates the specified tenant. - /// - /// The tenant. - /// The connection. - /// - /// - public virtual TContext Create(string tenant, string connection, string context) - { - if (string.IsNullOrEmpty(context)) - return Create(tenant, connection); - - SqlConnectionFactory connectionFactory = new(); - DbConnection dbConnection = connectionFactory.CreateConnection(connection); - Database.SetInitializer(null); - - DbCompiledModel compiledModel = NamedModelCache.GetOrAdd( - Tuple.Create(tenant, dbConnection.ConnectionString, context), - _ => GetContextModel(dbConnection, tenant)); - - return ConstructContext(dbConnection, compiledModel, false); - } - - /// - /// Creates the specified tenant. - /// - /// The tenant. - /// The connection. - /// - public virtual TContext Create(string tenant, string nameOrConnectionString) - { - SqlConnectionFactory connectionFactory = new(); - DbConnection dbConnection = connectionFactory.CreateConnection(nameOrConnectionString); - Database.SetInitializer(null); - - DbCompiledModel compiledModel = ModelCache.GetOrAdd( - Tuple.Create(tenant, dbConnection.ConnectionString), - _ => GetContextModel(dbConnection, tenant)); - - return ConstructContext(dbConnection, compiledModel, false); - } - - /// - /// Constructs the context. - /// - /// - protected abstract TContext ConstructContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection); - - /// - /// Gets the scheduler context model. - /// - /// The database connection. - /// - /// - protected abstract DbCompiledModel GetContextModel(DbConnection dbConnection, string schema); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/DbContext Factory/INamedDbContextFactory.cs b/src/providers/EntityFramework.NetFramework/DbContext Factory/INamedDbContextFactory.cs deleted file mode 100644 index f20fde3..0000000 --- a/src/providers/EntityFramework.NetFramework/DbContext Factory/INamedDbContextFactory.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Data.Entity; -using System.Data.Entity.Infrastructure; - -namespace Dime.Repositories -{ - /// - /// Entity Framework context factory - /// - /// - public interface INamedDbContextFactory : IDbContextFactory where TContext : DbContext - { - /// - /// Creates the context by name - /// - /// The name - /// The instantiated context - TContext Create(string nameOrConnectionString); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Dime.Repositories.Sql.EntityFramework.NetFramework.csproj b/src/providers/EntityFramework.NetFramework/Dime.Repositories.Sql.EntityFramework.NetFramework.csproj deleted file mode 100644 index 08a0c24..0000000 --- a/src/providers/EntityFramework.NetFramework/Dime.Repositories.Sql.EntityFramework.NetFramework.csproj +++ /dev/null @@ -1,42 +0,0 @@ - - - Dime.Repositories.Sql.EntityFramework.NetFramework - Dime.Repositories.Sql.EntityFramework.NetFramework - net7.0;net461 - Dime.Repositories.Sql.EntityFramework.NetFramework - Dime Software - Dime.Repositories.Sql.EntityFramework.NetFramework - en - Implementation of the repository pattern with Entity Framework - Copyright © 2021 - 2.0.0.0-alpha.45 - 2.0.0.0 - 2.0.0.0 - latest - Dime Software - https://cdn.dime-software.com/dime-software/logo-shape.png - https://github.com/dimesoftware/repository - https://github.com/dimesoftware/repository - Dime.Scheduler - true - MIT - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Exceptions/ConcurrencyException.cs b/src/providers/EntityFramework.NetFramework/Exceptions/ConcurrencyException.cs deleted file mode 100644 index 902a14b..0000000 --- a/src/providers/EntityFramework.NetFramework/Exceptions/ConcurrencyException.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.Serialization; - -namespace Dime.Repositories -{ - [Serializable] - [Obsolete("Use shared project")] - [ExcludeFromCodeCoverage] - public class ConcurrencyException : Exception - { - public ConcurrencyException() - { - } - - public ConcurrencyException(string message) : base(message) - { - } - - public ConcurrencyException(string message, Exception innerException) : base(message, innerException) - { - } - - protected ConcurrencyException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Exceptions/ConstraintViolationException.cs b/src/providers/EntityFramework.NetFramework/Exceptions/ConstraintViolationException.cs deleted file mode 100644 index 0a7ed95..0000000 --- a/src/providers/EntityFramework.NetFramework/Exceptions/ConstraintViolationException.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.Serialization; - -namespace Dime.Repositories -{ - /// - /// Exception to indicate an error with constraints such as PK and FK - /// - [Serializable] - [Obsolete("Use shared project")] - [ExcludeFromCodeCoverage] - public class ConstraintViolationException : Exception - { - /// - /// Default constructor - /// - public ConstraintViolationException() - { - } - - /// - /// Constructor accepting the message - /// - /// The exception message - public ConstraintViolationException(string message) : base(message) - { - } - - /// - /// - /// - /// The exception message - /// The exception that was caught - public ConstraintViolationException(string message, Exception innerException) : base(message, innerException) - { - } - - /// - /// - /// - /// SerializationInfo for the exception - /// The Streaming Context - protected ConstraintViolationException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Exceptions/DatabaseAccessException.cs b/src/providers/EntityFramework.NetFramework/Exceptions/DatabaseAccessException.cs deleted file mode 100644 index fca3e69..0000000 --- a/src/providers/EntityFramework.NetFramework/Exceptions/DatabaseAccessException.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.Serialization; - -namespace Dime.Repositories -{ - /// - /// Exception to indicate a general error with the database - /// - [Serializable] - [Obsolete("Use shared project")] - [ExcludeFromCodeCoverage] - public class DatabaseAccessException : Exception - { - /// - /// Initializes a new instance of the System.Exception class. - /// - public DatabaseAccessException() - { - } - - /// - /// Initializes a new instance of the System.Exception class with a specified error message - /// - /// The error message that explains the reason for the exception. - public DatabaseAccessException(string message) - : base(message) - { - } - - /// - /// Initializes a new instance of the System.Exception class with a specified error - /// message and a reference to the inner exception that is the cause of this exception. - /// - /// The error message that explains the reason for the exception. - /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - public DatabaseAccessException(string message, Exception innerException) - : base(message, innerException) - { - } - - /// - /// Initializes a new instance of the System.Exception class with a specified error - /// message and a reference to the inner exception that is the cause of this exception. - /// - /// SerializationInfo for the exception - /// The Streaming Context - protected DatabaseAccessException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Model Builder/DbContextModelBuilder.cs b/src/providers/EntityFramework.NetFramework/Model Builder/DbContextModelBuilder.cs deleted file mode 100644 index d5dbc82..0000000 --- a/src/providers/EntityFramework.NetFramework/Model Builder/DbContextModelBuilder.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Data.Entity; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection; - -namespace Dime.Repositories -{ - /// - /// - /// - [ExcludeFromCodeCoverage] - public static class DbContextModelBuilder - { - /// - /// - /// - /// - /// - public static void BuildModel(this DbModelBuilder modelBuilder, string schema) where T : DbContext - { - Type foundType = Assembly.GetCallingAssembly() - .GetTypes() - .FirstOrDefault(x => typeof(IModelBuilder).IsAssignableFrom(x) && !x.IsAbstract && !x.IsInterface); - - if (foundType == null) - throw new ArgumentException("No model builder found for context in assembly {0}", Assembly.GetCallingAssembly().FullName); - - object o = Activator.CreateInstance(foundType); - IModelBuilder concreteModelBuilder = (IModelBuilder)o; - concreteModelBuilder.BuildContext(modelBuilder, schema); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Model Builder/IModelBuilder.cs b/src/providers/EntityFramework.NetFramework/Model Builder/IModelBuilder.cs deleted file mode 100644 index 51a7685..0000000 --- a/src/providers/EntityFramework.NetFramework/Model Builder/IModelBuilder.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Data.Entity; - -namespace Dime.Repositories -{ - /// - /// Represents a model builder for - /// - /// The db context type - public interface IModelBuilder where T : DbContext - { - /// - /// Builds the default context - /// - /// The code first model builder - void BuildContext(DbModelBuilder builder); - - /// - /// Builds the context for a schema other than the default dbo schema - /// - /// The code first model builder - /// The schema name - void BuildContext(DbModelBuilder builder, string schema); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Async/CreateRepositoryAsync.cs b/src/providers/EntityFramework.NetFramework/Repository/Async/CreateRepositoryAsync.cs deleted file mode 100644 index 2a46f51..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Async/CreateRepositoryAsync.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public virtual async Task CreateAsync(TEntity entity) - { - using TContext ctx = Context; - ctx.Entry(entity).State = EntityState.Added; - TEntity createdItem = ctx.Set().Add(entity); - await SaveChangesAsync(ctx); - - return createdItem; - } - - public virtual async Task CreateAsync(TEntity entity, Expression> condition) - { - using TContext ctx = Context; - ctx.Entry(entity).State = EntityState.Added; - TEntity createdItem = ctx.Set().AddIfNotExists(entity, condition); - await SaveChangesAsync(ctx); - - return createdItem; - } - - public virtual async Task CreateAsync(TEntity entity, Func beforeSaveAction) - { - using TContext ctx = Context; - - await beforeSaveAction(entity, ctx); - - ctx.Entry(entity).State = EntityState.Added; - TEntity createdItem = ctx.Set().Add(entity); - await SaveChangesAsync(ctx); - - return createdItem; - } - - public virtual async Task CreateAsync(TEntity entity, bool commit) - { - using TContext ctx = Context; - ctx.Entry(entity).State = EntityState.Added; - TEntity createdItem = ctx.Set().Add(entity); - - if (commit) - await SaveChangesAsync(ctx); - - return createdItem; - } - - public virtual async Task> CreateAsync(IQueryable entities) - { - if (!entities.Any()) - return entities; - - List newEntities = new(); - - using TContext ctx = Context; - foreach (TEntity entity in entities.ToList()) - { - ctx.Entry(entity).State = EntityState.Added; - TEntity newEntity = ctx.Set().Add(entity); - newEntities.Add(newEntity); - } - - await SaveChangesAsync(ctx); - - return newEntities.AsQueryable(); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Async/DeleteRepositoryAsync.cs b/src/providers/EntityFramework.NetFramework/Repository/Async/DeleteRepositoryAsync.cs deleted file mode 100644 index 5d45e6d..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Async/DeleteRepositoryAsync.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public virtual async Task DeleteAsync(object? id) - { - using TContext ctx = Context; - TEntity item = await ctx.Set().FindAsync(id); - if (item != default(TEntity)) - { - ctx.Set().Remove(item); - await SaveChangesAsync(ctx); - } - } - - public virtual async Task DeleteAsync(IEnumerable ids) - { - using TContext ctx = Context; - foreach (object id in ids.Distinct().ToList()) - { - TEntity item = await ctx.Set().FindAsync(id); - if (item == default(TEntity)) - continue; - - ctx.Set().Remove(item); - } - - await SaveChangesAsync(ctx); - } - - public virtual async Task DeleteAsync(object? id, bool commit) - { - using TContext ctx = Context; - TEntity item = await ctx.Set().FindAsync(id); - if (item != default(TEntity)) - { - ctx.Set().Remove(item); - if (commit) - await SaveChangesAsync(ctx); - } - } - - public virtual async Task DeleteAsync(TEntity entity) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - ctx.Set().Remove(entity); - await SaveChangesAsync(ctx); - } - - public async Task DeleteAsync(IEnumerable entities) - { - if (!entities.Any()) - return; - - using TContext ctx = Context; - foreach (TEntity entity in entities) - { - ctx.Set().Attach(entity); - ctx.Set().Remove(entity); - } - - await SaveChangesAsync(ctx); - } - - public virtual async Task DeleteAsync(TEntity entity, bool commit) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - ctx.Set().Remove(entity); - - if (commit) - await SaveChangesAsync(ctx); - } - - public virtual async Task DeleteAsync(Expression> where) - { - using TContext ctx = Context; - IEnumerable entities = ctx.Set().With(where).AsNoTracking().ToList(); - if (entities.Any()) - { - foreach (TEntity item in entities) - ctx.Set().Attach(item); - - ctx.Set().RemoveRange(entities); - await SaveChangesAsync(ctx); - } - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Async/PagedRepositoryAsync.cs b/src/providers/EntityFramework.NetFramework/Repository/Async/PagedRepositoryAsync.cs deleted file mode 100644 index 257634c..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Async/PagedRepositoryAsync.cs +++ /dev/null @@ -1,270 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; -using LinqKit; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public virtual Task> FindAllPagedAsync( - Expression> where = null, - Expression> select = null, - Expression> orderBy = null, - bool? ascending = null, - int? page = null, - int? pageSize = null, - params string[] includes) - where TResult : class - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select); - - IQueryable fullGraphQuery = Include(query, includes); - Page p = new( - fullGraphQuery.ToList(), - ctx.Set().AsNoTracking().AsExpandable().Count(where)); - - return Task.FromResult((IPage)p); - } - - public Task> FindAllPagedAsync( - Expression> where = null, - Func groupBy = null, - Expression, IEnumerable>> select = null, - Expression> orderBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) where TResult : class, new() - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithGroup(groupBy) - .WithSelect(select); - - IQueryable fullGraphQuery = Include(query, includes); - - Page p = new( - fullGraphQuery.ToList(), - ctx.Set().AsNoTracking().AsExpandable().Count(where)); - - return Task.FromResult((IPage)p); - } - - public async Task> FindAllPagedAsync( - Expression> where = null, - Expression> select = null, - IEnumerable> orderBy = null, - Expression> groupBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) where TResult : class - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select); - - return await Task.FromResult( - new Page(query.ToList(), - ctx.Count(where))); - } - - public async Task> FindAllPagedAsync( - Expression> where = null, - Expression> count = null, - Expression> select = null, - IEnumerable> orderBy = null, - Expression> groupBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) where TResult : class - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .With(where) - .WithOrder(orderBy) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select); - - return await Task.FromResult(new Page(query.ToList(), ctx.Count(count))); - } - - public async Task> FindAllPagedAsync( - Expression> where = null, - Expression> orderBy = null, - bool? ascending = null, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .AsQueryable(); - - return await Task.FromResult( - new Page(query.ToList(), - ctx.Count(where))); - } - - public async Task> FindAllPagedAsync( - Expression> where = null, - Expression> orderBy = null, - Expression> groupBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize); - - return await Task.FromResult( - new Page( - query.ToList(), - ctx.Count(where))); - } - - public async Task> FindAllPagedAsync( - Expression> where = null, - Expression> count = null, - IEnumerable> orderBy = null, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .With(where) - .WithOrder(orderBy) - .With(page, pageSize, orderBy) - .With(pageSize); - - return await Task.FromResult(new Page(query.ToList(), ctx.Count(count))); - } - - public async Task> FindAllPagedAsync( - Expression> where = null, - Expression> count = null, - IEnumerable> orderBy = null, - int? page = default, - int? pageSize = default, - bool trackChanges = false, - params string[] includes) - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .With(where) - .WithOrder(orderBy) - .With(page, pageSize, orderBy) - .With(pageSize); - - return await Task.FromResult( - new Page(trackChanges - ? query.ToList() - : query.AsNoTracking().ToList(), - ctx.Count(count)) - ); - } - - public async Task> FindAllPagedAsync( - Expression> where = null, - IEnumerable> orderBy = null, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .With(where) - .WithOrder(orderBy) - .With(page, pageSize, orderBy) - .With(pageSize); - - return await Task.FromResult(new Page(query.ToList(), ctx.Count(where))); - } - - public async Task> FindAllPagedAsync( - Expression> where = null, - IEnumerable>> orderBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .AsQueryable(); - - return await Task.FromResult(new Page(query.ToList(), ctx.Count(where))); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Async/RepositoryAsync.cs b/src/providers/EntityFramework.NetFramework/Repository/Async/RepositoryAsync.cs deleted file mode 100644 index 3df34ee..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Async/RepositoryAsync.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.Validation; -using System.Data.SqlClient; -using System.Linq; -using System.Threading.Tasks; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public virtual async Task SaveChangesAsync() - { - int retryMax = 0; - bool saveFailed = false; - do - { - try - { - return !Configuration.SaveInBatch && 0 < await Context.SaveChangesAsync(); - } - catch (DbEntityValidationException ex) - { - Rethrow(ex); - return false; - } - catch (DbUpdateConcurrencyException dbUpdateConcurrencyEx) - { - if (Configuration.SaveStrategy == ConcurrencyStrategy.ClientFirst) - { - foreach (DbEntityEntry failedEntry in dbUpdateConcurrencyEx.Entries) - { - if (failedEntry.State == EntityState.Deleted) - { - failedEntry.State = EntityState.Detached; - continue; - } - - DbPropertyValues dbValues = failedEntry.GetDatabaseValues(); - if (dbValues == null) - continue; - - failedEntry.OriginalValues.SetValues(dbValues); - return await SaveChangesAsync(); - } - return true; - } - else - { - foreach (DbEntityEntry failedEnttry in dbUpdateConcurrencyEx.Entries) - await failedEnttry.ReloadAsync(); - - return true; - } - } - catch (DbUpdateException dbUpdateEx) - { - if (dbUpdateEx.InnerException?.InnerException == null) - throw; - - if (dbUpdateEx.InnerException.InnerException is not SqlException sqlException) - throw new DatabaseAccessException(dbUpdateEx.Message, dbUpdateEx.InnerException); - - throw sqlException.Number switch - { - 2627 => new ConcurrencyException(sqlException.Message, sqlException), - 547 => new ConstraintViolationException(sqlException.Message, - sqlException) - , - 2601 => new ConstraintViolationException(sqlException.Message, - sqlException) - , - _ => new DatabaseAccessException(sqlException.Message, sqlException) - }; - } - } - while (saveFailed && retryMax <= 3); - } - - public virtual async Task SaveChangesAsync(TContext context) - { - int retryMax; - bool saveFailed; - do - { - try - { - if (!Configuration.SaveInBatch) - { - int result = context.SaveChanges(); - return 0 < result; - } - else - return false; - } - catch (DbEntityValidationException validationEx) - { - Rethrow(validationEx); - return false; - } - catch (DbUpdateConcurrencyException dbUpdateConcurrencyEx) - { - if (Configuration.SaveStrategy == ConcurrencyStrategy.ClientFirst) - { - bool retried = false; - foreach (DbEntityEntry failedEntry in dbUpdateConcurrencyEx.Entries) - { - if (failedEntry.State == EntityState.Deleted) - { - failedEntry.State = EntityState.Detached; - retried = true; - continue; - } - - DbPropertyValues dbValues = failedEntry.GetDatabaseValues(); - if (dbValues == null) - continue; - - retried = true; - failedEntry.OriginalValues.SetValues(dbValues); - return await SaveChangesAsync(context); - } - - if (!retried) - throw; - - return retried; - } - else - { - foreach (DbEntityEntry failedEnttry in dbUpdateConcurrencyEx.Entries) - await failedEnttry.ReloadAsync(); - - return true; - } - } - catch (DbUpdateException dbUpdateEx) - { - if (dbUpdateEx.InnerException?.InnerException == null) - throw; - - if (dbUpdateEx.InnerException.InnerException is not SqlException sqlException) - throw new DatabaseAccessException(dbUpdateEx.Message, dbUpdateEx.InnerException); - - throw sqlException.Number switch - { - 2627 => new ConcurrencyException(sqlException.Message, sqlException), - 547 => new ConstraintViolationException(sqlException.Message, - sqlException) - , - 2601 => new ConstraintViolationException(sqlException.Message, - sqlException) - , - _ => new DatabaseAccessException(sqlException.Message, sqlException) - }; - } - } - while (saveFailed && retryMax <= 3); - } - - private static void Rethrow(DbEntityValidationException ex) - { - IEnumerable errorMessages = ex.EntityValidationErrors - .SelectMany(x => x.ValidationErrors) - .Select(x => x.ErrorMessage); - - string fullErrorMessage = string.Join("; ", errorMessages); - - string exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage); - - throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Async/SqlRepositoryAsync.cs b/src/providers/EntityFramework.NetFramework/Repository/Async/SqlRepositoryAsync.cs deleted file mode 100644 index 96fb5f6..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Async/SqlRepositoryAsync.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -using System.Linq; -using System.Threading.Tasks; - -#if NET461 -using System.Data.SqlClient; -#else - -using Microsoft.Data.SqlClient; - -#endif - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public async Task ExecuteSqlAsync(string sql) - { - using TContext ctx = Context; - await ctx.Database.ExecuteSqlCommandAsync(sql); - } - - public async Task ExecuteStoredProcedureAsync(string name, params DbParameter[] parameters) - { - using TContext ctx = Context; - - string ExecQuery(string x, DbParameter[] y) - { - string parameterString = string.Join(",", y.Select(z => $"{z.ParameterName}={z.Value}")); - return $"EXEC {x} {parameterString}"; - } - - string execQueryString = ExecQuery(name, parameters); - - return await ctx.Database.ExecuteSqlCommandAsync(execQueryString, parameters); - } - - public async Task ExecuteStoredProcedureAsync(string name, string schema = "dbo", params DbParameter[] parameters) - { - string ExecQuery(string x, DbParameter[] y) - { - string parameterString = string.Join(",", y.Select(z => $"{z.ParameterName}={z.Value}")); - return $"EXEC {schema}.{x} {parameterString}"; - } - - string execQueryString = ExecQuery(name, parameters); - - using TContext ctx = Context; - return await ctx.Database.ExecuteSqlCommandAsync(execQueryString, parameters); - } - - public async Task> ExecuteStoredProcedureAsync(string name, string schema = "dbo", params DbParameter[] parameters) - { - using TContext ctx = Context; - using DbConnection connection = ctx.Database.Connection; - connection.Open(); - using DbCommand cmd = connection.CreateCommand(); - cmd.CommandText = name; - cmd.CommandType = CommandType.StoredProcedure; - cmd.Parameters.AddRange(parameters); - - using IDataReader reader = await cmd.ExecuteReaderAsync(); - return reader.GetRecords(); - } - - public async Task ExecuteStoredProcedureAsync(T name, string schema = "dbo", params DbParameter[] parameters) - { - string ExecQuery(string x, DbParameter[] y) - { - string parameterString = string.Join(",", y.Select(z => $"{z.ParameterName}={z.Value}")); - return $"EXEC {schema}.{nameof(x)} {parameterString}"; - } - - string execQueryString = ExecQuery(nameof(name), parameters); - - using TContext ctx = Context; - return await ctx.Database.ExecuteSqlCommandAsync(execQueryString, parameters); - } - - public async Task> ExecuteStoredProcedureAsync(string command, params DbParameter[] parameters) - { - string ExecQuery(string x, DbParameter[] y) - { - string parameterString = string.Join(",", y.Select(z => $"@{z.ParameterName}={z.Value}")); - return $"EXEC {x} {parameterString}"; - } - - return await Task.Run(() => - { - using TContext ctx = Context; - return ctx.Database.SqlQuery(ExecQuery(command, parameters)); - }); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Async/UpdateRepositoryAsync.cs b/src/providers/EntityFramework.NetFramework/Repository/Async/UpdateRepositoryAsync.cs deleted file mode 100644 index bb18ec4..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Async/UpdateRepositoryAsync.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public virtual async Task UpdateAsync(TEntity entity, bool commitChanges = true) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - ctx.Entry(entity).State = EntityState.Modified; - - if (commitChanges) - await SaveChangesAsync(ctx); - - return entity; - } - - public async Task UpdateAsync(IEnumerable entities, bool commitChanges = true) - { - if (!entities.Any()) - return; - - using TContext ctx = Context; - foreach (TEntity entity in entities) - { - ctx.Set().Attach(entity); - ctx.Entry(entity).State = EntityState.Modified; - } - - await SaveChangesAsync(ctx); - } - - public virtual async Task UpdateAsync(TEntity entity, params string[] properties) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - DbEntityEntry entry = ctx.Entry(entity); - - foreach (string property in properties) - { - if (entry.Member(property) is DbComplexPropertyEntry) - entry.ComplexProperty(property).IsModified = true; - else - entry.Property(property).IsModified = true; - } - - ctx.Entry(entity).State = EntityState.Modified; - await SaveChangesAsync(ctx); - return entity; - } - - public virtual async Task UpdateAsync(TEntity entity, params Expression>[] properties) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - DbEntityEntry entry = ctx.Entry(entity); - - foreach (Expression> property in properties) - entry.Property(property).IsModified = true; - - ctx.Entry(entity).State = EntityState.Modified; - - await SaveChangesAsync(ctx); - - return entity; - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/EfRepositoryFactory.cs b/src/providers/EntityFramework.NetFramework/Repository/EfRepositoryFactory.cs deleted file mode 100644 index 0285978..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/EfRepositoryFactory.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Data.Entity; -using System.Diagnostics.CodeAnalysis; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - public class EfRepositoryFactory : IRepositoryFactory, IRepositoryFactory - where TContext : DbContext - { - public EfRepositoryFactory(INamedDbContextFactory contextFactory) - : this(contextFactory, new RepositoryConfiguration()) - { - } - - public EfRepositoryFactory( - INamedDbContextFactory contextFactory, - RepositoryConfiguration repositoryConfiguration) - { - ContextFactory = contextFactory; - RepositoryConfiguration = repositoryConfiguration; - } - - protected INamedDbContextFactory ContextFactory { get; } - public RepositoryConfiguration RepositoryConfiguration { get; } - - public virtual IRepository Create() where TEntity : class, new() - => Create(RepositoryConfiguration); - - public virtual IRepository Create(RepositoryConfiguration opts) where TEntity : class, new() - => new EfRepository( - !string.IsNullOrEmpty(opts.Connection) ? opts : RepositoryConfiguration, - ContextFactory); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Sync/CreateRepository.cs b/src/providers/EntityFramework.NetFramework/Repository/Sync/CreateRepository.cs deleted file mode 100644 index eeb5d6d..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Sync/CreateRepository.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public virtual TEntity Create(TEntity entity) - { - using TContext ctx = Context; - ctx.Entry(entity).State = EntityState.Added; - TEntity createdItem = ctx.Set().Add(entity); - SaveChanges(Context); - - return createdItem; - } - - public virtual TEntity Create(TEntity entity, Expression> condition) - { - using TContext ctx = Context; - ctx.Entry(entity).State = EntityState.Added; - TEntity createdItem = ctx.Set().AddIfNotExists(entity, condition); - SaveChanges(Context); - - return createdItem; - } - - public virtual TEntity Create(TEntity entity, Func beforeSaveAction) - { - beforeSaveAction(entity, Context); - - using TContext ctx = Context; - ctx.Entry(entity).State = EntityState.Added; - TEntity createdItem = ctx.Set().Add(entity); - SaveChanges(Context); - - return createdItem; - } - - public virtual TEntity Create(TEntity entity, bool commit) - { - using TContext ctx = Context; - ctx.Entry(entity).State = EntityState.Added; - TEntity createdItem = ctx.Set().Add(entity); - - if (commit) - SaveChanges(Context); - - return createdItem; - } - - public virtual IQueryable Create(IQueryable entities) - { - if (!entities.Any()) - return entities; - - List newEntities = new(); - List entitiesToCreate = entities.ToList(); - - using TContext ctx = Context; - foreach (TEntity entity in entitiesToCreate) - { - ctx.Entry(entity).State = EntityState.Added; - TEntity newEntity = ctx.Set().Add(entity); - newEntities.Add(newEntity); - } - - SaveChanges(Context); - - return newEntities.AsQueryable(); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Sync/PagedRepository.cs b/src/providers/EntityFramework.NetFramework/Repository/Sync/PagedRepository.cs deleted file mode 100644 index 6b5aeb7..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Sync/PagedRepository.cs +++ /dev/null @@ -1,214 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Linq; -using System.Linq.Expressions; -using LinqKit; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public virtual Page FindAllPaged( - Expression> where = null, - Expression> select = null, - Expression> orderBy = null, - bool? ascending = null, - int? page = null, - int? pageSize = null, - params string[] includes) - where TResult : class - { - using TContext ctx = Context; - IQueryable query = - ctx.Set() - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select); - - IQueryable fullGraphQuery = Include(query, includes); - return new Page(fullGraphQuery.ToList(), ctx.Count(where)); - } - - public Page FindAllPaged( - Expression> where = null, - Func groupBy = null, - Expression, IEnumerable>> select = null, - Expression> orderBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) where TResult : class, new() - { - using TContext ctx = Context; - - IQueryable query = - ctx.Set() - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithGroup(groupBy) - .WithSelect(select); - - IQueryable fullGraphQuery = Include(query, includes); - return new Page(fullGraphQuery.ToList(), ctx.Count(where)); - } - - public Page FindAllPaged( - Expression> where = null, - Expression> select = null, - IEnumerable> orderBy = null, - Expression> groupBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) where TResult : class - { - using TContext ctx = Context; - return ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select) - .ToPage(ctx.Count(where)); - } - - public Page FindAllPaged( - Expression> where = null, - Expression> count = null, - Expression> select = null, - IEnumerable> orderBy = null, - Expression> groupBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) where TResult : class - { - using TContext ctx = Context; - return ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .AsQueryable() - .With(where) - .WithOrder(orderBy) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select) - .ToPage(ctx.Count(count)); - } - - public Page FindAllPaged( - Expression> where = null, - Expression> orderBy = null, - bool? ascending = null, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - return ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .AsQueryable() - .ToPage(ctx.Count(where)); - } - - public Page FindAllPaged( - Expression> where = null, - Expression> orderBy = null, - Expression> groupBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - return ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .ToPage(ctx.Count(where)); - } - - public Page FindAllPaged( - Expression> where = null, - Expression> count = null, - IEnumerable> orderBy = null, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - return ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .With(where) - .WithOrder(orderBy) - .With(page, pageSize, orderBy) - .With(pageSize) - .ToPage(ctx.Count(where)); - } - - public Page FindAllPaged( - Expression> where = null, - IEnumerable> orderBy = null, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - return ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .With(where) - .WithOrder(orderBy) - .With(page, pageSize, orderBy) - .With(pageSize) - .ToPage(ctx.Count(where)); - } - - public Page FindAllPaged( - Expression> where = null, - IEnumerable>> orderBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) - { - using TContext ctx = Context; - return ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .AsQueryable() - .ToPage(ctx.Count(where)); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Sync/Repository.cs b/src/providers/EntityFramework.NetFramework/Repository/Sync/Repository.cs deleted file mode 100644 index 49860ea..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Sync/Repository.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.Validation; -using System.Diagnostics.CodeAnalysis; - -#if NET461 -using System.Data.SqlClient; -#else - -using Microsoft.Data.SqlClient; - -#endif - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - public partial class EfRepository : ISqlRepository - where TEntity : class, new() - where TContext : DbContext - { - public EfRepository(TContext dbContext) - : this(dbContext, new RepositoryConfiguration()) - { - } - - public EfRepository(TContext dbContext, RepositoryConfiguration configuration) - { - Context = dbContext; - Configuration = configuration; - } - - public EfRepository(RepositoryConfiguration configuration, INamedDbContextFactory factory) - { - Configuration = configuration; - Factory = factory; - } - - private TContext _context; - - protected TContext Context - { - get => Factory?.Create(Configuration.Connection); - set => _context = value; - } - - private RepositoryConfiguration Configuration { get; } - - private INamedDbContextFactory Factory { get; } - - public virtual bool SaveChanges(TContext context) - { - int retryMax; - bool saveFailed; - do - { - try - { - if (Configuration.SaveInBatch) - return false; - - int result = context.SaveChanges(); - return 0 < result; - } - catch (DbEntityValidationException validationEx) - { - Rethrow(validationEx); - return false; - } - catch (DbUpdateConcurrencyException dbUpdateConcurrencyEx) - { - if (Configuration.SaveStrategy == ConcurrencyStrategy.ClientFirst) - { - foreach (DbEntityEntry failedEntry in dbUpdateConcurrencyEx.Entries) - { - DbPropertyValues dbValues = failedEntry.GetDatabaseValues(); - if (dbValues == null) - continue; - - failedEntry.OriginalValues.SetValues(dbValues); - return SaveChanges(context); - } - return true; - } - - foreach (DbEntityEntry failedEntry in dbUpdateConcurrencyEx.Entries) - failedEntry.Reload(); - - return true; - } - catch (DbUpdateException dbUpdateEx) - { - if (dbUpdateEx.InnerException?.InnerException == null) - throw; - - if (dbUpdateEx.InnerException.InnerException is not SqlException sqlException) - throw new DatabaseAccessException(dbUpdateEx.Message, dbUpdateEx.InnerException); - - throw sqlException.Number switch - { - 2627 => new ConcurrencyException(sqlException.Message, sqlException), - 547 => new ConstraintViolationException(sqlException.Message, - sqlException) - , - 2601 => new ConstraintViolationException(sqlException.Message, - sqlException) - , - _ => new DatabaseAccessException(sqlException.Message, sqlException) - }; - } - } - while (saveFailed && retryMax <= 3); - } - - public void Dispose() - { - if (Context == null) - return; - - Context.Dispose(); - Context = null; - } - - public static explicit operator TContext(EfRepository repository) - => repository.Context; - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Sync/StoredProcedureRepository.cs b/src/providers/EntityFramework.NetFramework/Repository/Sync/StoredProcedureRepository.cs deleted file mode 100644 index 41c8327..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Sync/StoredProcedureRepository.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Collections.Generic; -using System.Data.Common; -using System.Linq; - -#if NET461 -using System.Data.SqlClient; -#else - -using Microsoft.Data.SqlClient; - -#endif - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public IEnumerable GetStoredProcedureSchema(string name, string schema = "dbo") - { - using TContext ctx = Context; - using SqlConnection connection = new(ctx.Database.Connection.ConnectionString); - connection.Open(); - using SqlCommand cmd = connection.CreateCommand(); - cmd.CommandText = $"{schema}.{name}"; - cmd.CommandType = System.Data.CommandType.StoredProcedure; - - SqlCommandBuilder.DeriveParameters(cmd); - foreach (SqlParameter param in cmd.Parameters) - { - yield return param; - } - } - - public int ExecuteStoredProcedure(string name, params DbParameter[] parameters) - { - using TContext ctx = Context; - string ExecQuery(string x, DbParameter[] y) - { - string parameterString = string.Join(",", parameters.Select(z => $"{z.ParameterName}={z.Value}")); - return $"EXEC {name} {parameterString}"; - } - - string execQueryString = ExecQuery(name, parameters); - return ctx.Database.ExecuteSqlCommand(execQueryString, parameters); - } - - public int ExecuteStoredProcedure(string name, string schema = "dbo", params DbParameter[] parameters) - { - using TContext ctx = Context; - string ExecQuery(string x, DbParameter[] y) - { - string parameterString = string.Join(",", parameters.Select(z => $"{z.ParameterName}={z.Value}")); - return $"EXEC {schema}.{name} {parameterString}"; - } - - string execQueryString = ExecQuery(name, parameters); - return ctx.Database.ExecuteSqlCommand(execQueryString, parameters); - } - - public IEnumerable ExecuteStoredProcedure(string name, string schema = "dbo", params DbParameter[] parameters) - { - using TContext ctx = Context; - using DbConnection connection = ctx.Database.Connection; - connection.Open(); - using DbCommand cmd = connection.CreateCommand(); - cmd.CommandText = $"{schema}.{name}"; - cmd.CommandType = System.Data.CommandType.StoredProcedure; - cmd.Parameters.AddRange(parameters); - - using DbDataReader reader = cmd.ExecuteReader(); - return reader.GetRecords(); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Sync/UpdateRepository.cs b/src/providers/EntityFramework.NetFramework/Repository/Sync/UpdateRepository.cs deleted file mode 100644 index c6378d9..0000000 --- a/src/providers/EntityFramework.NetFramework/Repository/Sync/UpdateRepository.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - public TEntity Update(TEntity entity) => Update(entity, true); - - public virtual TEntity Update(TEntity entity, bool commitChanges = true) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - ctx.Entry(entity).State = EntityState.Modified; - - if (commitChanges) - SaveChanges(Context); - - return entity; - } - - public void Update(IEnumerable entities, bool commitChanges = true) - { - if (!entities.Any()) - return; - - using TContext ctx = Context; - foreach (TEntity entity in entities) - { - ctx.Set().Attach(entity); - ctx.Entry(entity).State = EntityState.Modified; - } - - SaveChanges(Context); - } - - public virtual TEntity Update(TEntity entity, params string[] properties) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - DbEntityEntry entry = ctx.Entry(entity); - - foreach (string property in properties) - { - if (entry.Member(property) is DbComplexPropertyEntry) - entry.ComplexProperty(property).IsModified = true; - else - entry.Property(property).IsModified = true; - } - - ctx.Entry(entity).State = EntityState.Modified; - SaveChanges(Context); - return entity; - } - - public virtual TEntity Update(TEntity entity, params Expression>[] properties) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - DbEntityEntry entry = ctx.Entry(entity); - - foreach (Expression> property in properties) - entry.Property(property).IsModified = true; - - ctx.Entry(entity).State = EntityState.Modified; - - SaveChanges(Context); - - return entity; - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/DataReaderExtensions.cs b/src/providers/EntityFramework.NetFramework/Utilities/DataReaderExtensions.cs deleted file mode 100644 index c752154..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/DataReaderExtensions.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Reflection; - -namespace Dime.Repositories -{ - public static class DataReaderExtensions - { - /// - /// - /// - /// - /// - /// - public static List GetRecords(this IDataReader reader) - { - List result = new(); - while (reader.Read()) - { - T t = (T)typeof(T).GetConstructor(Type.EmptyTypes).Invoke(Array.Empty()); - PropertyInfo[] props = t.GetType().GetProperties(); - object[] indexer = null; - foreach (PropertyInfo p in props) - { - if (reader.HasColumn(p.Name) && reader[p.Name].GetType() != typeof(DBNull)) - p.SetValue(t, reader[p.Name], indexer); - } - - result.Add(t); - } - - return result; - } - - /// - /// - /// - /// - /// - /// - public static bool HasColumn(this IDataRecord dr, string columnName) - { - for (int i = 0; i < dr.FieldCount; i++) - { - if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase)) - return true; - } - - return false; - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/DbContextExtensions.cs b/src/providers/EntityFramework.NetFramework/Utilities/DbContextExtensions.cs deleted file mode 100644 index 9e9e7d3..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/DbContextExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Data.Entity; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Linq.Expressions; -using LinqKit; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - internal static class DbContextExtensions - { - /// - /// - /// - /// - /// - /// - /// - internal static int Count(this DbContext ctx, Expression> query = null) - where TEntity : class - => query == null - ? ctx.Set().AsExpandable().AsNoTracking().Count() - : ctx.Set().AsExpandable().AsNoTracking().Count(query); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/DbSetExtensions.cs b/src/providers/EntityFramework.NetFramework/Utilities/DbSetExtensions.cs deleted file mode 100644 index b3e2ae6..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/DbSetExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Data.Entity; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - internal static class DbSetExtensions - { - /// - /// Conditionally adds the item to the set - /// - /// The entity type - /// The entity's set - /// The record to add - /// The condition - /// The created item if the condition was met; otherwise null - public static T AddIfNotExists(this DbSet dbSet, T entity, Expression> condition = null) where T : class, new() - => !(condition == null || dbSet.Any(condition)) ? dbSet.Add(entity) : null; - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/Extensions/EFExtensions.cs b/src/providers/EntityFramework.NetFramework/Utilities/Extensions/EFExtensions.cs deleted file mode 100644 index 57c33f7..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/Extensions/EFExtensions.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Core.Metadata.Edm; -using System.Data.Entity.Infrastructure; -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - internal static class EFExtensions - { - private static MetadataWorkspace _workspace; - private static ObjectItemCollection _itemCollection; - - private static EntityType GetEntityType(IObjectContextAdapter context) - { - _workspace ??= context.ObjectContext.MetadataWorkspace; - _itemCollection ??= (ObjectItemCollection)_workspace.GetItemCollection(DataSpace.OSpace); - - EntityType entityType = _itemCollection.OfType().FirstOrDefault(e => _itemCollection.GetClrType(e) == typeof(T)); - return entityType; - } - - /// - /// - /// - /// - /// - /// - /// - /// - internal static IQueryable Include(this IQueryable query, DbContext context, params string[] includes) - where TEntity : class - { - // Don't eagerly load navigation properties when the includes parameter has been explicitly set to null - if (includes == null) - return query; - - List includeList = new(); - if (includes.Any()) - return includes - .Where(x => !string.IsNullOrEmpty(x) && !includeList.Contains(x)) - .Aggregate(query, (current, include) => current.Include(include)); - - ReadOnlyMetadataCollection navigationProperties = GetEntityType(context)?.NavigationProperties; - if (navigationProperties == null) - return query; - - foreach (NavigationProperty navigationProperty in - navigationProperties.Where(navigationProperty => !includeList.Contains(navigationProperty.Name))) - { - includeList.Add(navigationProperty.Name); - query = query.Include(navigationProperty.Name); - } - - return query; - } - - /// - /// - /// - /// - /// - /// - /// - /// - /// - internal static IQueryable IncludeView(this IQueryable query, DbContext context, params string[] includes) where TEntity : class - { - if (includes != null && includes.Any()) - return includes - .Where(x => !string.IsNullOrEmpty(x)) - .Aggregate(query, (current, include) => current.Include(include)); - - return GetEntityType(context) - .NavigationProperties - .Aggregate(query, (current, navigationProperty) => current.Include(navigationProperty.Name)); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/LinqOperationExtensions.cs b/src/providers/EntityFramework.NetFramework/Utilities/LinqOperationExtensions.cs deleted file mode 100644 index 0febc47..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/LinqOperationExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - internal static class OrderLinq - { - internal static IOrderedQueryable SortBy(this IEnumerable query, IOrder order) - { - string verb = order.IsAscending ? "OrderBy" : "OrderByDescending"; - LinqOrderHelper helper = new(verb, order.Property); - return helper.GetAsQueryable(query); - } - - /// - /// - /// - /// - /// - /// - /// - internal static IOrderedQueryable ThenBy(this IEnumerable source, IOrder order) - { - string verb = order.IsAscending ? "ThenBy" : "ThenByDescending"; - LinqOrderHelper helper = new(verb, order.Property); - return helper.GetAsQueryable(source); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/LinqOperationHelper.cs b/src/providers/EntityFramework.NetFramework/Utilities/LinqOperationHelper.cs deleted file mode 100644 index cc48f91..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/LinqOperationHelper.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; - -namespace Dime.Repositories -{ - /// - /// - /// - /// - [ExcludeFromCodeCoverage] - internal class LinqOrderHelper - { - #region Constructor - - internal LinqOrderHelper(string methodName, string propertyName) - { - Method = methodName; - ParentParameterExpression = Expression.Parameter(typeof(TSource), "x"); - MemberExpression = SetMember(Parse(propertyName)); - } - - #endregion Constructor - - #region Properties - - private string Method { get; } - private ParameterExpression ParentParameterExpression { get; } - private MemberExpression MemberExpression { get; } - - /// - /// - /// - /// - /// - internal IOrderedQueryable GetAsQueryable(IEnumerable query) - { - LambdaExpression selector = Expression.Lambda(MemberExpression, ParentParameterExpression); - MethodInfo methodInfo = GetMethodInfo(Method, MemberExpression.Type); - - IOrderedQueryable newQuery = (IOrderedQueryable)methodInfo.Invoke(methodInfo, new object[] { query, selector }); - return newQuery; - } - - /// - /// - /// - /// - private MemberExpression SetMember(IOrderedEnumerable> orderedList) - { - MemberExpression memberExpression = default; - for (int i = 0; i < orderedList.Count(); i++) - { - // Get the current record in the loop - string dataIndex = orderedList.ElementAt(i).Value; - - // If this is the first iteration, just set the variable - else append the expa - memberExpression = i == 0 ? - Expression.PropertyOrField(ParentParameterExpression, dataIndex) : - Expression.PropertyOrField(memberExpression, dataIndex); - } - - return memberExpression; - } - - /// - /// - /// - /// - /// - /// - private MethodInfo GetMethodInfo(string methodName, Type type) - { - //Get System.Linq.Queryable.OrderBy() method. - Type enumarableType = typeof(Queryable); - MethodInfo method = enumarableType.GetMethods() - .Where(m => m.Name == methodName && m.IsGenericMethodDefinition) - .Where(m => - { - List parameters = m.GetParameters().ToList(); - //Put more restriction here to ensure selecting the right overload - return parameters.Count == 2;//overload that has 2 parameters - }).Single(); - - //The linq's OrderBy has two generic types, which provided here - MethodInfo genericMethod = method.MakeGenericMethod(typeof(TSource), type); - - return genericMethod; - } - - /// - /// - /// - /// - /// - private IOrderedEnumerable> Parse(string propertyName) - { - int c = 1; - IDictionary properties = new Dictionary(); - propertyName.Split('.').ToList().ForEach(x => { properties.Add(c, x); c++; }); - - IOrderedEnumerable> orderedList = properties.OrderBy(x => x.Key); - return orderedList; - } - - #endregion Properties - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/GroupByQueryFactory.cs b/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/GroupByQueryFactory.cs deleted file mode 100644 index 0b5b073..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/GroupByQueryFactory.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - internal static partial class QueryFactory - { - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// - /// The source. - /// The predicate. - /// - public static IQueryable> WithGroup(this IQueryable source, Expression> predicate) - => source.GroupBy(predicate); - - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// - /// The source. - /// The predicate. - /// - public static IQueryable> WithGroup(this IQueryable source, Func predicate) - => source.GroupBy(predicate).AsQueryable(); - - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// - /// The source. - /// The predicate. - /// - public static IQueryable> WithGroup(this IOrderedEnumerable source, Func predicate) - => source.GroupBy(predicate).AsQueryable(); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/SelectQueryFactory.cs b/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/SelectQueryFactory.cs deleted file mode 100644 index 0810e97..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/SelectQueryFactory.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - internal static partial class QueryFactory - { - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect( - this IQueryable> source, - Expression, IEnumerable>> selector) - => selector == null ? default : source.SelectMany(selector); - - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect( - this IQueryable> source, - Expression, int, TResult>> selector) - => selector == null ? default : source.Select(selector); - - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect(this IOrderedEnumerable source, - Func selector) - where TSource : class - where TResult : class - => selector == null ? default : source.Select(selector).AsQueryable(); - - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect(this IQueryable source, - Expression> selector) - where TSource : class - => selector == null ? default : source.Select(selector).AsQueryable(); - - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect(this IQueryable source, - Func selector) - where TSource : class - where TResult : class - => selector == null ? default : source.Select(selector).AsQueryable(); - - /// - /// - /// - /// - /// - /// - /// - /// - internal static TResult WithFirstSelect(this TSource source, - Expression> selector) - where TSource : class - where TResult : class - => selector == null - ? default - : new List { source }.AsQueryable().Select(selector).FirstOrDefault(); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/SkipQueryFactory.cs b/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/SkipQueryFactory.cs deleted file mode 100644 index 54eba84..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/SkipQueryFactory.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - internal static partial class QueryFactory - { - /// - /// Bypasses a specified number of elements in a sequence and then returns the remaining elements. - /// - /// The type of the elements of source. - /// An System.Linq.IQueryable`1 to return elements from. - /// The number of elements to skip before returning the remaining elements. - /// Size of the page. - /// - /// An System.Linq.IQueryable`1 that contains elements that occur after the specified index in the input sequence. - internal static IQueryable With(this IQueryable source, int? page, int? pageSize, IEnumerable> orderBy) - { - int pageToApply = page.GetValueOrDefault(); - int pageSizeToApply = pageSize.GetValueOrDefault(); - - if (pageToApply == 0 || pageSizeToApply == 0) - return source; - - int itemsToSkip = (pageToApply - 1) * pageSizeToApply; - - return orderBy == null ? - source.OrderBy(x => true).Skip(() => itemsToSkip) : - source.Skip(() => itemsToSkip); - } - - /// - /// Bypasses a specified number of elements in a sequence and then returns the remaining elements. - /// - /// The type of the elements of source. - /// An System.Linq.IQueryable`1 to return elements from. - /// The number of elements to skip before returning the remaining elements. - /// Size of the page. - /// - /// An System.Linq.IQueryable`1 that contains elements that occur after the specified index in the input sequence. - internal static IQueryable With(this IQueryable source, int? page, int? pageSize, Expression> orderBy) - { - int pageToApply = page.GetValueOrDefault(); - int pageSizeToApply = pageSize.GetValueOrDefault(); - - if (pageToApply == 0 || pageSizeToApply == 0) - return source; - - int itemsToSkip = (pageToApply - 1) * pageSizeToApply; - - return orderBy == null ? - source.OrderBy(x => true).Skip(() => itemsToSkip) : - source.Skip(() => itemsToSkip); - } - - /// - /// Bypasses a specified number of elements in a sequence and then returns the remaining elements. - /// - /// The type of the elements of source. - /// An System.Linq.IQueryable`1 to return elements from. - /// The number of elements to skip before returning the remaining elements. - /// Size of the page. - /// - /// An System.Linq.IQueryable`1 that contains elements that occur after the specified index in the input sequence. - internal static IQueryable With(this IQueryable source, int? page, int? pageSize, IEnumerable>> orderBy) - { - int pageToApply = page.GetValueOrDefault(); - int pageSizeToApply = pageSize.GetValueOrDefault(); - - if (pageToApply == 0 || pageSizeToApply == 0) - return source; - - int itemsToSkip = (pageToApply - 1) * pageSizeToApply; - - return orderBy == null ? - source.OrderBy(x => true).Skip(() => itemsToSkip) : - source.Skip(() => itemsToSkip); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/SortingQueryFactory.cs b/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/SortingQueryFactory.cs deleted file mode 100644 index 01ae960..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/SortingQueryFactory.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - internal static partial class QueryFactory - { - /// - /// Wrapper around LINQ ORDER BY - /// - /// The type of the source. - /// The source. - /// The order by expression. - /// - internal static IQueryable WithOrder(this IQueryable source, IEnumerable> orderByExpression) - { - if (orderByExpression != null && orderByExpression.Count() > 1) - { - IEnumerable orderBy = null; - for (int i = 0; i < orderByExpression.Count(); i++) - { - IOrder element = orderByExpression.ElementAt(i); - orderBy = i == 0 ? source.SortBy(element) : orderBy.ThenBy(element); - } - - return orderBy.AsQueryable(); - } - - if (orderByExpression != null && orderByExpression.Count() == 1) - return source.SortBy(orderByExpression.ElementAt(0)).AsQueryable(); - - return source.OrderBy(x => true); - } - - /// - /// Wrapper around LINQ ORDER BY - /// - /// The type of the source. - /// The source. - /// The order by expression. - /// - /// - internal static IQueryable WithOrder(this IQueryable source, IEnumerable>> orderByExpression, bool ascending) - { - if (orderByExpression == null) - return source; - if (orderByExpression.Count() > 1) - { - Func orderBy = orderByExpression.ElementAt(0).Compile(); - Func orderByThen = orderByExpression.ElementAt(1).Compile(); - - return ascending - ? source.OrderBy(orderBy).ThenBy(orderByThen).AsQueryable() - : source.OrderBy(orderBy).ThenByDescending(orderByThen).AsQueryable(); - } - else - { - Func orderBy = orderByExpression.ElementAt(0).Compile(); - - return ascending - ? source.OrderBy(orderBy).AsQueryable() - : source.OrderByDescending(orderBy).AsQueryable(); - } - } - - /// - /// Wrapper around LINQ ORDER BY - /// - /// The type of the source. - /// The source. - /// The order by expression. - /// - /// - internal static IQueryable WithOrder(this IQueryable source, Expression> orderByExpression, bool ascending) - { - if (orderByExpression == null) - return source; - Func compiledExpression = orderByExpression.Compile(); - return ascending - ? source.OrderBy(compiledExpression).AsQueryable() - : source.OrderByDescending(compiledExpression).AsQueryable(); - } - - /// - /// Wrapper around LINQ ORDER BY - /// - /// The type of the source. - /// The source. - /// The order by expression. - /// - /// - internal static IQueryable WithOrder(this IQueryable source, Func orderByExpression, bool ascending) - { - if (orderByExpression != null) - return ascending - ? source.OrderBy(orderByExpression).AsQueryable() - : source.OrderByDescending(orderByExpression).AsQueryable(); - - Func defaultSorting = x => true; - return ascending - ? source.OrderBy(defaultSorting).AsQueryable() - : source.OrderByDescending(defaultSorting).AsQueryable(); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/TakeQueryFactory.cs b/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/TakeQueryFactory.cs deleted file mode 100644 index 591e7d4..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/TakeQueryFactory.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Data.Entity; -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - internal static class TakeQueryFactory - { - internal static IQueryable With(this IQueryable source, int? takeCount) - { - int itemsToTake = takeCount.GetValueOrDefault(); - return itemsToTake == 0 ? source : source.Take(() => itemsToTake); - } - } - - [ExcludeFromCodeCoverage] - internal static class PageFactory - { - internal static Page ToPage(this IQueryable source, int count) - => new Page(source.ToList(), count); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/WhereQueryFactory.cs b/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/WhereQueryFactory.cs deleted file mode 100644 index ee48f92..0000000 --- a/src/providers/EntityFramework.NetFramework/Utilities/Query Factory/WhereQueryFactory.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - internal static partial class QueryFactory - { - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// The source. - /// The predicate. - /// - internal static IQueryable With(this IQueryable source, Expression> predicate) - => predicate == null ? source : source.Where(predicate); - - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// The source. - /// The predicate. - /// - internal static TSource WithFirst(this IQueryable source, Expression> predicate) - => predicate == null ? source.FirstOrDefault() : source.FirstOrDefault(predicate); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Dime.Repositories.Sql.EntityFramework.Shared.projitems b/src/providers/EntityFramework.Shared/Dime.Repositories.Sql.EntityFramework.Shared.projitems deleted file mode 100644 index b23aa39..0000000 --- a/src/providers/EntityFramework.Shared/Dime.Repositories.Sql.EntityFramework.Shared.projitems +++ /dev/null @@ -1,36 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - e2c7ade6-23d8-4897-a156-05dcd901e2d0 - - - Dime.Repositories.Sql.EntityFramework.Shared - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Dime.Repositories.Sql.EntityFramework.Shared.shproj b/src/providers/EntityFramework.Shared/Dime.Repositories.Sql.EntityFramework.Shared.shproj deleted file mode 100644 index c8937cd..0000000 --- a/src/providers/EntityFramework.Shared/Dime.Repositories.Sql.EntityFramework.Shared.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - e2c7ade6-23d8-4897-a156-05dcd901e2d0 - 14.0 - - - - - - - - diff --git a/src/providers/EntityFramework.Shared/Exceptions/ConstraintViolationException.cs b/src/providers/EntityFramework.Shared/Exceptions/ConstraintViolationException.cs deleted file mode 100644 index 0afbe20..0000000 --- a/src/providers/EntityFramework.Shared/Exceptions/ConstraintViolationException.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace Dime.Repositories -{ - /// - /// Exception to indicate an error with constraints such as PK and FK - /// - [Serializable] - public class ConstraintViolationException : Exception - { - /// - /// Default constructor - /// - public ConstraintViolationException() - { - } - - /// - /// Constructor accepting the message - /// - /// The exception message - public ConstraintViolationException(string message) : base(message) - { - } - - /// - /// - /// - /// The exception message - /// The exception that was caught - public ConstraintViolationException(string message, Exception innerException) : base(message, innerException) - { - } - - /// - /// - /// - /// SerializationInfo for the exception - /// The Streaming Context - protected ConstraintViolationException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Exceptions/DatabaseAccessException.cs b/src/providers/EntityFramework.Shared/Exceptions/DatabaseAccessException.cs deleted file mode 100644 index e5691b1..0000000 --- a/src/providers/EntityFramework.Shared/Exceptions/DatabaseAccessException.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace Dime.Repositories -{ - /// - /// Exception to indicate a general error with the database - /// - [Serializable] - public class DatabaseAccessException : Exception - { - /// - /// Initializes a new instance of the System.Exception class. - /// - public DatabaseAccessException() - { - } - - /// - /// Initializes a new instance of the System.Exception class with a specified error message - /// - /// The error message that explains the reason for the exception. - public DatabaseAccessException(string message) - : base(message) - { - } - - /// - /// Initializes a new instance of the System.Exception class with a specified error - /// message and a reference to the inner exception that is the cause of this exception. - /// - /// The error message that explains the reason for the exception. - /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - public DatabaseAccessException(string message, Exception innerException) - : base(message, innerException) - { - } - - /// - /// Initializes a new instance of the System.Exception class with a specified error - /// message and a reference to the inner exception that is the cause of this exception. - /// - /// SerializationInfo for the exception - /// The Streaming Context - protected DatabaseAccessException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Repository/Async/AggregateRepositoryAsync.cs b/src/providers/EntityFramework.Shared/Repository/Async/AggregateRepositoryAsync.cs deleted file mode 100644 index 46f9428..0000000 --- a/src/providers/EntityFramework.Shared/Repository/Async/AggregateRepositoryAsync.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Linq.Expressions; -using System.Threading.Tasks; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - /// - /// Counts the amount of records in the data store for the table that corresponds to the entity type . - /// - /// A number of the amount of records - public Task CountAsync() - { - long count; - using (TContext ctx = Context) - count = ctx.Count(); - - return Task.FromResult(count); - } - - /// - /// Counts the amount of records in the data store for the table that corresponds to the entity type . - /// - /// A number of the amount of records - /// The expression to execute against the data store - public Task CountAsync(Expression> where) - { - long count; - using (TContext ctx = Context) - count = ctx.Count(where); - - return Task.FromResult((long)count); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Repository/Async/GetRepositoryAsync.cs b/src/providers/EntityFramework.Shared/Repository/Async/GetRepositoryAsync.cs deleted file mode 100644 index 65c3a74..0000000 --- a/src/providers/EntityFramework.Shared/Repository/Async/GetRepositoryAsync.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System; -using System.Collections.Generic; - -#if NET461 - -using System.Data.Entity; -using System.Data.Entity.Core.Metadata.Edm; -using System.Data.Entity.Infrastructure; - -#else - -using Microsoft.EntityFrameworkCore; - -#endif - -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; -using LinqKit; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - /// - /// Checks if there is any record that matches the query - /// - /// The query to execute in the Any method - /// True if there is at least one record - public virtual async Task ExistsAsync(Expression> where) - { - await using TContext ctx = Context; - return await ctx.Set().AsNoTracking().AnyAsync(where); - } - - /// - /// Gets the record by its identifier - /// - /// The identifier of the entity - /// The record of type that matches the id - public virtual async Task FindByIdAsync(object? id) - { - await using TContext ctx = Context; - return await ctx.Set().FindAsync(id); - } - - /// - /// Gets the record by its identifier - /// - /// The identifier of the entity - /// The optional list of related entities that should be eagerly loaded - /// The record of type that matches the id - public virtual async Task FindByIdAsync(object? id, params string[] includes) - { - await using TContext ctx = Context; - foreach (string include in includes) - ctx.Set().Include(include).AsNoTracking(); - - return await ctx.Set().FindAsync(id); - } - - /// - /// Gets the first record from the data store that matches the parameter - /// - /// The expression to execute against the data store - /// The first record of type that matches the query - public virtual async Task FindOneAsync(Expression> where) - { - await using TContext ctx = Context; - TEntity query = ctx.Set() - .AsNoTracking() - .AsExpandable() - .With(where) - .FirstOrDefault(); - - return await Task.Run(() => query); - } - - /// - /// Gets the first record from the data store that matches the parameter - /// - /// The expression to execute against the data store - /// The optional list of related entities that should be eagerly loaded - /// The first record of type that matches the query - public virtual async Task FindOneAsync(Expression> where, params string[] includes) - { - await using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .With(where); - - IQueryable fullGraphQuery = await Task.Run(() => query); - return fullGraphQuery.FirstOrDefault(); - } - - /// - /// Gets the first record from the data store that matches the parameter - /// - /// The projected class - /// The expression to execute against the data store - /// The expression for the projection of type that should be executed against the data store - /// The sorting expression to execute against the data store - /// Indicates whether the sorting is ascending (true) or descending (false) - /// The page number which is multiplied by the pagesize to calculate the amount of items to skip - /// The size of the batch of items that must be retrieved - /// The optional list of related entities that should be eagerly loaded - /// An instance of with the mapped data from the record that matched all filters. - public Task FindOneAsync( - Expression> where = null, - Expression> select = null, - Expression> orderBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) where TResult : class - { - using TContext ctx = Context; - IQueryable query = ctx.Set() - .AsExpandable() - .AsQueryable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select) - .Include(Context, includes); - - return Task.FromResult(query.FirstOrDefault()); - } - - /// - /// Finds entities based on provided criteria. - /// - /// The expression to execute against the data store - /// The optional list of related entities that should be eagerly loaded - /// An collection of that matched all filters. - public virtual async Task> FindAllAsync(Expression> where, params string[] includes) - { - await using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsQueryable() - .AsNoTracking() - .With(where); - - return await Task.FromResult(query.ToList()); - } - - /// - /// Gets the first record from the data store that matches the parameter - /// - /// The projected class - /// The expression to execute against the data store - /// The expression for the projection of type that should be executed against the data store - /// The sorting expression to execute against the data store - /// Indicates whether the sorting is ascending (true) or descending (false) - /// The page number which is multiplied by the pagesize to calculate the amount of items to skip - /// The size of the batch of items that must be retrieved - /// The optional list of related entities that should be eagerly loaded - /// An instance of with the mapped data from the record that matched all filters. - public virtual Task> FindAllAsync( - Expression> where = null, - Expression> select = null, - Expression> orderBy = null, - bool? ascending = null, - int? page = null, - int? pageSize = null, - params string[] includes) - { - using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .AsQueryable() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select); - - return Task.FromResult(query.ToList() as IEnumerable); - } - - /// - /// Retrieves a collection of paged, sorted and filtered items in a flat list - /// - /// The expression to execute against the data store - /// The order by. - /// - /// The page number which is multiplied by the page size to calculate the amount of items to skip - /// The size of the batch of items that must be retrieved - /// The optional list of related entities that should be eagerly loaded - /// An collection of with the mapped data from the records that matched all filters. - public virtual async Task> FindAllAsync( - Expression> where = null, - Expression> orderBy = null, - bool? ascending = null, - int? page = null, - int? pageSize = null, - params string[] includes) - { - await using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize); - - return await Task.FromResult(query.ToList()); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Repository/Sync/AggregateRepository.cs b/src/providers/EntityFramework.Shared/Repository/Sync/AggregateRepository.cs deleted file mode 100644 index 6aa199a..0000000 --- a/src/providers/EntityFramework.Shared/Repository/Sync/AggregateRepository.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; - -#if NET461 - -#else - -using Microsoft.EntityFrameworkCore; - -#endif - -namespace Dime.Repositories -{ - public partial class EfRepository - { - /// - /// Counts the amount of records in the data store for the table that corresponds to the entity type . - /// - /// A number of the amount of records - public long Count() - { - using TContext ctx = Context; - int count = ctx.Set().AsNoTracking().Count(); - - return count; - } - - /// - /// Counts the amount of records in the data store for the table that corresponds to the entity type . - /// - /// A number of the amount of records - /// The expression to execute against the data store - public long Count(Expression> where) - { - using TContext ctx = Context; - int count = ctx.Set().AsNoTracking().Count(where); - - return count; - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Repository/Sync/DeleteRepository.cs b/src/providers/EntityFramework.Shared/Repository/Sync/DeleteRepository.cs deleted file mode 100644 index 251b069..0000000 --- a/src/providers/EntityFramework.Shared/Repository/Sync/DeleteRepository.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Collections.Generic; - -#if NET461 - -using System.Data.Entity; - -#else - -using Microsoft.EntityFrameworkCore; - -#endif - -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - /// - /// Removes the record from the data store by its identifier - /// - /// The identifier of the entity - /// Void - public virtual void Delete(object? id) - { - using TContext ctx = Context; - TEntity item = ctx.Set().Find(id); - if (item == default(TEntity)) - return; - - ctx.Set().Remove(item); - SaveChanges(ctx); - } - - /// - /// Removes the record from the data store by its identifier - /// - /// The identifier of the entity - /// Indicates whether or not SaveChanges should be called during this call - /// Void - public virtual void Delete(object? id, bool commit) - { - using TContext ctx = Context; - TEntity item = ctx.Set().Find(id); - if (item == default(TEntity)) - return; - - ctx.Set().Remove(item); - if (commit) - SaveChanges(ctx); - } - - /// - /// Removes the record from the data store - /// - /// The disconnected entity to remove - /// Void - public virtual void Delete(TEntity entity) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - ctx.Set().Remove(entity); - SaveChanges(ctx); - } - - /// - /// Removes the records - /// - /// The disconnected entities to remove - /// Void - public void Delete(IEnumerable entities) - { - if (!entities.Any()) - return; - - using TContext ctx = Context; - foreach (TEntity entity in entities) - { - ctx.Set().Attach(entity); - ctx.Set().Remove(entity); - } - - SaveChanges(ctx); - } - - /// - /// Removes the record from the data store - /// - /// The disconnected entity to remove - /// Indicates whether or not SaveChanges should be called during this call - /// - public virtual void Delete(TEntity entity, bool commit) - { - using TContext ctx = Context; - ctx.Set().Attach(entity); - ctx.Set().Remove(entity); - - if (commit) - SaveChanges(ctx); - } - - /// - /// Removes the record from the data store - /// - /// The expression to execute against the data store - /// Void - public virtual void Delete(Expression> where) - { - using TContext ctx = Context; - IEnumerable entities = ctx.Set().With(where).AsNoTracking().ToList(); - if (entities == null) - return; - - foreach (TEntity item in entities) - ctx.Set().Attach(item); - - ctx.Set().RemoveRange(entities); - SaveChanges(ctx); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Repository/Sync/GetRepository.cs b/src/providers/EntityFramework.Shared/Repository/Sync/GetRepository.cs deleted file mode 100644 index b7bcdb7..0000000 --- a/src/providers/EntityFramework.Shared/Repository/Sync/GetRepository.cs +++ /dev/null @@ -1,274 +0,0 @@ -using System; -using System.Collections.Generic; - -#if NET461 - -using System.Data.Entity; - -#else - -using Microsoft.EntityFrameworkCore; - -#endif - -using System.Linq; -using System.Linq.Expressions; -using LinqKit; - -namespace Dime.Repositories -{ - public partial class EfRepository - { - /// - /// Checks if there is any record that matches the query - /// - /// The query to execute in the Any method - /// True if there is at least one record - public bool Exists(Expression> where) - { - using TContext ctx = Context; - return ctx.Set().AsNoTracking().Any(where); - } - - /// - /// Gets the record by its identifier - /// - /// The identifier of the entity - /// The record of type that matches the id - public virtual TEntity FindById(object? id) - { - using TContext ctx = Context; - return ctx.Set().Find(id); - } - - /// - /// Gets the record by its identifier - /// - /// The identifier of the entity - /// The optional list of related entities that should be eagerly loaded - /// The record of type that matches the id - public virtual TEntity FindById(object? id, params string[] includes) - { - using TContext ctx = Context; - foreach (string include in includes) - ctx.Set().Include(include).AsNoTracking(); - - return ctx.Set().Find(id); - } - - /// - /// Gets the first record from the data store that matches the parameter - /// - /// The expression to execute against the data store - /// The first record of type that matches the query - public virtual TEntity FindOne(Expression> where) - { - using TContext ctx = Context; - TEntity query = ctx.Set() - .AsNoTracking() - .AsExpandable() - .With(where) - .FirstOrDefault(); - - return query; - } - - /// - /// Gets the first record from the data store that matches the parameter - /// - /// The expression to execute against the data store - /// The optional list of related entities that should be eagerly loaded - /// The first record of type that matches the query - public virtual TEntity FindOne(Expression> where, params string[] includes) - { - using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .With(where); - - return query.FirstOrDefault(); - } - - /// - /// Gets the first record from the data store that matches the parameter - /// - /// The projected class - /// The expression to execute against the data store - /// The expression for the projection of type that should be executed against the data store - /// The sorting expression to execute against the data store - /// Indicates whether the sorting is ascending (true) or descending (false) - /// The page number which is multiplied by the pagesize to calculate the amount of items to skip - /// The size of the batch of items that must be retrieved - /// The optional list of related entities that should be eagerly loaded - /// An instance of with the mapped data from the record that matched all filters. - public TResult FindOne( - Expression> where = null, - Expression> select = null, - Expression> orderBy = null, - bool? ascending = default, - int? page = default, - int? pageSize = default, - params string[] includes) where TResult : class - { - using TContext ctx = Context; - IQueryable query = ctx.Set() - .AsExpandable() - .AsQueryable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select) - .Include(Context, includes); - - return query.FirstOrDefault(); - } - - /// - /// Finds entities based on provided criteria. - /// - /// The expression to execute against the data store - /// An collection of that matched all filters. - public IEnumerable FindAll(Expression> where) - { - using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, null) - .AsExpandable() - .AsQueryable() - .AsNoTracking() - .With(where); - - return query.ToList(); - } - - /// - /// Finds entities based on provided criteria. - /// - /// The expression to execute against the data store - /// The optional list of related entities that should be eagerly loaded - /// An collection of that matched all filters. - public virtual IEnumerable FindAll(Expression> where, params string[] includes) - { - using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsQueryable() - .AsNoTracking() - .With(where); - - return query.ToList(); - } - - /// - /// Finds entities based on provided criteria. - /// - /// The expression to execute against the data store - /// The flag to indicate if all navigation properties should be eagerly loaed - /// The optional list of related entities that should be eagerly loaded - /// An collection of that matched all filters. - public IEnumerable FindAll(Expression> where, bool includeAll, params string[] includes) - { - using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsQueryable() - .AsNoTracking() - .With(where); - - return query.ToList(); - } - - /// - /// Retrieves a collection of paged and filtered items in a flat list - /// - /// The expression to execute against the data store - /// The page number which is multiplied by the pagesize to calculate the amount of items to skip - /// The size of the batch of items that must be retrieved - /// The optional list of related entities that should be eagerly loaded - /// An collection of with the mapped data from the records that matched all filters. - public IEnumerable FindAll(Expression> where, int? page, int? pageSize, string[] includes) - { - using TContext ctx = Context; - return ctx.Set() - .AsExpandable() - .AsQueryable() - .AsNoTracking() - .With(where) - .With(page, pageSize, default(IEnumerable>>)) - .With(pageSize) - .Include(Context, includes); - } - - /// - /// Gets the records from the data store that matches the parameter - /// - /// The projected class - /// The expression to execute against the data store - /// The expression for the projection of type that should be executed against the data store - /// The sorting expression to execute against the data store - /// Indicates whether the sorting is ascending (true) or descending (false) - /// The page number which is multiplied by the pagesize to calculate the amount of items to skip - /// The size of the batch of items that must be retrieved - /// The optional list of related entities that should be eagerly loaded - /// An instance of with the mapped data from the record that matched all filters. - public virtual IEnumerable FindAll( - Expression> where = null, - Expression> select = null, - Expression> orderBy = null, - bool? ascending = null, - int? page = null, - int? pageSize = null, - params string[] includes) - { - using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, includes) - .AsNoTracking() - .AsExpandable() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize) - .WithSelect(select); - - return query.ToList(); - } - - /// - /// Retrieves a collection of paged, sorted and filtered items in a flat list - /// - /// The expression to execute against the data store - /// The order by. - /// - /// The page number which is multiplied by the pagesize to calculate the amount of items to skip - /// The size of the batch of items that must be retrieved - /// The optional list of related entities that should be eagerly loaded - /// An collection of with the mapped data from the records that matched all filters. - public virtual IEnumerable FindAll( - Expression> where = null, - Expression> orderBy = null, - bool? ascending = null, - int? page = null, - int? pageSize = null, - params string[] includes) - { - using TContext ctx = Context; - IQueryable query = ctx.Set() - .Include(ctx, includes) - .AsExpandable() - .AsNoTracking() - .With(where) - .WithOrder(orderBy, ascending ?? true) - .With(page, pageSize, orderBy) - .With(pageSize); - - return query.ToList(); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Utilities/LinqOperationExtensions.cs b/src/providers/EntityFramework.Shared/Utilities/LinqOperationExtensions.cs deleted file mode 100644 index 913591a..0000000 --- a/src/providers/EntityFramework.Shared/Utilities/LinqOperationExtensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - internal static class OrderLinq - { - /// - /// - /// - /// - /// - /// - /// - [Obsolete("In a next release this will be internal. Fetch a utility library instead.", false)] - internal static IOrderedQueryable OrderDescending(this IEnumerable query, string propertyName) - { - LinqOrderHelper helper = new("OrderByDescending", propertyName); - return helper.GetAsQueryable(query); - } - - /// - /// - /// - /// - /// - /// - /// - [Obsolete("In a next release this will be internal. Fetch a utility library instead.", false)] - internal static IOrderedQueryable Order(this IEnumerable query, string propertyName) - { - LinqOrderHelper helper = new("OrderBy", propertyName); - return helper.GetAsQueryable(query); - } - - /// - /// - /// - /// - /// - /// - /// - [Obsolete("In a next release this will be internal. Fetch a utility library instead.", false)] - internal static IOrderedQueryable ThenBy(this IEnumerable source, string property) - { - LinqOrderHelper helper = new("ThenBy", property); - return helper.GetAsQueryable(source); - } - - /// - /// - /// - /// - /// - /// - /// - [Obsolete("In a next release this will be internal. Fetch a utility library instead.", false)] - internal static IOrderedQueryable ThenByDescending(this IEnumerable source, string property) - { - LinqOrderHelper helper = new("ThenByDescending", property); - return helper.GetAsQueryable(source); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Utilities/Query Factory/GroupByQueryFactory.cs b/src/providers/EntityFramework.Shared/Utilities/Query Factory/GroupByQueryFactory.cs deleted file mode 100644 index 0b5b073..0000000 --- a/src/providers/EntityFramework.Shared/Utilities/Query Factory/GroupByQueryFactory.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - internal static partial class QueryFactory - { - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// - /// The source. - /// The predicate. - /// - public static IQueryable> WithGroup(this IQueryable source, Expression> predicate) - => source.GroupBy(predicate); - - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// - /// The source. - /// The predicate. - /// - public static IQueryable> WithGroup(this IQueryable source, Func predicate) - => source.GroupBy(predicate).AsQueryable(); - - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// - /// The source. - /// The predicate. - /// - public static IQueryable> WithGroup(this IOrderedEnumerable source, Func predicate) - => source.GroupBy(predicate).AsQueryable(); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Utilities/Query Factory/SelectQueryFactory.cs b/src/providers/EntityFramework.Shared/Utilities/Query Factory/SelectQueryFactory.cs deleted file mode 100644 index 0810e97..0000000 --- a/src/providers/EntityFramework.Shared/Utilities/Query Factory/SelectQueryFactory.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - internal static partial class QueryFactory - { - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect( - this IQueryable> source, - Expression, IEnumerable>> selector) - => selector == null ? default : source.SelectMany(selector); - - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect( - this IQueryable> source, - Expression, int, TResult>> selector) - => selector == null ? default : source.Select(selector); - - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect(this IOrderedEnumerable source, - Func selector) - where TSource : class - where TResult : class - => selector == null ? default : source.Select(selector).AsQueryable(); - - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect(this IQueryable source, - Expression> selector) - where TSource : class - => selector == null ? default : source.Select(selector).AsQueryable(); - - /// - /// Withes the specified selector. - /// - /// The type of the source. - /// The type of the result. - /// The source. - /// The selector. - /// - internal static IQueryable WithSelect(this IQueryable source, - Func selector) - where TSource : class - where TResult : class - => selector == null ? default : source.Select(selector).AsQueryable(); - - /// - /// - /// - /// - /// - /// - /// - /// - internal static TResult WithFirstSelect(this TSource source, - Expression> selector) - where TSource : class - where TResult : class - => selector == null - ? default - : new List { source }.AsQueryable().Select(selector).FirstOrDefault(); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Utilities/Query Factory/SkipQueryFactory.cs b/src/providers/EntityFramework.Shared/Utilities/Query Factory/SkipQueryFactory.cs deleted file mode 100644 index 6daf9c9..0000000 --- a/src/providers/EntityFramework.Shared/Utilities/Query Factory/SkipQueryFactory.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; - -#if NET461 - -using System.Data.Entity; - -#else - -#endif - -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - internal static partial class QueryFactory - { - /// - /// Bypasses a specified number of elements in a sequence and then returns the remaining elements. - /// - /// The type of the elements of source. - /// An System.Linq.IQueryable`1 to return elements from. - /// The number of elements to skip before returning the remaining elements. - /// Size of the page. - /// - /// An System.Linq.IQueryable`1 that contains elements that occur after the specified index in the input sequence. - internal static IQueryable With(this IQueryable source, int? page, int? pageSize, IEnumerable> orderBy) - { - int pageToApply = page.GetValueOrDefault(); - int pageSizeToApply = pageSize.GetValueOrDefault(); - - if (pageToApply == 0 || pageSizeToApply == 0) - return source; - - int itemsToSkip = (pageToApply - 1) * pageSizeToApply; - - return orderBy == null - ? source.OrderBy(x => true).Skip(itemsToSkip) - : source.Skip(itemsToSkip); - } - - /// - /// Bypasses a specified number of elements in a sequence and then returns the remaining elements. - /// - /// The type of the elements of source. - /// An System.Linq.IQueryable`1 to return elements from. - /// The number of elements to skip before returning the remaining elements. - /// Size of the page. - /// - /// An System.Linq.IQueryable`1 that contains elements that occur after the specified index in the input sequence. - internal static IQueryable With(this IQueryable source, int? page, int? pageSize, Expression> orderBy) - { - int pageToApply = page.GetValueOrDefault(); - int pageSizeToApply = pageSize.GetValueOrDefault(); - - if (pageToApply == 0 || pageSizeToApply == 0) - return source; - - int itemsToSkip = (pageToApply - 1) * pageSizeToApply; - - return orderBy == null ? - source.OrderBy(x => true).Skip(itemsToSkip) : - source.Skip(itemsToSkip); - } - - /// - /// Bypasses a specified number of elements in a sequence and then returns the remaining elements. - /// - /// The type of the elements of source. - /// An System.Linq.IQueryable`1 to return elements from. - /// The number of elements to skip before returning the remaining elements. - /// Size of the page. - /// - /// An System.Linq.IQueryable`1 that contains elements that occur after the specified index in the input sequence. - internal static IQueryable With(this IQueryable source, int? page, int? pageSize, IEnumerable>> orderBy) - { - int pageToApply = page.GetValueOrDefault(); - int pageSizeToApply = pageSize.GetValueOrDefault(); - - if (pageToApply == 0 || pageSizeToApply == 0) - return source; - - int itemsToSkip = (pageToApply - 1) * pageSizeToApply; - - return orderBy == null ? - source.OrderBy(x => true).Skip(itemsToSkip) : - source.Skip(itemsToSkip); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Utilities/Query Factory/TakeQueryFactory.cs b/src/providers/EntityFramework.Shared/Utilities/Query Factory/TakeQueryFactory.cs deleted file mode 100644 index 47ac7ff..0000000 --- a/src/providers/EntityFramework.Shared/Utilities/Query Factory/TakeQueryFactory.cs +++ /dev/null @@ -1,28 +0,0 @@ -#if NET461 - -using System.Data.Entity; - -#endif - -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Dime.Repositories -{ - [ExcludeFromCodeCoverage] - internal static class TakeQueryFactory - { - /// - /// Returns a specified number of contiguous elements from the start of a sequence. - /// - /// The type of the source. - /// The sequence to return elements from. - /// The number of elements to return. - /// An System.Linq.IQueryable`1 that contains the specified number of elements from the start of source. - internal static IQueryable With(this IQueryable source, int? takeCount) - { - int itemsToTake = takeCount.GetValueOrDefault(); - return itemsToTake == 0 ? source : source.Take(itemsToTake); - } - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Utilities/Query Factory/WhereQueryFactory.cs b/src/providers/EntityFramework.Shared/Utilities/Query Factory/WhereQueryFactory.cs deleted file mode 100644 index ee48f92..0000000 --- a/src/providers/EntityFramework.Shared/Utilities/Query Factory/WhereQueryFactory.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; - -namespace Dime.Repositories -{ - internal static partial class QueryFactory - { - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// The source. - /// The predicate. - /// - internal static IQueryable With(this IQueryable source, Expression> predicate) - => predicate == null ? source : source.Where(predicate); - - /// - /// Wrapper around LINQ WHERE - /// - /// The type of the source. - /// The source. - /// The predicate. - /// - internal static TSource WithFirst(this IQueryable source, Expression> predicate) - => predicate == null ? source.FirstOrDefault() : source.FirstOrDefault(predicate); - } -} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Configuration/RepositoryConfiguration.cs b/src/providers/EntityFramework/Configuration/RepositoryConfiguration.cs similarity index 84% rename from src/providers/EntityFramework.Shared/Configuration/RepositoryConfiguration.cs rename to src/providers/EntityFramework/Configuration/RepositoryConfiguration.cs index 5f8c103..8a6d395 100644 --- a/src/providers/EntityFramework.Shared/Configuration/RepositoryConfiguration.cs +++ b/src/providers/EntityFramework/Configuration/RepositoryConfiguration.cs @@ -1,8 +1,11 @@ -namespace Dime.Repositories +using System.Diagnostics.CodeAnalysis; + +namespace Dime.Repositories { /// /// Represents a repository configuration object /// + [ExcludeFromCodeCoverage] public class RepositoryConfiguration { /// diff --git a/src/providers/EntityFramework.NetCore/Dime.Repositories.Sql.EntityFramework.NetCore.csproj b/src/providers/EntityFramework/Dime.Repositories.Sql.EntityFramework.csproj similarity index 71% rename from src/providers/EntityFramework.NetCore/Dime.Repositories.Sql.EntityFramework.NetCore.csproj rename to src/providers/EntityFramework/Dime.Repositories.Sql.EntityFramework.csproj index ab6d49f..32bd780 100644 --- a/src/providers/EntityFramework.NetCore/Dime.Repositories.Sql.EntityFramework.NetCore.csproj +++ b/src/providers/EntityFramework/Dime.Repositories.Sql.EntityFramework.csproj @@ -19,34 +19,28 @@ Dime Software - net7.0 + net8.0 Dime.Repositories.Sql.EntityFramework Dime.Repositories.Sql.EntityFramework Entity Framework;Repository;SQL https://cdn.dime-software.com/dime-software/logo-shape.png - 2.0.0.0-alpha.47 + 2.0.0.0 Implementation of the repository pattern with Microsoft SQL using Entity Framework Core - Copyright © 2022 + Copyright © 2023 https://github.com/dimesoftware/repository https://github.com/dimesoftware/repository git - - - - - - - - + + + - diff --git a/src/providers/EntityFramework.Shared/Exceptions/ConcurrencyException.cs b/src/providers/EntityFramework/Exceptions/ConcurrencyException.cs similarity index 70% rename from src/providers/EntityFramework.Shared/Exceptions/ConcurrencyException.cs rename to src/providers/EntityFramework/Exceptions/ConcurrencyException.cs index 70e4da5..a9b27a9 100644 --- a/src/providers/EntityFramework.Shared/Exceptions/ConcurrencyException.cs +++ b/src/providers/EntityFramework/Exceptions/ConcurrencyException.cs @@ -1,9 +1,10 @@ using System; -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; namespace Dime.Repositories { [Serializable] + [ExcludeFromCodeCoverage] public class ConcurrencyException : Exception { public ConcurrencyException() @@ -17,9 +18,5 @@ public ConcurrencyException(string message) : base(message) public ConcurrencyException(string message, Exception innerException) : base(message, innerException) { } - - protected ConcurrencyException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } } } \ No newline at end of file diff --git a/src/providers/EntityFramework/Exceptions/ConstraintViolationException.cs b/src/providers/EntityFramework/Exceptions/ConstraintViolationException.cs new file mode 100644 index 0000000..a194fd0 --- /dev/null +++ b/src/providers/EntityFramework/Exceptions/ConstraintViolationException.cs @@ -0,0 +1,27 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; + +namespace Dime.Repositories +{ + [Serializable] + [ExcludeFromCodeCoverage] + public class ConstraintViolationException : Exception + { + public ConstraintViolationException() + { + } + + public ConstraintViolationException(string message) : base(message) + { + } + + public ConstraintViolationException(string message, Exception innerException) : base(message, innerException) + { + } + + protected ConstraintViolationException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/src/providers/EntityFramework/Exceptions/DatabaseAccessException.cs b/src/providers/EntityFramework/Exceptions/DatabaseAccessException.cs new file mode 100644 index 0000000..706f8ef --- /dev/null +++ b/src/providers/EntityFramework/Exceptions/DatabaseAccessException.cs @@ -0,0 +1,30 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; + +namespace Dime.Repositories +{ + [Serializable] + [ExcludeFromCodeCoverage] + public class DatabaseAccessException : Exception + { + public DatabaseAccessException() + { + } + + public DatabaseAccessException(string message) + : base(message) + { + } + + public DatabaseAccessException(string message, Exception innerException) + : base(message, innerException) + { + } + + protected DatabaseAccessException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/src/providers/EntityFramework.NetCore/Model Builder/DbContextModelBuilder.cs b/src/providers/EntityFramework/Model Builder/DbContextModelBuilder.cs similarity index 100% rename from src/providers/EntityFramework.NetCore/Model Builder/DbContextModelBuilder.cs rename to src/providers/EntityFramework/Model Builder/DbContextModelBuilder.cs diff --git a/src/providers/EntityFramework.NetCore/Model Builder/IModelBuilder.cs b/src/providers/EntityFramework/Model Builder/IModelBuilder.cs similarity index 100% rename from src/providers/EntityFramework.NetCore/Model Builder/IModelBuilder.cs rename to src/providers/EntityFramework/Model Builder/IModelBuilder.cs diff --git a/src/providers/EntityFramework.NetFramework/Repository/Async/AggregateRepositoryAsync.cs b/src/providers/EntityFramework/Repository/Async/AggregateRepositoryAsync.cs similarity index 52% rename from src/providers/EntityFramework.NetFramework/Repository/Async/AggregateRepositoryAsync.cs rename to src/providers/EntityFramework/Repository/Async/AggregateRepositoryAsync.cs index 5e522a7..a1a750d 100644 --- a/src/providers/EntityFramework.NetFramework/Repository/Async/AggregateRepositoryAsync.cs +++ b/src/providers/EntityFramework/Repository/Async/AggregateRepositoryAsync.cs @@ -7,17 +7,15 @@ namespace Dime.Repositories public partial class EfRepository { public Task CountAsync() - { - using TContext ctx = Context; - long count = ctx.Count(); - return Task.FromResult(count); - } + => CountAsync(null); public Task CountAsync(Expression> where) { - using TContext ctx = Context; - long count = ctx.Count(where); - return Task.FromResult(count); + long count; + using (TContext ctx = Context) + count = ctx.Count(where); + + return Task.FromResult((long)count); } } } \ No newline at end of file diff --git a/src/providers/EntityFramework.NetCore/Repository/Async/CreateRepositoryAsync.cs b/src/providers/EntityFramework/Repository/Async/CreateRepositoryAsync.cs similarity index 90% rename from src/providers/EntityFramework.NetCore/Repository/Async/CreateRepositoryAsync.cs rename to src/providers/EntityFramework/Repository/Async/CreateRepositoryAsync.cs index 86bcb0a..9095933 100644 --- a/src/providers/EntityFramework.NetCore/Repository/Async/CreateRepositoryAsync.cs +++ b/src/providers/EntityFramework/Repository/Async/CreateRepositoryAsync.cs @@ -3,24 +3,15 @@ using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; - -#if NET461 - -using System.Data.Entity; - -#else - using Microsoft.EntityFrameworkCore; -#endif - namespace Dime.Repositories { public partial class EfRepository { public virtual async Task CreateAsync(TEntity entity) { - await using TContext ctx = Context; + TContext ctx = Context; ctx.Entry(entity).State = EntityState.Added; TEntity createdItem = ctx.Set().Add(entity)?.Entity; await SaveChangesAsync(ctx); @@ -46,7 +37,7 @@ public virtual async Task CreateAsync(TEntity entity, Expression CreateAsync(TEntity entity, Func beforeSaveAction) { - await using TContext ctx = Context; + TContext ctx = Context; await beforeSaveAction(entity, ctx); ctx.Entry(entity).State = EntityState.Added; @@ -58,7 +49,7 @@ public virtual async Task CreateAsync(TEntity entity, Func CreateAsync(TEntity entity, bool commit) { - await using TContext ctx = Context; + TContext ctx = Context; ctx.Entry(entity).State = EntityState.Added; TEntity createdItem = ctx.Set().Add(entity)?.Entity; @@ -74,7 +65,7 @@ public virtual async Task> CreateAsync(IQueryable e return entities; List newEntities = new(); - await using TContext ctx = Context; + TContext ctx = Context; foreach (TEntity entity in entities.ToList()) { ctx.Entry(entity).State = EntityState.Added; diff --git a/src/providers/EntityFramework.Shared/Repository/Async/DeleteRepositoryAsync.cs b/src/providers/EntityFramework/Repository/Async/DeleteRepositoryAsync.cs similarity index 88% rename from src/providers/EntityFramework.Shared/Repository/Async/DeleteRepositoryAsync.cs rename to src/providers/EntityFramework/Repository/Async/DeleteRepositoryAsync.cs index 0b611ff..e42e5e5 100644 --- a/src/providers/EntityFramework.Shared/Repository/Async/DeleteRepositoryAsync.cs +++ b/src/providers/EntityFramework/Repository/Async/DeleteRepositoryAsync.cs @@ -4,17 +4,8 @@ using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; - -#if NET461 - -using System.Data.Entity; - -#else - using Microsoft.EntityFrameworkCore; -#endif - namespace Dime.Repositories { public partial class EfRepository @@ -28,7 +19,7 @@ public virtual async Task DeleteAsync(object? id) return; } - await using TContext ctx = Context; + TContext ctx = Context; TEntity item = await ctx.Set().FindAsync(id); if (item != default(TEntity)) { @@ -39,7 +30,7 @@ public virtual async Task DeleteAsync(object? id) public virtual async Task DeleteAsync(IEnumerable ids) { - await using TContext ctx = Context; + TContext ctx = Context; foreach (object id in ids.Distinct().ToList()) { TEntity item = await ctx.Set().FindAsync(id); @@ -54,7 +45,7 @@ public virtual async Task DeleteAsync(IEnumerable ids) public virtual async Task DeleteAsync(object? id, bool commit) { - await using TContext ctx = Context; + TContext ctx = Context; TEntity item = await ctx.Set().FindAsync(id); if (item != default(TEntity)) { @@ -66,7 +57,7 @@ public virtual async Task DeleteAsync(object? id, bool commit) public virtual async Task DeleteAsync(TEntity entity) { - await using TContext ctx = Context; + TContext ctx = Context; ctx.Set().Attach(entity); ctx.Set().Remove(entity); await SaveChangesAsync(ctx); @@ -77,7 +68,7 @@ public async Task DeleteAsync(IEnumerable entities) if (!entities.Any()) return; - await using TContext ctx = Context; + TContext ctx = Context; foreach (TEntity entity in entities) { ctx.Set().Attach(entity); @@ -89,7 +80,7 @@ public async Task DeleteAsync(IEnumerable entities) public virtual async Task DeleteAsync(TEntity entity, bool commit) { - await using TContext ctx = Context; + TContext ctx = Context; ctx.Set().Attach(entity); ctx.Set().Remove(entity); @@ -99,7 +90,7 @@ public virtual async Task DeleteAsync(TEntity entity, bool commit) public virtual async Task DeleteAsync(Expression> where) { - await using TContext ctx = Context; + TContext ctx = Context; IEnumerable entities = ctx.Set().With(where).AsNoTracking().ToList(); if (entities.Any()) { diff --git a/src/providers/EntityFramework.NetFramework/Repository/Async/GetRepositoryAsync.cs b/src/providers/EntityFramework/Repository/Async/GetRepositoryAsync.cs similarity index 71% rename from src/providers/EntityFramework.NetFramework/Repository/Async/GetRepositoryAsync.cs rename to src/providers/EntityFramework/Repository/Async/GetRepositoryAsync.cs index 6dcce8b..beb2d31 100644 --- a/src/providers/EntityFramework.NetFramework/Repository/Async/GetRepositoryAsync.cs +++ b/src/providers/EntityFramework/Repository/Async/GetRepositoryAsync.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Core.Metadata.Edm; -using System.Data.Entity.Infrastructure; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using LinqKit; +using Microsoft.EntityFrameworkCore; namespace Dime.Repositories { @@ -14,19 +12,19 @@ public partial class EfRepository { public virtual async Task ExistsAsync(Expression> where) { - using TContext ctx = Context; + TContext ctx = Context; return await ctx.Set().AsNoTracking().AnyAsync(where); } public virtual async Task FindByIdAsync(object? id) { - using TContext ctx = Context; + TContext ctx = Context; return await ctx.Set().FindAsync(id); } public virtual async Task FindByIdAsync(object? id, params string[] includes) { - using TContext ctx = Context; + TContext ctx = Context; foreach (string include in includes) ctx.Set().Include(include).AsNoTracking(); @@ -35,7 +33,7 @@ public virtual async Task FindByIdAsync(object? id, params string[] inc public virtual async Task FindOneAsync(Expression> where) { - using TContext ctx = Context; + TContext ctx = Context; TEntity query = ctx.Set() .AsNoTracking() .AsExpandable() @@ -47,15 +45,12 @@ public virtual async Task FindOneAsync(Expression> public virtual async Task FindOneAsync(Expression> where, params string[] includes) { - using TContext ctx = Context; - IQueryable query = ctx.Set() + TContext ctx = Context; + return ctx.Set() .Include(ctx, includes) .AsNoTracking() .AsExpandable() - .With(where); - - IQueryable fullGraphQuery = await Task.Run(() => query); - return fullGraphQuery.FirstOrDefault(); + .WithFirst(where); } public Task FindOneAsync( @@ -76,15 +71,15 @@ public Task FindOneAsync( .WithOrder(orderBy, ascending ?? true) .With(page, pageSize, orderBy) .With(pageSize) - .WithSelect(select); + .WithSelect(select) + .Include(Context, includes); - IQueryable fullGraphQuery = Include(query, includes); - return Task.FromResult(fullGraphQuery.FirstOrDefault()); + return Task.FromResult(query.FirstOrDefault()); } public virtual async Task> FindAllAsync(Expression> where, params string[] includes) { - using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) .AsExpandable() @@ -127,7 +122,7 @@ public virtual async Task> FindAllAsync( int? pageSize = null, params string[] includes) { - using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) .AsExpandable() @@ -139,22 +134,5 @@ public virtual async Task> FindAllAsync( return await Task.FromResult(query.ToList()); } - - private IQueryable Include(IQueryable query, params string[] includes) - { - if (includes == null) - return query; - - if (includes.Any()) - return includes - .Where(include => include != null) - .Aggregate(query, (current, include) => current.Include(include)); - - MetadataWorkspace workspace = ((IObjectContextAdapter)Context).ObjectContext.MetadataWorkspace; - ObjectItemCollection itemCollection = (ObjectItemCollection)workspace.GetItemCollection(DataSpace.OSpace); - EntityType entityType = itemCollection.OfType().Single(e => itemCollection.GetClrType(e) == typeof(TEntity)); - - return entityType.NavigationProperties.Aggregate(query, (current, navigationProperty) => current.Include(navigationProperty.Name)); - } } } \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Repository/Async/PagedRepositoryAsync.cs b/src/providers/EntityFramework/Repository/Async/PagedRepositoryAsync.cs similarity index 96% rename from src/providers/EntityFramework.Shared/Repository/Async/PagedRepositoryAsync.cs rename to src/providers/EntityFramework/Repository/Async/PagedRepositoryAsync.cs index 634b0a0..e42cdca 100644 --- a/src/providers/EntityFramework.Shared/Repository/Async/PagedRepositoryAsync.cs +++ b/src/providers/EntityFramework/Repository/Async/PagedRepositoryAsync.cs @@ -1,27 +1,15 @@ using System; using System.Collections.Generic; - -#if NET461 - -using System.Data.Entity; - -#else - -using Microsoft.EntityFrameworkCore; - -#endif - using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using LinqKit; +using Microsoft.EntityFrameworkCore; namespace Dime.Repositories { public partial class EfRepository { - #region Projected Pages - /// /// Finds all asynchronous. /// @@ -129,7 +117,7 @@ public async Task> FindAllPagedAsync( int? pageSize = default, params string[] includes) where TResult : class { - await using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) @@ -171,7 +159,7 @@ public async Task> FindAllPagedAsync( int? pageSize = default, params string[] includes) where TResult : class { - await using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) @@ -186,10 +174,6 @@ public async Task> FindAllPagedAsync( return await Task.FromResult(new Page(query.ToList(), ctx.Count(count))); } - #endregion Projected Pages - - #region Unprojected Pages - /// /// /// @@ -208,7 +192,7 @@ public async Task> FindAllPagedAsync( int? pageSize = default, params string[] includes) { - await using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) @@ -246,7 +230,7 @@ public async Task> FindAllPagedAsync( int? pageSize = default, params string[] includes) { - await using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) @@ -281,7 +265,7 @@ public async Task> FindAllPagedAsync( int? pageSize = default, params string[] includes) { - await using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) @@ -314,7 +298,7 @@ public async Task> FindAllPagedAsync( bool trackChanges = false, params string[] includes) { - await using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) @@ -347,7 +331,7 @@ public async Task> FindAllPagedAsync( int? pageSize = default, params string[] includes) { - await using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) @@ -379,7 +363,7 @@ public async Task> FindAllPagedAsync( int? pageSize = default, params string[] includes) { - await using TContext ctx = Context; + TContext ctx = Context; IQueryable query = ctx.Set() .Include(ctx, includes) @@ -393,7 +377,5 @@ public async Task> FindAllPagedAsync( return await Task.FromResult(new Page(query.ToList(), ctx.Count(where))); } - - #endregion Unprojected Pages } } \ No newline at end of file diff --git a/src/providers/EntityFramework.NetCore/Repository/Async/RepositoryAsync.cs b/src/providers/EntityFramework/Repository/Async/RepositoryAsync.cs similarity index 92% rename from src/providers/EntityFramework.NetCore/Repository/Async/RepositoryAsync.cs rename to src/providers/EntityFramework/Repository/Async/RepositoryAsync.cs index 4179a76..945f944 100644 --- a/src/providers/EntityFramework.NetCore/Repository/Async/RepositoryAsync.cs +++ b/src/providers/EntityFramework/Repository/Async/RepositoryAsync.cs @@ -48,12 +48,8 @@ public virtual async Task SaveChangesAsync() throw sqlException.Number switch { 2627 => (Exception)new ConcurrencyException(sqlException.Message, sqlException), - 547 => new ConstraintViolationException(sqlException.Message, - sqlException) - , - 2601 => new ConstraintViolationException(sqlException.Message, - sqlException) - , + 547 => new ConstraintViolationException(sqlException.Message, sqlException), + 2601 => new ConstraintViolationException(sqlException.Message, sqlException), _ => new DatabaseAccessException(sqlException.Message, sqlException) }; } @@ -105,12 +101,8 @@ public virtual async Task SaveChangesAsync(TContext context) throw sqlException.Number switch { 2627 => (Exception)new ConcurrencyException(sqlException.Message, sqlException), - 547 => new ConstraintViolationException(sqlException.Message, - sqlException) - , - 2601 => new ConstraintViolationException(sqlException.Message, - sqlException) - , + 547 => new ConstraintViolationException(sqlException.Message, sqlException), + 2601 => new ConstraintViolationException(sqlException.Message, sqlException), _ => new DatabaseAccessException(sqlException.Message, sqlException) }; } diff --git a/src/providers/EntityFramework.NetCore/Repository/Async/SqlRepositoryAsync.cs b/src/providers/EntityFramework/Repository/Async/SqlRepositoryAsync.cs similarity index 94% rename from src/providers/EntityFramework.NetCore/Repository/Async/SqlRepositoryAsync.cs rename to src/providers/EntityFramework/Repository/Async/SqlRepositoryAsync.cs index 0acca46..c027775 100644 --- a/src/providers/EntityFramework.NetCore/Repository/Async/SqlRepositoryAsync.cs +++ b/src/providers/EntityFramework/Repository/Async/SqlRepositoryAsync.cs @@ -12,7 +12,7 @@ public partial class EfRepository { public async Task ExecuteSqlAsync(string sql) { - await using TContext ctx = Context; + TContext ctx = Context; await ctx.Database.ExecuteSqlRawAsync(sql); } @@ -25,7 +25,7 @@ string ExecQuery(string x, DbParameter[] y) } string execQueryString = ExecQuery(name, parameters); - await using TContext ctx = Context; + TContext ctx = Context; return await ctx.Database.ExecuteSqlRawAsync(execQueryString, parameters); } @@ -38,7 +38,7 @@ string ExecQuery(string x, DbParameter[] y) } string execQueryString = ExecQuery(name, parameters); - await using TContext ctx = Context; + TContext ctx = Context; return await ctx.Database.ExecuteSqlRawAsync(execQueryString, parameters); } @@ -65,7 +65,7 @@ string ExecQuery(string x, DbParameter[] y) } string execQueryString = ExecQuery(nameof(name), parameters); - await using TContext ctx = Context; + TContext ctx = Context; return 1; } diff --git a/src/providers/EntityFramework.NetCore/Repository/Async/UpdateRepositoryAsync.cs b/src/providers/EntityFramework/Repository/Async/UpdateRepositoryAsync.cs similarity index 91% rename from src/providers/EntityFramework.NetCore/Repository/Async/UpdateRepositoryAsync.cs rename to src/providers/EntityFramework/Repository/Async/UpdateRepositoryAsync.cs index 603dbd6..ff78814 100644 --- a/src/providers/EntityFramework.NetCore/Repository/Async/UpdateRepositoryAsync.cs +++ b/src/providers/EntityFramework/Repository/Async/UpdateRepositoryAsync.cs @@ -12,7 +12,7 @@ public partial class EfRepository { public virtual async Task UpdateAsync(TEntity entity, bool commitChanges = true) { - await using TContext ctx = Context; + TContext ctx = Context; ctx.Set().Attach(entity); ctx.Entry(entity).State = EntityState.Modified; @@ -27,7 +27,7 @@ public async Task UpdateAsync(IEnumerable entities, bool commitChanges if (!entities.Any()) return; - await using TContext ctx = Context; + TContext ctx = Context; foreach (TEntity entity in entities) { ctx.Set().Attach(entity); @@ -39,7 +39,7 @@ public async Task UpdateAsync(IEnumerable entities, bool commitChanges public virtual async Task UpdateAsync(TEntity entity, params string[] properties) { - await using TContext ctx = Context; + TContext ctx = Context; ctx.Set().Attach(entity); EntityEntry entry = ctx.Entry(entity); @@ -53,7 +53,7 @@ public virtual async Task UpdateAsync(TEntity entity, params string[] p public virtual async Task UpdateAsync(TEntity entity, params Expression>[] properties) { - await using TContext ctx = Context; + TContext ctx = Context; ctx.Set().Attach(entity); EntityEntry entry = ctx.Entry(entity); diff --git a/src/providers/EntityFramework.NetCore/Repository/EfRepositoryFactory.cs b/src/providers/EntityFramework/Repository/EfRepositoryFactory.cs similarity index 100% rename from src/providers/EntityFramework.NetCore/Repository/EfRepositoryFactory.cs rename to src/providers/EntityFramework/Repository/EfRepositoryFactory.cs diff --git a/src/providers/EntityFramework.NetCore/Repository/IEfRepositoryFactory.cs b/src/providers/EntityFramework/Repository/IEfRepositoryFactory.cs similarity index 100% rename from src/providers/EntityFramework.NetCore/Repository/IEfRepositoryFactory.cs rename to src/providers/EntityFramework/Repository/IEfRepositoryFactory.cs diff --git a/src/providers/EntityFramework.NetFramework/Repository/Sync/AggregateRepository.cs b/src/providers/EntityFramework/Repository/Sync/AggregateRepository.cs similarity index 63% rename from src/providers/EntityFramework.NetFramework/Repository/Sync/AggregateRepository.cs rename to src/providers/EntityFramework/Repository/Sync/AggregateRepository.cs index 723e404..a783d5a 100644 --- a/src/providers/EntityFramework.NetFramework/Repository/Sync/AggregateRepository.cs +++ b/src/providers/EntityFramework/Repository/Sync/AggregateRepository.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore; namespace Dime.Repositories { @@ -9,13 +10,17 @@ public partial class EfRepository public long Count() { using TContext ctx = Context; - return ctx.Set().AsNoTracking().Count(); + int count = ctx.Set().AsNoTracking().Count(); + + return count; } public long Count(Expression> where) { using TContext ctx = Context; - return ctx.Set().AsNoTracking().Count(where); + int count = ctx.Set().AsNoTracking().Count(where); + + return count; } } } \ No newline at end of file diff --git a/src/providers/EntityFramework.NetCore/Repository/Sync/CreateRepository.cs b/src/providers/EntityFramework/Repository/Sync/CreateRepository.cs similarity index 100% rename from src/providers/EntityFramework.NetCore/Repository/Sync/CreateRepository.cs rename to src/providers/EntityFramework/Repository/Sync/CreateRepository.cs diff --git a/src/providers/EntityFramework.NetFramework/Repository/Sync/DeleteRepository.cs b/src/providers/EntityFramework/Repository/Sync/DeleteRepository.cs similarity index 89% rename from src/providers/EntityFramework.NetFramework/Repository/Sync/DeleteRepository.cs rename to src/providers/EntityFramework/Repository/Sync/DeleteRepository.cs index f13780b..f2e45f1 100644 --- a/src/providers/EntityFramework.NetFramework/Repository/Sync/DeleteRepository.cs +++ b/src/providers/EntityFramework/Repository/Sync/DeleteRepository.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using System.Data.Entity; using System.Linq; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore; namespace Dime.Repositories { @@ -16,7 +16,7 @@ public virtual void Delete(object? id) return; ctx.Set().Remove(item); - SaveChanges(Context); + SaveChanges(ctx); } public virtual void Delete(object? id, bool commit) @@ -28,7 +28,7 @@ public virtual void Delete(object? id, bool commit) ctx.Set().Remove(item); if (commit) - SaveChanges(Context); + SaveChanges(ctx); } public virtual void Delete(TEntity entity) @@ -36,7 +36,7 @@ public virtual void Delete(TEntity entity) using TContext ctx = Context; ctx.Set().Attach(entity); ctx.Set().Remove(entity); - SaveChanges(Context); + SaveChanges(ctx); } public void Delete(IEnumerable entities) @@ -51,7 +51,7 @@ public void Delete(IEnumerable entities) ctx.Set().Remove(entity); } - SaveChanges(Context); + SaveChanges(ctx); } public virtual void Delete(TEntity entity, bool commit) @@ -61,7 +61,7 @@ public virtual void Delete(TEntity entity, bool commit) ctx.Set().Remove(entity); if (commit) - SaveChanges(Context); + SaveChanges(ctx); } public virtual void Delete(Expression> where) @@ -75,7 +75,7 @@ public virtual void Delete(Expression> where) ctx.Set().Attach(item); ctx.Set().RemoveRange(entities); - SaveChanges(Context); + SaveChanges(ctx); } } } \ No newline at end of file diff --git a/src/providers/EntityFramework.NetFramework/Repository/Sync/GetRepository.cs b/src/providers/EntityFramework/Repository/Sync/GetRepository.cs similarity index 95% rename from src/providers/EntityFramework.NetFramework/Repository/Sync/GetRepository.cs rename to src/providers/EntityFramework/Repository/Sync/GetRepository.cs index d22dde7..cd33ef4 100644 --- a/src/providers/EntityFramework.NetFramework/Repository/Sync/GetRepository.cs +++ b/src/providers/EntityFramework/Repository/Sync/GetRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; -using System.Data.Entity; using System.Linq; using System.Linq.Expressions; using LinqKit; +using Microsoft.EntityFrameworkCore; namespace Dime.Repositories { @@ -72,9 +72,10 @@ public TResult FindOne( .WithOrder(orderBy, ascending ?? true) .With(page, pageSize, orderBy) .With(pageSize) - .WithSelect(select); + .WithSelect(select) + .Include(Context, includes); - return Include(query, includes).FirstOrDefault(); + return query.FirstOrDefault(); } public IEnumerable FindAll(Expression> where) @@ -119,15 +120,14 @@ public IEnumerable FindAll(Expression> where, bool public IEnumerable FindAll(Expression> where, int? page, int? pageSize, string[] includes) { using TContext ctx = Context; - IQueryable query = ctx.Set() + return ctx.Set() .AsExpandable() .AsQueryable() .AsNoTracking() .With(where) .With(page, pageSize, default(IEnumerable>>)) - .With(pageSize); - - return Include(query, includes); + .With(pageSize) + .Include(Context, includes); } public virtual IEnumerable FindAll( diff --git a/src/providers/EntityFramework.Shared/Repository/Sync/PagedRepository.cs b/src/providers/EntityFramework/Repository/Sync/PagedRepository.cs similarity index 67% rename from src/providers/EntityFramework.Shared/Repository/Sync/PagedRepository.cs rename to src/providers/EntityFramework/Repository/Sync/PagedRepository.cs index a302068..fb3e17c 100644 --- a/src/providers/EntityFramework.Shared/Repository/Sync/PagedRepository.cs +++ b/src/providers/EntityFramework/Repository/Sync/PagedRepository.cs @@ -3,35 +3,12 @@ using System.Linq; using System.Linq.Expressions; using LinqKit; - -#if NET461 - -using System.Data.Entity; - -#else - using Microsoft.EntityFrameworkCore; -#endif - namespace Dime.Repositories { public partial class EfRepository { - #region Projected Pages - - /// - /// Finds all hronous. - /// - /// The type of the result. - /// The where. - /// The select. - /// The order by. - /// - /// The page. - /// Size of the page. - /// The includes. - /// public virtual Page FindAllPaged( Expression> where = null, Expression> select = null, @@ -57,19 +34,6 @@ public virtual Page FindAllPaged( return new Page(query.ToList(), ctx.Count(where)); } - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// public Page FindAllPaged( Expression> where = null, Func groupBy = null, @@ -96,19 +60,6 @@ public Page FindAllPaged( return new Page(query.ToList(), ctx.Count(where)); } - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// public Page FindAllPaged( Expression> where = null, Expression> select = null, @@ -134,20 +85,6 @@ public Page FindAllPaged( return new Page(query.ToList(), ctx.Count(where)); } - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// public Page FindAllPaged( Expression> where = null, Expression> count = null, @@ -175,20 +112,6 @@ public Page FindAllPaged( return new Page(query.ToList(), ctx.Count(count)); } - #endregion Projected Pages - - #region Unprojected Pages - - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// public Page FindAllPaged( Expression> where = null, Expression> orderBy = null, @@ -212,17 +135,6 @@ public Page FindAllPaged( return new Page(query.ToList(), ctx.Count(where)); } - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// public Page FindAllPaged( Expression> where = null, Expression> orderBy = null, @@ -246,16 +158,6 @@ public Page FindAllPaged( return new Page(query.ToList(), ctx.Count(where)); } - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// public Page FindAllPaged( Expression> where = null, Expression> count = null, @@ -278,16 +180,6 @@ public Page FindAllPaged( return new Page(query.ToList(), ctx.Count(count)); } - /// - /// Gets the items hronously. - /// - /// The type of the entity. - /// The where. - /// The order by. - /// The page. - /// Size of the page. - /// The includes. - /// public Page FindAllPaged( Expression> where = null, IEnumerable> orderBy = null, @@ -309,16 +201,6 @@ public Page FindAllPaged( return new Page(query.ToList(), ctx.Count(where)); } - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// public Page FindAllPaged( Expression> where = null, IEnumerable>> orderBy = null, @@ -342,6 +224,5 @@ public Page FindAllPaged( return new Page(query.ToList(), ctx.Count(where)); } - #endregion Unprojected Pages } } \ No newline at end of file diff --git a/src/providers/EntityFramework.NetCore/Repository/Sync/Repository.cs b/src/providers/EntityFramework/Repository/Sync/Repository.cs similarity index 95% rename from src/providers/EntityFramework.NetCore/Repository/Sync/Repository.cs rename to src/providers/EntityFramework/Repository/Sync/Repository.cs index eb784ac..1933915 100644 --- a/src/providers/EntityFramework.NetCore/Repository/Sync/Repository.cs +++ b/src/providers/EntityFramework/Repository/Sync/Repository.cs @@ -67,6 +67,7 @@ public virtual bool SaveChanges(TContext context) failedEntry.OriginalValues.SetValues(dbValues); return SaveChanges(context); } + return true; } @@ -86,12 +87,8 @@ public virtual bool SaveChanges(TContext context) throw sqlException.Number switch { 2627 => (Exception)new ConcurrencyException(sqlException.Message, sqlException), - 547 => new ConstraintViolationException(sqlException.Message, - sqlException) - , - 2601 => new ConstraintViolationException(sqlException.Message, - sqlException) - , + 547 => new ConstraintViolationException(sqlException.Message, sqlException), + 2601 => new ConstraintViolationException(sqlException.Message, sqlException), _ => new DatabaseAccessException(sqlException.Message, sqlException) }; } diff --git a/src/providers/EntityFramework.NetCore/Repository/Sync/StoredProcedureRepository.cs b/src/providers/EntityFramework/Repository/Sync/StoredProcedureRepository.cs similarity index 98% rename from src/providers/EntityFramework.NetCore/Repository/Sync/StoredProcedureRepository.cs rename to src/providers/EntityFramework/Repository/Sync/StoredProcedureRepository.cs index 103c4b0..dc5df2f 100644 --- a/src/providers/EntityFramework.NetCore/Repository/Sync/StoredProcedureRepository.cs +++ b/src/providers/EntityFramework/Repository/Sync/StoredProcedureRepository.cs @@ -1,15 +1,8 @@ using System.Collections.Generic; using System.Data.Common; using System.Linq; -using Microsoft.EntityFrameworkCore; - -#if NET461 -using System.Data.SqlClient; -#else - using Microsoft.Data.SqlClient; - -#endif +using Microsoft.EntityFrameworkCore; namespace Dime.Repositories { diff --git a/src/providers/EntityFramework.Shared/Repository/Sync/UpdateRepository.cs b/src/providers/EntityFramework/Repository/Sync/UpdateRepository.cs similarity index 54% rename from src/providers/EntityFramework.Shared/Repository/Sync/UpdateRepository.cs rename to src/providers/EntityFramework/Repository/Sync/UpdateRepository.cs index 51a68fd..844642b 100644 --- a/src/providers/EntityFramework.Shared/Repository/Sync/UpdateRepository.cs +++ b/src/providers/EntityFramework/Repository/Sync/UpdateRepository.cs @@ -1,35 +1,13 @@ using System.Collections.Generic; - -#if NET461 - -using System.Data.Entity; -using System.Data.Entity.Infrastructure; - -#else - -using Microsoft.EntityFrameworkCore; - -#endif - using System.Linq; +using Microsoft.EntityFrameworkCore; namespace Dime.Repositories { public partial class EfRepository { - /// - /// Updates the entities - /// - /// The entities to update - /// public TEntity Update(TEntity entity) => Update(entity, true); - /// - /// Updates the existing entity. - /// - /// The entity to update - /// Indication whether or not the SaveChanges should be called during this call - /// public virtual TEntity Update(TEntity entity, bool commitChanges = true) { using TContext ctx = Context; @@ -42,12 +20,6 @@ public virtual TEntity Update(TEntity entity, bool commitChanges = true) return entity; } - /// - /// Updates the entities - /// - /// The entities to update - /// Indication whether or not the SaveChanges should be called during this call - /// public void Update(IEnumerable entities, bool commitChanges = true) { if (!entities.Any()) diff --git a/src/providers/EntityFramework.Shared/Utilities/DataReaderExtensions.cs b/src/providers/EntityFramework/Utilities/DataReaderExtensions.cs similarity index 77% rename from src/providers/EntityFramework.Shared/Utilities/DataReaderExtensions.cs rename to src/providers/EntityFramework/Utilities/DataReaderExtensions.cs index 723da74..8bf3a17 100644 --- a/src/providers/EntityFramework.Shared/Utilities/DataReaderExtensions.cs +++ b/src/providers/EntityFramework/Utilities/DataReaderExtensions.cs @@ -7,12 +7,6 @@ namespace Dime.Repositories { internal static class DataReaderExtensions { - /// - /// - /// - /// - /// - /// internal static List GetRecords(this IDataReader reader) { List result = new(); @@ -33,12 +27,6 @@ internal static List GetRecords(this IDataReader reader) return result; } - /// - /// - /// - /// - /// - /// public static bool HasColumn(this IDataRecord dr, string columnName) { for (int i = 0; i < dr.FieldCount; i++) diff --git a/src/providers/EntityFramework.Shared/Utilities/DbContextExtensions.cs b/src/providers/EntityFramework/Utilities/DbContextExtensions.cs similarity index 61% rename from src/providers/EntityFramework.Shared/Utilities/DbContextExtensions.cs rename to src/providers/EntityFramework/Utilities/DbContextExtensions.cs index ba9ed4f..ed86a7c 100644 --- a/src/providers/EntityFramework.Shared/Utilities/DbContextExtensions.cs +++ b/src/providers/EntityFramework/Utilities/DbContextExtensions.cs @@ -1,36 +1,26 @@ using System; - -#if NET461 - -using System.Data.Entity; - -#else - -using Microsoft.EntityFrameworkCore; - -#endif - using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; +using System.Threading.Tasks; using LinqKit; +using Microsoft.EntityFrameworkCore; namespace Dime.Repositories { [ExcludeFromCodeCoverage] internal static class DbContextExtensions { - /// - /// - /// - /// - /// - /// - /// internal static int Count(this DbContext ctx, Expression> query = null) where TEntity : class => query == null ? ctx.Set().AsExpandable().AsNoTracking().Count() : ctx.Set().AsExpandable().AsNoTracking().Count(query); + + internal static Task CountAsync(this DbContext ctx, Expression> query = null) + where TEntity : class + => query == null + ? ctx.Set().AsExpandable().AsNoTracking().CountAsync() + : ctx.Set().AsExpandable().AsNoTracking().CountAsync(query); } } \ No newline at end of file diff --git a/src/providers/EntityFramework.NetCore/Utilities/EFExtensions.cs b/src/providers/EntityFramework/Utilities/EFExtensions.cs similarity index 81% rename from src/providers/EntityFramework.NetCore/Utilities/EFExtensions.cs rename to src/providers/EntityFramework/Utilities/EFExtensions.cs index 11399b4..27d8e5e 100644 --- a/src/providers/EntityFramework.NetCore/Utilities/EFExtensions.cs +++ b/src/providers/EntityFramework/Utilities/EFExtensions.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata; @@ -18,7 +20,7 @@ internal static IQueryable Include(this IQueryable qu return query; List includeList = new(); - if (includes.Any()) + if (includes.Length != 0) return includes .Where(x => !string.IsNullOrEmpty(x) && !includeList.Contains(x)) .Aggregate(query, (current, include) => current.Include(include)); @@ -43,7 +45,7 @@ internal static IQueryable IncludeView(this IQueryabl where TEntity : class where TResult : class { - if (includes != null && includes.Any()) + if (includes != null && includes.Length != 0) return includes.Where(include => include != null) .Aggregate(query, (current, include) => current.Include(context, include)); @@ -51,5 +53,11 @@ internal static IQueryable IncludeView(this IQueryabl .GetNavigations() .Aggregate(query, (current, navigationProperty) => current.Include(context, navigationProperty.Name)); } + + public static Task> ToListAsyncSafe(this IQueryable source) + { + ArgumentNullException.ThrowIfNull(source); + return source is not IAsyncEnumerable ? Task.FromResult(source.ToList()) : source.ToListAsync(); + } } } \ No newline at end of file diff --git a/src/providers/EntityFramework/Utilities/LinqOperationExtensions.cs b/src/providers/EntityFramework/Utilities/LinqOperationExtensions.cs new file mode 100644 index 0000000..dda720a --- /dev/null +++ b/src/providers/EntityFramework/Utilities/LinqOperationExtensions.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Dime.Repositories +{ + [ExcludeFromCodeCoverage] + internal static class OrderLinq + { + internal static IOrderedQueryable OrderDescending(this IEnumerable query, string propertyName) + { + LinqOrderHelper helper = new("OrderByDescending", propertyName); + return helper.GetAsQueryable(query); + } + + internal static IOrderedQueryable Order(this IEnumerable query, string propertyName) + { + LinqOrderHelper helper = new("OrderBy", propertyName); + return helper.GetAsQueryable(query); + } + + internal static IOrderedQueryable ThenBy(this IEnumerable source, string property) + { + LinqOrderHelper helper = new("ThenBy", property); + return helper.GetAsQueryable(source); + } + + internal static IOrderedQueryable ThenByDescending(this IEnumerable source, string property) + { + LinqOrderHelper helper = new("ThenByDescending", property); + return helper.GetAsQueryable(source); + } + } +} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Utilities/LinqOperationHelper.cs b/src/providers/EntityFramework/Utilities/LinqOperationHelper.cs similarity index 97% rename from src/providers/EntityFramework.Shared/Utilities/LinqOperationHelper.cs rename to src/providers/EntityFramework/Utilities/LinqOperationHelper.cs index d00fbc9..15a8b2a 100644 --- a/src/providers/EntityFramework.Shared/Utilities/LinqOperationHelper.cs +++ b/src/providers/EntityFramework/Utilities/LinqOperationHelper.cs @@ -7,7 +7,6 @@ namespace Dime.Repositories { - [Obsolete("In a next release this will be internal. Fetch a utility library instead.", false)] [ExcludeFromCodeCoverage] internal class LinqOrderHelper { diff --git a/src/providers/EntityFramework/Utilities/Query Factory/GroupByQueryFactory.cs b/src/providers/EntityFramework/Utilities/Query Factory/GroupByQueryFactory.cs new file mode 100644 index 0000000..75ac72e --- /dev/null +++ b/src/providers/EntityFramework/Utilities/Query Factory/GroupByQueryFactory.cs @@ -0,0 +1,20 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Linq.Expressions; + +namespace Dime.Repositories +{ + [ExcludeFromCodeCoverage] + internal static partial class QueryFactory + { + public static IQueryable> WithGroup(this IQueryable source, Expression> predicate) + => source.GroupBy(predicate); + + public static IQueryable> WithGroup(this IQueryable source, Func predicate) + => source.GroupBy(predicate).AsQueryable(); + + public static IQueryable> WithGroup(this IOrderedEnumerable source, Func predicate) + => source.GroupBy(predicate).AsQueryable(); + } +} \ No newline at end of file diff --git a/src/providers/EntityFramework/Utilities/Query Factory/SelectQueryFactory.cs b/src/providers/EntityFramework/Utilities/Query Factory/SelectQueryFactory.cs new file mode 100644 index 0000000..d754219 --- /dev/null +++ b/src/providers/EntityFramework/Utilities/Query Factory/SelectQueryFactory.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace Dime.Repositories +{ + internal static partial class QueryFactory + { + internal static IQueryable WithSelect( + this IQueryable> source, + Expression, IEnumerable>> selector) + => selector == null ? default : source.SelectMany(selector); + + internal static IQueryable WithSelect( + this IQueryable> source, + Expression, int, TResult>> selector) + => selector == null ? default : source.Select(selector); + + internal static IQueryable WithSelect(this IOrderedEnumerable source, + Func selector) + where TSource : class + where TResult : class + => selector == null ? default : source.Select(selector).AsQueryable(); + + internal static IQueryable WithSelect(this IQueryable source, + Expression> selector) + where TSource : class + => selector == null ? default : source.Select(selector).AsQueryable(); + + internal static IQueryable WithSelect(this IQueryable source, + Func selector) + where TSource : class + where TResult : class + => selector == null ? default : source.Select(selector).AsQueryable(); + + internal static TResult WithFirstSelect(this TSource source, + Expression> selector) + where TSource : class + where TResult : class + => selector == null + ? default + : new List { source }.AsQueryable().Select(selector).FirstOrDefault(); + } +} \ No newline at end of file diff --git a/src/providers/EntityFramework/Utilities/Query Factory/SkipQueryFactory.cs b/src/providers/EntityFramework/Utilities/Query Factory/SkipQueryFactory.cs new file mode 100644 index 0000000..333407d --- /dev/null +++ b/src/providers/EntityFramework/Utilities/Query Factory/SkipQueryFactory.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace Dime.Repositories +{ + internal static partial class QueryFactory + { + internal static IQueryable With(this IQueryable source, int? page, int? pageSize, IEnumerable> orderBy) + { + int pageToApply = page.GetValueOrDefault(); + int pageSizeToApply = pageSize.GetValueOrDefault(); + + if (pageToApply == 0 || pageSizeToApply == 0) + return source; + + int itemsToSkip = (pageToApply - 1) * pageSizeToApply; + + return orderBy == null + ? source.OrderBy(x => true).Skip(itemsToSkip) + : source.Skip(itemsToSkip); + } + + internal static IQueryable With(this IQueryable source, int? page, int? pageSize, Expression> orderBy) + { + int pageToApply = page.GetValueOrDefault(); + int pageSizeToApply = pageSize.GetValueOrDefault(); + + if (pageToApply == 0 || pageSizeToApply == 0) + return source; + + int itemsToSkip = (pageToApply - 1) * pageSizeToApply; + + return orderBy == null ? + source.OrderBy(x => true).Skip(itemsToSkip) : + source.Skip(itemsToSkip); + } + + internal static IQueryable With(this IQueryable source, int? page, int? pageSize, IEnumerable>> orderBy) + { + int pageToApply = page.GetValueOrDefault(); + int pageSizeToApply = pageSize.GetValueOrDefault(); + + if (pageToApply == 0 || pageSizeToApply == 0) + return source; + + int itemsToSkip = (pageToApply - 1) * pageSizeToApply; + + return orderBy == null ? + source.OrderBy(x => true).Skip(itemsToSkip) : + source.Skip(itemsToSkip); + } + } +} \ No newline at end of file diff --git a/src/providers/EntityFramework.Shared/Utilities/Query Factory/SortingQueryFactory.cs b/src/providers/EntityFramework/Utilities/Query Factory/SortingQueryFactory.cs similarity index 70% rename from src/providers/EntityFramework.Shared/Utilities/Query Factory/SortingQueryFactory.cs rename to src/providers/EntityFramework/Utilities/Query Factory/SortingQueryFactory.cs index 02824fc..fa5421c 100644 --- a/src/providers/EntityFramework.Shared/Utilities/Query Factory/SortingQueryFactory.cs +++ b/src/providers/EntityFramework/Utilities/Query Factory/SortingQueryFactory.cs @@ -5,16 +5,8 @@ namespace Dime.Repositories { - [Obsolete("In a next release this will be internal. Fetch a utility library instead.", false)] internal static partial class QueryFactory { - /// - /// Wrapper around LINQ ORDER BY - /// - /// The type of the source. - /// The source. - /// The order by expression. - /// internal static IQueryable WithOrder(this IQueryable source, IEnumerable> orderByExpression) { if (orderByExpression != null && orderByExpression.Count() > 1) @@ -39,14 +31,6 @@ internal static IQueryable WithOrder(this IQueryable return source.OrderBy(x => true); } - /// - /// Wrapper around LINQ ORDER BY - /// - /// The type of the source. - /// The source. - /// The order by expression. - /// - /// internal static IQueryable WithOrder(this IQueryable source, IEnumerable>> orderByExpression, bool ascending) { if (orderByExpression == null) @@ -70,14 +54,6 @@ internal static IQueryable WithOrder(this IQueryable } } - /// - /// Wrapper around LINQ ORDER BY - /// - /// The type of the source. - /// The source. - /// The order by expression. - /// - /// internal static IQueryable WithOrder(this IQueryable source, Expression> orderByExpression, bool ascending) { if (orderByExpression == null) @@ -88,14 +64,6 @@ internal static IQueryable WithOrder(this IQueryable : source.OrderByDescending(compiledExpression).AsQueryable(); } - /// - /// Wrapper around LINQ ORDER BY - /// - /// The type of the source. - /// The source. - /// The order by expression. - /// - /// internal static IQueryable WithOrder(this IQueryable source, Func orderByExpression, bool ascending) { if (orderByExpression == null) diff --git a/src/providers/EntityFramework/Utilities/Query Factory/TakeQueryFactory.cs b/src/providers/EntityFramework/Utilities/Query Factory/TakeQueryFactory.cs new file mode 100644 index 0000000..726872c --- /dev/null +++ b/src/providers/EntityFramework/Utilities/Query Factory/TakeQueryFactory.cs @@ -0,0 +1,15 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Dime.Repositories +{ + [ExcludeFromCodeCoverage] + internal static class TakeQueryFactory + { + internal static IQueryable With(this IQueryable source, int? takeCount) + { + int itemsToTake = takeCount.GetValueOrDefault(); + return itemsToTake == 0 ? source : source.Take(itemsToTake); + } + } +} \ No newline at end of file diff --git a/src/providers/EntityFramework/Utilities/Query Factory/WhereQueryFactory.cs b/src/providers/EntityFramework/Utilities/Query Factory/WhereQueryFactory.cs new file mode 100644 index 0000000..d17088e --- /dev/null +++ b/src/providers/EntityFramework/Utilities/Query Factory/WhereQueryFactory.cs @@ -0,0 +1,15 @@ +using System; +using System.Linq; +using System.Linq.Expressions; + +namespace Dime.Repositories +{ + internal static partial class QueryFactory + { + internal static IQueryable With(this IQueryable source, Expression> predicate) + => predicate == null ? source : source.Where(predicate); + + internal static TSource WithFirst(this IQueryable source, Expression> predicate) + => predicate == null ? source.FirstOrDefault() : source.FirstOrDefault(predicate); + } +} \ No newline at end of file diff --git a/src/test.runsettings b/src/test.runsettings deleted file mode 100644 index 2c3dbef..0000000 --- a/src/test.runsettings +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - .*\.dll$ - .*\.exe$ - - - .*CPPUnitTestFramework.* - .*moq.dll - .*Tests.dll - - - - - False - True - True - False - - - - - - \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/AggregateRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/AggregateRepositoryTests.cs deleted file mode 100644 index ea065e5..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/AggregateRepositoryTests.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetCore.Tests -{ - public partial class RepositoryTests - { - [TestMethod] - public void Repository_Count_NoPredicate_ShouldCountAll() - { - // In-memory database only exists while the connection is open - using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - // Create the schema in the database - using (BloggingContext context = new(options)) - context.Database.EnsureCreated(); - - // Insert seed data into the database using one instance of the context - using (BloggingContext context = new(options)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using IRepository repo = new EfRepository(new BloggingContext(options)); - long result = repo.Count(); - Assert.AreEqual(3, result); - } - finally - { - connection.Close(); - } - } - - [TestMethod] - public async Task Repository_CountAsync_NoPredicate_ShouldCountAll() - { - // In-memory database only exists while the connection is open - await using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - // Create the schema in the database - await using (BloggingContext context = new(options)) - context.Database.EnsureCreated(); - - // Insert seed data into the database using one instance of the context - await using (BloggingContext context = new(options)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using IRepository repo = new EfRepository(new BloggingContext(options)); - long result = await repo.CountAsync(); - Assert.AreEqual(3, result); - } - finally - { - connection.Close(); - } - } - - [TestMethod] - public async Task Repository_CountAsync_Predicate_ShouldCountCorrectly() - { - // In-memory database only exists while the connection is open - await using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - // Create the schema in the database - await using (BloggingContext context = new(options)) - { - context.Database.EnsureCreated(); - } - - // Insert seed data into the database using one instance of the context - await using (BloggingContext context = new(options)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using IRepository repo = new EfRepository(new BloggingContext(options)); - long result = await repo.CountAsync(x => x.Url.Contains("cat")); - Assert.AreEqual(2, result); - } - finally - { - connection.Close(); - } - } - - [TestMethod] - public void Repository_Count_Predicate_ShouldCountCorrectly() - { - // In-memory database only exists while the connection is open - using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - // Create the schema in the database - using (BloggingContext context = new(options)) - { - context.Database.EnsureCreated(); - } - - // Insert seed data into the database using one instance of the context - using (BloggingContext context = new(options)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using IRepository repo = new EfRepository(new BloggingContext(options)); - long result = repo.Count(x => x.Url.Contains("cat")); - Assert.AreEqual(2, result); - } - finally - { - connection.Close(); - } - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/CreateRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/CreateRepositoryTests.cs deleted file mode 100644 index 3d3afad..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/CreateRepositoryTests.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetCore.Tests -{ - public partial class RepositoryTests - { - [TestMethod] - public void Repository_Create_ShouldAddOne() - { - // In-memory database only exists while the connection is open - using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - // Create the schema in the database - using (BloggingContext context = new(options)) - context.Database.EnsureCreated(); - - // Run the test against one instance of the context - using (IRepository repo = new EfRepository(new BloggingContext(options))) - repo.Create(new Blog { Url = "http://sample.com" }); - - // Use a separate instance of the context to verify correct data was saved to database - using (BloggingContext context = new(options)) - { - Assert.AreEqual(1, context.Blogs.Count()); - Assert.AreEqual("http://sample.com", context.Blogs.Single().Url); - } - } - finally - { - connection.Close(); - } - } - - [TestMethod] - public async Task Repository_CreateAsync_ShouldAddOne() - { - // In-memory database only exists while the connection is open - await using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - // Create the schema in the database - await using (BloggingContext context = new(options)) - context.Database.EnsureCreated(); - - using (IRepository repo = new EfRepository(new BloggingContext(options))) - await repo.CreateAsync(new Blog { Url = "http://sample.com" }); - - // Use a separate instance of the context to verify correct data was saved to database - await using (BloggingContext context = new(options)) - { - Assert.AreEqual(1, context.Blogs.Count()); - Assert.AreEqual("http://sample.com", context.Blogs.Single().Url); - } - } - finally - { - connection.Close(); - } - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/DeleteRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/DeleteRepositoryTests.cs deleted file mode 100644 index 607baca..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/DeleteRepositoryTests.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetCore.Tests -{ - public partial class RepositoryTests - { - [TestMethod] - public void Repository_Delete_ByEntity_ShouldRemoveOne() - { - // In-memory database only exists while the connection is open - using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - using (BloggingContext context = new(options)) - { - context.Database.EnsureCreated(); - - context.Blogs.Add(new Blog { BlogId = 1, Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { BlogId = 2, Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { BlogId = 3, Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using (IRepository repo = new EfRepository(new BloggingContext(options))) - repo.Delete(new Blog { BlogId = 1 }); - - // Use a separate instance of the context to verify correct data was saved to database - using (BloggingContext context = new(options)) - { - Assert.AreEqual(2, context.Blogs.Count()); - } - } - finally - { - connection.Close(); - } - } - - [TestMethod] - public async Task Repository_DeleteAsync_ByEntity_ShouldRemoveOne() - { - // In-memory database only exists while the connection is open - await using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - await using (BloggingContext context = new(options)) - { - context.Database.EnsureCreated(); - - context.Blogs.Add(new Blog { BlogId = 1, Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { BlogId = 2, Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { BlogId = 3, Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using (IRepository repo = new EfRepository(new BloggingContext(options))) - await repo.DeleteAsync(new Blog { BlogId = 1 }); - - // Use a separate instance of the context to verify correct data was saved to database - await using (BloggingContext context = new(options)) - { - Assert.AreEqual(2, context.Blogs.Count()); - } - } - finally - { - connection.Close(); - } - } - - [TestMethod] - public async Task Repository_DeleteAsync_ByIds_ShouldRemoveList() - { - // In-memory database only exists while the connection is open - await using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - await using (BloggingContext context = new(options)) - { - context.Database.EnsureCreated(); - - context.Blogs.Add(new Blog { BlogId = 1, Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { BlogId = 2, Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { BlogId = 3, Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - List ids = new() { 1, 2 }; - using (IRepository repo = new EfRepository(new BloggingContext(options))) - await repo.DeleteAsync(ids); - - // Use a separate instance of the context to verify correct data was saved to database - await using (BloggingContext context = new(options)) - { - Assert.AreEqual(1, context.Blogs.Count()); - } - } - catch (Exception ex) - { - Assert.Fail(ex.Message); - } - finally - { - connection.Close(); - } - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/GetRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/GetRepositoryTests.cs deleted file mode 100644 index 8e891a4..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/GetRepositoryTests.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetCore.Tests -{ - [TestClass] - public partial class RepositoryTests - { - [TestMethod] - public void Repository_FindAll_Contains_ShouldFindMatches() - { - // In-memory database only exists while the connection is open - using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - // Create the schema in the database - using (BloggingContext context = new(options)) - context.Database.EnsureCreated(); - - // Insert seed data into the database using one instance of the context - using (BloggingContext context = new(options)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using IRepository repo = new EfRepository(new BloggingContext(options)); - IEnumerable result = repo.FindAll(x => x.Url.Contains("cat")); - Assert.AreEqual(2, result.Count()); - } - finally - { - connection.Close(); - } - } - - [TestMethod] - public async Task Repository_FindAllAsync_Contains_ShouldFindMatches() - { - // In-memory database only exists while the connection is open - await using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - // Create the schema in the database - await using (BloggingContext context = new(options)) - context.Database.EnsureCreated(); - - // Insert seed data into the database using one instance of the context - await using (BloggingContext context = new(options)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using IRepository repo = new EfRepository(new BloggingContext(options)); - IEnumerable result = await repo.FindAllAsync(x => x.Url.Contains("cat")); - Assert.AreEqual(2, result.Count()); - } - finally - { - connection.Close(); - } - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/UpdateRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/UpdateRepositoryTests.cs deleted file mode 100644 index 7f06095..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/UpdateRepositoryTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetCore.Tests -{ - public partial class RepositoryTests - { - [TestMethod] - public void Repository_Update_ByEntity_ShouldRemoveOne() - { - // In-memory database only exists while the connection is open - using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - using (BloggingContext context = new(options)) - { - context.Database.EnsureCreated(); - - context.Blogs.Add(new Blog { BlogId = 1, Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { BlogId = 2, Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { BlogId = 3, Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using (IRepository repo = new EfRepository(new BloggingContext(options))) - repo.Update(new Blog { BlogId = 1, Url = "http://sample.com/zebras" }); - - // Use a separate instance of the context to verify correct data was saved to database - using (BloggingContext context = new(options)) - { - Blog blog = context.Blogs.Find(1); - Assert.IsTrue(blog.Url == "http://sample.com/zebras"); - } - } - finally - { - connection.Close(); - } - } - - [TestMethod] - public async Task Repository_UpdateAsync_ByEntity_ShouldRemoveOne() - { - // In-memory database only exists while the connection is open - await using SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - DbContextOptions options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - await using (BloggingContext context = new(options)) - { - context.Database.EnsureCreated(); - - context.Blogs.Add(new Blog { BlogId = 1, Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { BlogId = 2, Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { BlogId = 3, Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using (IRepository repo = new EfRepository(new BloggingContext(options))) - await repo.UpdateAsync(new Blog { BlogId = 1, Url = "http://sample.com/zebras" }); - - // Use a separate instance of the context to verify correct data was saved to database - await using (BloggingContext context = new(options)) - { - Blog blog = await context.Blogs.FindAsync(1); - Assert.IsTrue(blog.Url == "http://sample.com/zebras"); - } - } - finally - { - connection.Close(); - } - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/AggregateRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/AggregateRepositoryTests.cs deleted file mode 100644 index 761bf64..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/AggregateRepositoryTests.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Threading.Tasks; -using Effort.Provider; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetFramework.Tests -{ - public partial class RepositoryTests - { - [TestMethod] - public void Repository_Count_NoPredicate_ShouldCountAll() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - IRepository repo = new EfRepository(new BloggingContext(connection)); - long result = repo.Count(); - Assert.AreEqual(3, result); - } - - [TestMethod] - public async Task Repository_CountAsync_NoPredicate_ShouldCountAll() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - IRepository repo = new EfRepository(new BloggingContext(connection)); - long result = await repo.CountAsync(); - Assert.AreEqual(3, result); - } - - [TestMethod] - public async Task Repository_CountAsync_Predicate_ShouldCountCorrectly() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - IRepository repo = new EfRepository(new BloggingContext(connection)); - long result = await repo.CountAsync(x => x.Url.Contains("cat")); - Assert.AreEqual(2, result); - } - - [TestMethod] - public void Repository_Count_Predicate_ShouldCountCorrectly() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using IRepository repo = new EfRepository(new BloggingContext(connection)); - long result = repo.Count(x => x.Url.Contains("cat")); - Assert.AreEqual(2, result); - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/BloggingContext.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/BloggingContext.cs deleted file mode 100644 index 7daff68..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/BloggingContext.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Generic; -using System.Data.Common; -using System.Data.Entity; - -namespace Dime.Repositories.Sql.EntityFramework.NetFramework.Tests -{ - public class BloggingContext : DbContext - { - public BloggingContext() - { - } - - public BloggingContext(DbConnection connection) : base(connection, true) - { - } - - public DbSet Blogs { get; set; } - public DbSet Posts { get; set; } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - modelBuilder.Entity().HasKey(c => c.Id); - - modelBuilder.Entity().HasKey(c => c.BlogId); - modelBuilder.Entity().HasOptional(c => c.Category); - - base.OnModelCreating(modelBuilder); - } - } - - public class Blog - { - public int BlogId { get; set; } - public string Url { get; set; } - public Category Category { get; set; } - public List Posts { get; set; } - } - - public class Category - { - public int Id { get; set; } - public string Name { get; set; } - } - - public class Post - { - public int PostId { get; set; } - public string Title { get; set; } - public string Content { get; set; } - - public int BlogId { get; set; } - public Blog Blog { get; set; } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/CreateRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/CreateRepositoryTests.cs deleted file mode 100644 index 9f9cf61..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/CreateRepositoryTests.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using Effort.Provider; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetFramework.Tests -{ - public partial class RepositoryTests - { - [TestMethod] - public void Repository_Create_ShouldAddOne() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (IRepository repo = new EfRepository(new BloggingContext(connection))) - repo.Create(new Blog { Url = "http://sample.com" }); - - using BloggingContext context = new(connection); - Assert.AreEqual(1, context.Blogs.Count()); - Assert.AreEqual("http://sample.com", context.Blogs.Single().Url); - } - - [TestMethod] - public async Task Repository_CreateAsync_ShouldAddOne() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (IRepository repo = new EfRepository(new BloggingContext(connection))) - await repo.CreateAsync(new Blog { Url = "http://sample.com" }); - - // Use a separate instance of the context to verify correct data was saved to database - using BloggingContext context = new(connection); - Assert.AreEqual(1, context.Blogs.Count()); - Assert.AreEqual("http://sample.com", context.Blogs.Single().Url); - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/DeleteRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/DeleteRepositoryTests.cs deleted file mode 100644 index a0878d4..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/DeleteRepositoryTests.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using Effort.Provider; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetFramework.Tests -{ - public partial class RepositoryTests - { - [TestMethod] - public void Repository_Delete_ByEntity_ShouldRemoveOne() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { BlogId = 1, Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { BlogId = 2, Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { BlogId = 3, Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using (IRepository repo = new EfRepository(new BloggingContext(connection))) - repo.Delete(new Blog { BlogId = 1 }); - - // Use a separate instance of the context to verify correct data was saved to database - using (BloggingContext context = new(connection)) - { - Assert.AreEqual(2, context.Blogs.Count()); - } - } - - [TestMethod] - public async Task Repository_DeleteAsync_ByEntity_ShouldRemoveOne() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { BlogId = 1, Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { BlogId = 2, Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { BlogId = 3, Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using (IRepository repo = new EfRepository(new BloggingContext(connection))) - await repo.DeleteAsync(new Blog { BlogId = 1 }); - - // Use a separate instance of the context to verify correct data was saved to database - using (BloggingContext context = new(connection)) - { - Assert.AreEqual(2, context.Blogs.Count()); - } - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests.csproj b/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests.csproj deleted file mode 100644 index 38358ef..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - {719B5ACC-8EA5-47B7-A8DA-B54A47E5ACA4} - net461 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - False - UnitTest - false - latest - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/GetRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/GetRepositoryTests.cs deleted file mode 100644 index 1853f96..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/GetRepositoryTests.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; -using Effort.Provider; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetFramework.Tests -{ - [TestClass] - public partial class RepositoryTests - { - [TestMethod] - public void Repository_FindAll_Contains_ShouldFindMatches() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - IRepository repo = new EfRepository(new BloggingContext(connection), new RepositoryConfiguration()); - IEnumerable result = repo.FindAll(x => x.Url.Contains("cat")); - Assert.AreEqual(2, result.Count()); - } - - [TestMethod] - public async Task Repository_FindAllAsync_Contains_ShouldFindMatches() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - await context.SaveChangesAsync(); - } - - IRepository repo = new EfRepository(new BloggingContext(connection), new RepositoryConfiguration()); - IEnumerable result = await repo.FindAllAsync(x => x.Url.Contains("cat")); - Assert.AreEqual(2, result.Count()); - } - - [TestMethod] - public async Task Repository_FindAllAsync_ShouldFindMatches() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats", Category = new() { Name = "Pets" } }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish", Category = new() { Name = "Pets" } }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs", Category = new() { Name = "Pets" } }); - await context.SaveChangesAsync(); - } - - IRepository repo = new EfRepository(new BloggingContext(connection), new RepositoryConfiguration()); - - Expression>[] includes = { x => x.Category, x => x.Category.Name }; - IEnumerable result = await repo.FindAllAsync( - where: x => x.Url.Contains("cat"), - orderBy: null, - ascending: false, - includes: includes.ToPropertyExpression()); - Assert.AreEqual(2, result.Count()); - } - } - - internal static class EfIncludesExtensions - { - public static string[] ToPropertyExpression(this Expression>[] items) - => items != null && items.Any() ? items.Where(x => x != null).Select(x => x.GetPropertyName()).ToArray() : null; - - public static string[] ToPropertyExpression(this Expression>[] includes, Expression> select = null) - => includes != null && select == null && includes.Any() ? includes.Select(x => x.GetPropertyName()).ToArray() : null; - - public static string[] ToPropertyExpression(this string[] includes) - => includes != null && includes.Any() ? includes.ToArray() : null; - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/PagedQueryRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/PagedQueryRepositoryTests.cs deleted file mode 100644 index 565b633..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/PagedQueryRepositoryTests.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using Effort.Provider; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetFramework.Tests -{ - [TestClass] - public class PagedQueryRepositoryTests - { - [TestMethod] - public async Task Repository_FindPagedAsync_Contains_ShouldFindMatches() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/2" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/3" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/4" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/5" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/6" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/7" }); - context.Blogs.Add(new Blog { Url = "http://sample.com/8" }); - - await context.SaveChangesAsync(); - } - - IRepository repo = new EfRepository(new BloggingContext(connection), new RepositoryConfiguration()); - IPage result = await repo.FindAllPagedAsync( - where: x => x.Url.Contains("cat"), - orderBy: null, - count: null, - page: 1, - pageSize: 5, - includes: null); - - Assert.AreEqual(2, result.Data.Count()); - Assert.AreEqual(10, result.Total); - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/UpdateRepositoryTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/UpdateRepositoryTests.cs deleted file mode 100644 index eb4f828..0000000 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetFramework.Tests/UpdateRepositoryTests.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Threading.Tasks; -using Effort.Provider; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Dime.Repositories.Sql.EntityFramework.NetFramework.Tests -{ - public partial class RepositoryTests - { - [TestMethod] - public void Repository_Update_ByEntity_ShouldRemoveOne() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { BlogId = 1, Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { BlogId = 2, Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { BlogId = 3, Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using (IRepository repo = new EfRepository(new BloggingContext(connection))) - repo.Update(new Blog { BlogId = 1, Url = "http://sample.com/zebras" }); - - // Use a separate instance of the context to verify correct data was saved to database - using (BloggingContext context = new(connection)) - { - Blog blog = context.Blogs.Find(1); - Assert.IsTrue(blog.Url == "http://sample.com/zebras"); - } - } - - [TestMethod] - public async Task Repository_UpdateAsync_ByEntity_ShouldRemoveOne() - { - EffortConnection connection = Effort.DbConnectionFactory.CreateTransient(); - - using (BloggingContext context = new(connection)) - { - context.Blogs.Add(new Blog { BlogId = 1, Url = "http://sample.com/cats" }); - context.Blogs.Add(new Blog { BlogId = 2, Url = "http://sample.com/catfish" }); - context.Blogs.Add(new Blog { BlogId = 3, Url = "http://sample.com/dogs" }); - context.SaveChanges(); - } - - using (IRepository repo = new EfRepository(new BloggingContext(connection))) - await repo.UpdateAsync(new Blog { BlogId = 1, Url = "http://sample.com/zebras" }); - - // Use a separate instance of the context to verify correct data was saved to database - using (BloggingContext context = new(connection)) - { - Blog blog = await context.Blogs.FindAsync(1); - Assert.IsTrue(blog.Url == "http://sample.com/zebras"); - } - } - } -} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CountAsyncTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CountAsyncTests.cs new file mode 100644 index 0000000..7ea3e0f --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CountAsyncTests.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class CountAsyncTests + { + [TestMethod] + public async Task CountAsync_NoPredicate_ShouldCountAll() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + long result = await repo.CountAsync(); + Assert.AreEqual(3, result); + } + + [TestMethod] + public async Task CountAsync_Predicate_ShouldCountCorrectly() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + long result = await repo.CountAsync(x => x.Url.Contains("cat")); + Assert.AreEqual(2, result); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CountTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CountTests.cs new file mode 100644 index 0000000..069b5dc --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CountTests.cs @@ -0,0 +1,28 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class CountTests + { + [TestMethod] + public void Count_NoPredicate_ShouldCountAll() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + long result = repo.Count(); + Assert.AreEqual(3, result); + } + + [TestMethod] + public void Count_Predicate_ShouldCountCorrectly() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + long result = repo.Count(x => x.Url.Contains("cat")); + Assert.AreEqual(2, result); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CreateAsyncTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CreateAsyncTests.cs new file mode 100644 index 0000000..8ad5f5f --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CreateAsyncTests.cs @@ -0,0 +1,39 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class CreateAsyncTests + { + [TestMethod] + public void Create_ShouldAddOne() + { + using TestDatabase testDb = new(); + + // Run the test against one instance of the context + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + repo.Create(new Blog { Url = "http://sample.com" }); + + // Use a separate instance of the context to verify correct data was saved to database + using BloggingContext context = new(testDb.Options); + Assert.AreEqual(4, context.Blogs.Count()); + Assert.AreEqual("http://sample.com", context.Blogs.OrderByDescending(x => x.BlogId).First().Url); + } + + [TestMethod] + public async Task CreateAsync_ShouldAddOne() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + await repo.CreateAsync(new Blog { Url = "http://sample.com" }); + + // Use a separate instance of the context to verify correct data was saved to database + await using BloggingContext context = new(testDb.Options); + Assert.AreEqual(4, context.Blogs.Count()); + Assert.AreEqual("http://sample.com", context.Blogs.OrderByDescending(x => x.BlogId).First().Url); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CreateTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CreateTests.cs new file mode 100644 index 0000000..91ab750 --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/CreateTests.cs @@ -0,0 +1,39 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class CreateTests + { + [TestMethod] + public void Create_ShouldAddOne() + { + using TestDatabase testDb = new(); + + // Run the test against one instance of the context + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + repo.Create(new Blog { Url = "http://sample.com" }); + + // Use a separate instance of the context to verify correct data was saved to database + using BloggingContext context = new(testDb.Options); + Assert.AreEqual(4, context.Blogs.Count()); + Assert.AreEqual("http://sample.com", context.Blogs.OrderByDescending(x => x.BlogId).First().Url); + } + + [TestMethod] + public async Task CreateAsync_ShouldAddOne() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + await repo.CreateAsync(new Blog { Url = "http://sample.com" }); + + // Use a separate instance of the context to verify correct data was saved to database + await using BloggingContext context = new(testDb.Options); + Assert.AreEqual(4, context.Blogs.Count()); + Assert.AreEqual("http://sample.com", context.Blogs.OrderByDescending(x => x.BlogId).First().Url); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/DeleteAsyncTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/DeleteAsyncTests.cs new file mode 100644 index 0000000..3824a6f --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/DeleteAsyncTests.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class DeleteAsyncTests + { + [TestMethod] + public async Task DeleteAsync_ByEntity_ShouldRemoveOne() + { + using TestDatabase testDb = new(); + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + await repo.DeleteAsync(new Blog { BlogId = 1 }); + + // Use a separate instance of the context to verify correct data was saved to database + await using BloggingContext context = new(testDb.Options); + Assert.AreEqual(2, context.Blogs.Count()); + } + + [TestMethod] + public async Task DeleteAsync_ByIds_ShouldRemoveList() + { + using TestDatabase testDb = new(); + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + + List ids = new() { 1, 2 }; + await repo.DeleteAsync(ids); + + // Use a separate instance of the context to verify correct data was saved to database + await using BloggingContext context = new(testDb.Options); + Assert.AreEqual(1, context.Blogs.Count()); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/DeleteTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/DeleteTests.cs new file mode 100644 index 0000000..145a506 --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/DeleteTests.cs @@ -0,0 +1,22 @@ +using System; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class DeleteTests + { + [TestMethod] + public void Delete_ByEntity_ShouldRemoveOne() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + repo.Delete(new Blog { BlogId = 1 }); + + using BloggingContext context = new(testDb.Options); + Assert.AreEqual(2, context.Blogs.Count()); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/Dime.Repositories.Sql.EntityFramework.NetCore.Tests.csproj b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/Dime.Repositories.Sql.EntityFramework.Tests.csproj similarity index 50% rename from src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/Dime.Repositories.Sql.EntityFramework.NetCore.Tests.csproj rename to src/test/Dime.Repositories.Sql.EntityFramework.Tests/Dime.Repositories.Sql.EntityFramework.Tests.csproj index c972154..5b198f3 100644 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/Dime.Repositories.Sql.EntityFramework.NetCore.Tests.csproj +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/Dime.Repositories.Sql.EntityFramework.Tests.csproj @@ -1,21 +1,20 @@  - net7.0 + net8.0 false - - - - - + + + + - + diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/GetAsyncTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/GetAsyncTests.cs new file mode 100644 index 0000000..f6f8e91 --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/GetAsyncTests.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class GetAsyncTests + { + [TestMethod] + public async Task FindAllAsync_Contains_ShouldFindMatches() + { + using TestDatabase testDb = new(); + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + IEnumerable result = await repo.FindAllAsync(x => x.Url.Contains("cat")); + Assert.AreEqual(2, result.Count()); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/GetTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/GetTests.cs new file mode 100644 index 0000000..c0d6f25 --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/GetTests.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class GetTests + { + [TestMethod] + public void FindAll_Contains_ShouldFindMatches() + { + using TestDatabase testDb = new(); + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + IEnumerable result = repo.FindAll(x => x.Url.Contains("cat")); + Assert.AreEqual(2, result.Count()); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/BloggingContext.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/Helpers/BloggingContext.cs similarity index 94% rename from src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/BloggingContext.cs rename to src/test/Dime.Repositories.Sql.EntityFramework.Tests/Helpers/BloggingContext.cs index 1a3a6c5..f866479 100644 --- a/src/test/Dime.Repositories.Sql.EntityFramework.NetCore.Tests/BloggingContext.cs +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/Helpers/BloggingContext.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; using Microsoft.EntityFrameworkCore; -namespace Dime.Repositories.Sql.EntityFramework.NetCore.Tests +namespace Dime.Repositories.Sql.EntityFramework.Tests { + public class BloggingContext : DbContext { public BloggingContext() diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/Helpers/TestDatabase.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/Helpers/TestDatabase.cs new file mode 100644 index 0000000..166ec1a --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/Helpers/TestDatabase.cs @@ -0,0 +1,45 @@ +using System; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + internal class TestDatabase : IDisposable + { + internal TestDatabase() + { + // In-memory database only exists while the connection is open + Connection = new("DataSource=:memory:"); + Connection.Open(); + + Options = new DbContextOptionsBuilder().UseSqlite(Connection).Options; + + CreateDatabase(); + } + + internal SqliteConnection Connection { get; private set; } + + internal DbContextOptions Options { get; private set; } + + internal void CreateDatabase() + { + // Create the schema in the database + using (BloggingContext context = new(Options)) + context.Database.EnsureCreated(); + + // Insert seed data into the database using one instance of the context + using (BloggingContext context = new(Options)) + { + context.Blogs.Add(new Blog { Url = "http://sample.com/cats" }); + context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" }); + context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" }); + context.SaveChanges(); + } + } + + public void Dispose() + { + Connection.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/PagedAsyncTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/PagedAsyncTests.cs new file mode 100644 index 0000000..ce50974 --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/PagedAsyncTests.cs @@ -0,0 +1,30 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class PagedAsyncTests + { + [TestMethod] + public async Task FindAllPagedAsync_All_ShouldFindMatches() + { + using TestDatabase testDb = new(); + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + IPage result = await repo.FindAllPagedAsync(null, null, 1, 2); + Assert.AreEqual(3, result.Total); + Assert.AreEqual(2, result.Data.Count()); + } + + [TestMethod] + public async Task FindAllPagedAsync_Contains_ShouldFindMatches() + { + using TestDatabase testDb = new(); + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + IPage result = await repo.FindAllPagedAsync(x => x.Url.Contains("cat"), null, 1, 1); + Assert.AreEqual(2, result.Total); + Assert.AreEqual(1, result.Data.Count()); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/UpdateAsyncTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/UpdateAsyncTests.cs new file mode 100644 index 0000000..8ba45e1 --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/UpdateAsyncTests.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class UpdateAsyncTests + { + [TestMethod] + public async Task UpdateAsync_ByEntity_ShouldRemoveOne() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + await repo.UpdateAsync(new Blog { BlogId = 1, Url = "http://sample.com/zebras" }); + + // Use a separate instance of the context to verify correct data was saved to database + await using BloggingContext context = new(testDb.Options); + Blog blog = await context.Blogs.FindAsync(1); + Assert.IsTrue(blog.Url == "http://sample.com/zebras"); + } + + [TestMethod] + public async Task UpdateAsync_Collection_ShouldUpdateAll() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + await repo.UpdateAsync(new Blog { BlogId = 1, Url = "http://sample.com/zebras" }); + await repo.UpdateAsync(new Blog { BlogId = 2, Url = "http://sample.com/lions" }); + + // Use a separate instance of the context to verify correct data was saved to database + await using BloggingContext context = new(testDb.Options); + Blog blog1 = await context.Blogs.FindAsync(1); + Assert.IsTrue(blog1.Url == "http://sample.com/zebras"); + + Blog blog2 = await context.Blogs.FindAsync(2); + Assert.IsTrue(blog2.Url == "http://sample.com/lions"); + } + } +} \ No newline at end of file diff --git a/src/test/Dime.Repositories.Sql.EntityFramework.Tests/UpdateTests.cs b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/UpdateTests.cs new file mode 100644 index 0000000..ced76fb --- /dev/null +++ b/src/test/Dime.Repositories.Sql.EntityFramework.Tests/UpdateTests.cs @@ -0,0 +1,51 @@ +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Dime.Repositories.Sql.EntityFramework.Tests +{ + [TestClass] + public partial class UpdateTests + { + [TestMethod] + public void Update_ByEntity_ShouldRemoveOne() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + repo.Update(new Blog { BlogId = 1, Url = "http://sample.com/zebras" }); + + // Use a separate instance of the context to verify correct data was saved to database + using BloggingContext context = new(testDb.Options); + Blog blog = context.Blogs.Find(1); + Assert.IsTrue(blog.Url == "http://sample.com/zebras"); + } + + [TestMethod] + public void Update_ByEntity_Commit_ShouldRemoveOne() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + repo.Update(new Blog { BlogId = 1, Url = "http://sample.com/zebras" }, true); + + // Use a separate instance of the context to verify correct data was saved to database + using BloggingContext context = new(testDb.Options); + Blog blog = context.Blogs.Find(1); + Assert.IsTrue(blog.Url == "http://sample.com/zebras"); + } + + [TestMethod] + public void Update_ByEntity_DoNotCommit_ShouldRemoveOne() + { + using TestDatabase testDb = new(); + + using IRepository repo = new EfRepository(new BloggingContext(testDb.Options)); + repo.Update(new Blog { BlogId = 1, Url = "http://sample.com/zebras" }, false); + + // Use a separate instance of the context to verify correct data was saved to database + using BloggingContext context = new(testDb.Options); + Blog blog = context.Blogs.Find(1); + Assert.IsTrue(blog.Url == "http://sample.com/cats"); + } + } +} \ No newline at end of file