diff --git a/.cr/personal/FavoritesList/List.xml b/.cr/personal/FavoritesList/List.xml new file mode 100644 index 0000000..a60e5ed --- /dev/null +++ b/.cr/personal/FavoritesList/List.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index 6a3747f..7ec8fd2 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -21,3 +21,4 @@ jobs: run: dotnet restore - name: Build run: dotnet build --configuration Release + diff --git a/README.md b/README.md index 8a86642..45015fb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ +[![time tracker](https://wakatime.com/badge/github/AIKICo/UnitOfWork.svg)](https://wakatime.com/badge/github/AIKICo/UnitOfWork) # UnitOfWork A plugin for Microsoft.EntityFrameworkCore to support repository, unit of work patterns, and multiple database with distributed transaction supported. diff --git a/UnitOfWork.sln b/UnitOfWork.sln index 15b7ef1..9781ae6 100644 --- a/UnitOfWork.sln +++ b/UnitOfWork.sln @@ -16,10 +16,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9661 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitOfWork", "src\UnitOfWork\UnitOfWork.csproj", "{FD8010C2-982B-470E-A9A5-C0DFA2D14809}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitOfWork.Tests", "test\UnitOfWork.Tests\UnitOfWork.Tests.csproj", "{FDAA4086-21E8-4939-8539-0A1723EC4922}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitOfWork.Host", "samples\UnitOfWork.Host\UnitOfWork.Host.csproj", "{207188FE-2344-4DC1-8656-E02CEF741422}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -30,22 +26,12 @@ Global {FD8010C2-982B-470E-A9A5-C0DFA2D14809}.Debug|Any CPU.Build.0 = Debug|Any CPU {FD8010C2-982B-470E-A9A5-C0DFA2D14809}.Release|Any CPU.ActiveCfg = Release|Any CPU {FD8010C2-982B-470E-A9A5-C0DFA2D14809}.Release|Any CPU.Build.0 = Release|Any CPU - {FDAA4086-21E8-4939-8539-0A1723EC4922}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FDAA4086-21E8-4939-8539-0A1723EC4922}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FDAA4086-21E8-4939-8539-0A1723EC4922}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FDAA4086-21E8-4939-8539-0A1723EC4922}.Release|Any CPU.Build.0 = Release|Any CPU - {207188FE-2344-4DC1-8656-E02CEF741422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {207188FE-2344-4DC1-8656-E02CEF741422}.Debug|Any CPU.Build.0 = Debug|Any CPU - {207188FE-2344-4DC1-8656-E02CEF741422}.Release|Any CPU.ActiveCfg = Release|Any CPU - {207188FE-2344-4DC1-8656-E02CEF741422}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {FD8010C2-982B-470E-A9A5-C0DFA2D14809} = {14F86AF9-D2C9-468D-8C71-9BC4785F68A0} - {FDAA4086-21E8-4939-8539-0A1723EC4922} = {D3C7F3F5-4AB2-4868-8D2C-516DFCFDC349} - {207188FE-2344-4DC1-8656-E02CEF741422} = {9661083F-4BCD-42D4-9EF8-1187DD9EDA60} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A7B21B30-8D65-449B-B192-64726743EFC3} diff --git a/samples/UnitOfWork.Host/Controllers/ValuesController.cs b/samples/UnitOfWork.Host/Controllers/ValuesController.cs index 5fcfe36..5ddff48 100644 --- a/samples/UnitOfWork.Host/Controllers/ValuesController.cs +++ b/samples/UnitOfWork.Host/Controllers/ValuesController.cs @@ -6,6 +6,7 @@ using Arch.EntityFrameworkCore.UnitOfWork.Host.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using UnitOfWork.Host.Models; namespace Arch.EntityFrameworkCore.UnitOfWork.Host.Controllers { diff --git a/samples/UnitOfWork.Host/Models/BlogggingContext.cs b/samples/UnitOfWork.Host/Models/BlogggingContext.cs index 1099928..caa208c 100644 --- a/samples/UnitOfWork.Host/Models/BlogggingContext.cs +++ b/samples/UnitOfWork.Host/Models/BlogggingContext.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Microsoft.EntityFrameworkCore; -namespace Arch.EntityFrameworkCore.UnitOfWork.Host.Models +namespace UnitOfWork.Host.Models { public class BloggingContext : DbContext { @@ -12,10 +12,7 @@ public BloggingContext(DbContextOptions options) public DbSet Blogs { get; set; } public DbSet Posts { get; set; } - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.EnableAutoHistory(null); - } + protected override void OnModelCreating(ModelBuilder modelBuilder) => modelBuilder.EnableAutoHistory(null); } public class Blog diff --git a/samples/UnitOfWork.Host/Models/CustomBlogRepository.cs b/samples/UnitOfWork.Host/Models/CustomBlogRepository.cs index c706628..6b171e6 100644 --- a/samples/UnitOfWork.Host/Models/CustomBlogRepository.cs +++ b/samples/UnitOfWork.Host/Models/CustomBlogRepository.cs @@ -1,4 +1,6 @@ -namespace Arch.EntityFrameworkCore.UnitOfWork.Host.Models +using UnitOfWork.Host.Models; + +namespace Arch.EntityFrameworkCore.UnitOfWork.Host.Models { public class CustomBlogRepository : Repository, IRepository { diff --git a/samples/UnitOfWork.Host/Startup.cs b/samples/UnitOfWork.Host/Startup.cs index b706c5d..661ce9c 100644 --- a/samples/UnitOfWork.Host/Startup.cs +++ b/samples/UnitOfWork.Host/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Hosting; +using UnitOfWork.Host.Models; namespace Arch.EntityFrameworkCore.UnitOfWork.Host { diff --git a/samples/UnitOfWork.Host/UnitOfWork.Host.csproj b/samples/UnitOfWork.Host/UnitOfWork.Host.csproj index 3d001d5..b2605a6 100644 --- a/samples/UnitOfWork.Host/UnitOfWork.Host.csproj +++ b/samples/UnitOfWork.Host/UnitOfWork.Host.csproj @@ -3,12 +3,14 @@ netcoreapp3.1 true Exe + false + diff --git a/src/UnitOfWork/IRepository.cs b/src/UnitOfWork/IRepository.cs index a31fef2..fe93c07 100644 --- a/src/UnitOfWork/IRepository.cs +++ b/src/UnitOfWork/IRepository.cs @@ -52,6 +52,40 @@ IPagedList GetPagedList(Expression> predicate = nul bool disableTracking = true, bool ignoreQueryFilters = false); + /// + /// Gets all entities. This method is not recommended + /// + /// The selector for projection. + /// A function to test each element for a condition. + /// A function to order elements. + /// A function to include navigation properties + /// true to disable changing tracking; otherwise, false. Default to true. + /// Ignore query filters + /// An that contains elements that satisfy the condition specified by . + /// Ex: This method defaults to a read-only, no-tracking query. + IQueryable GetAll(Expression> selector, + Expression> predicate = null, + Func, IOrderedQueryable> orderBy = null, + Func, IIncludableQueryable> include = null, bool disableTracking = true, bool ignoreQueryFilters = false); + + /// + /// Gets all entities. This method is not recommended + /// + /// The selector for projection. + /// A function to test each element for a condition. + /// A function to order elements. + /// A function to include navigation properties + /// true to disable changing tracking; otherwise, false. Default to true. + /// Ignore query filters + /// An that contains elements that satisfy the condition specified by . + /// Ex: This method defaults to a read-only, no-tracking query. + Task> GetAllAsync(Expression> selector, + Expression> predicate = null, + Func, IOrderedQueryable> orderBy = null, + Func, IIncludableQueryable> include = null, + bool disableTracking = true, + bool ignoreQueryFilters = false); + /// /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query. /// @@ -244,24 +278,6 @@ IQueryable GetAll(Expression> predicate = null, bool disableTracking = true, bool ignoreQueryFilters = false); - /// - /// Gets all entities. This method is not recommended - /// - /// The selector for projection. - /// A function to test each element for a condition. - /// A function to order elements. - /// A function to include navigation properties - /// true to disable changing tracking; otherwise, false. Default to true. - /// Ignore query filters - /// An that contains elements that satisfy the condition specified by . - /// Ex: This method defaults to a read-only, no-tracking query. - IQueryable GetAll(Expression> selector, - Expression> predicate = null, - Func, IOrderedQueryable> orderBy = null, - Func, IIncludableQueryable> include = null, - bool disableTracking = true, - bool ignoreQueryFilters = false); - /// /// Gets all entities. This method is not recommended /// @@ -284,128 +300,124 @@ Task> GetAllAsync(Expression> predicate = nul bool disableTracking = true, bool ignoreQueryFilters = false); - /// - /// Gets all entities. This method is not recommended - /// - /// The selector for projection. - /// A function to test each element for a condition. - /// A function to order elements. - /// A function to include navigation properties - /// true to disable changing tracking; otherwise, false. Default to true. - /// Ignore query filters - /// An that contains elements that satisfy the condition specified by . - /// Ex: This method defaults to a read-only, no-tracking query. - Task> GetAllAsync(Expression> selector, - Expression> predicate = null, - Func, IOrderedQueryable> orderBy = null, - Func, IIncludableQueryable> include = null, - bool disableTracking = true, - bool ignoreQueryFilters = false); - /// /// Gets the count based on a predicate. /// /// + /// /// - int Count(Expression> predicate = null); + int Count(Expression> predicate = null, bool ignoreQueryFilters = false); /// /// Gets async the count based on a predicate. /// /// + /// /// - Task CountAsync(Expression> predicate = null); + Task CountAsync(Expression> predicate = null, bool ignoreQueryFilters = false); /// /// Gets the long count based on a predicate. /// /// + /// /// - long LongCount(Expression> predicate = null); + long LongCount(Expression> predicate = null, bool ignoreQueryFilters = false); /// /// Gets async the long count based on a predicate. /// /// + /// /// - Task LongCountAsync(Expression> predicate = null); + Task LongCountAsync(Expression> predicate = null, bool ignoreQueryFilters = false); /// /// Gets the max based on a predicate. /// /// /// /// + /// /// decimal - T Max(Expression> predicate = null, Expression> selector = null); + T Max(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false); /// /// Gets the async max based on a predicate. /// /// /// /// + /// /// decimal - Task MaxAsync(Expression> predicate = null, Expression> selector = null); + Task MaxAsync(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false); /// /// Gets the min based on a predicate. /// /// /// + /// /// decimal - T Min(Expression> predicate = null, Expression> selector = null); + T Min(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false); /// /// Gets the async min based on a predicate. /// /// /// + /// /// decimal - Task MinAsync(Expression> predicate = null, Expression> selector = null); + Task MinAsync(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false); /// /// Gets the average based on a predicate. /// /// /// /// + /// /// decimal - decimal Average (Expression> predicate = null, Expression> selector = null); + decimal Average (Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false); /// - /// Gets the async average based on a predicate. - /// - /// - /// /// - /// decimal - Task AverageAsync(Expression> predicate = null, Expression> selector = null); + /// Gets the async average based on a predicate. + /// + /// + /// /// + /// + /// decimal + Task AverageAsync(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false); /// /// Gets the sum based on a predicate. /// /// /// /// + /// /// decimal - decimal Sum (Expression> predicate = null, Expression> selector = null); + decimal Sum (Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false); /// /// Gets the async sum based on a predicate. /// /// /// /// + /// /// decimal - Task SumAsync (Expression> predicate = null, Expression> selector = null); + Task SumAsync (Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false); /// /// Gets the Exists record based on a predicate. /// /// + /// /// - bool Exists(Expression> selector = null); + bool Exists(Expression> selector = null, bool ignoreQueryFilters = false); /// /// Gets the Async Exists record based on a predicate. /// /// + /// /// - Task ExistsAsync(Expression> selector = null); + Task ExistsAsync(Expression> selector = null, bool ignoreQueryFilters = false); /// /// Inserts a new entity synchronously. @@ -490,6 +502,28 @@ Task> GetAllAsync(Expression> sel /// The entities. void Delete(IEnumerable entities); + /// + /// Bulk Delete the specified entity. + /// + void BulkDelete(); + + /// + /// ASync Bulk Delete the specified entity. + /// + Task BulkDeleteAsync(); + + /// + /// Bulk Update the specified entity. + /// the entity property + /// + void BulkUpdate(Expression, SetPropertyCalls>> setPropertyCalls); + + /// + /// Async Bulk Update the specified entity. + /// the entity property + /// + Task BulkUpdateAsync(Expression, SetPropertyCalls>> setPropertyCalls); + /// /// Change entity state for patch method on web api. /// diff --git a/src/UnitOfWork/Repository.cs b/src/UnitOfWork/Repository.cs index c3fff96..005946c 100644 --- a/src/UnitOfWork/Repository.cs +++ b/src/UnitOfWork/Repository.cs @@ -12,6 +12,7 @@ using Microsoft.EntityFrameworkCore.Query; using Arch.EntityFrameworkCore.UnitOfWork.Collections; using Microsoft.EntityFrameworkCore.ChangeTracking; +// ReSharper disable All namespace Arch.EntityFrameworkCore.UnitOfWork { @@ -53,10 +54,7 @@ public virtual void ChangeTable(string table) /// Gets all entities. This method is not recommended /// /// The . - public IQueryable GetAll() - { - return _dbSet; - } + public IQueryable GetAll() => _dbSet; /// /// Gets all entities. This method is not recommended @@ -116,7 +114,7 @@ public IQueryable GetAll( /// Ignore query filters /// An that contains elements that satisfy the condition specified by . /// Ex: This method defaults to a read-only, no-tracking query. - public IQueryable GetAll(Expression> selector, + public IQueryable GetAll(Expression> selector, Expression> predicate = null, Func, IOrderedQueryable> orderBy = null, Func, IIncludableQueryable> include = null, bool disableTracking = true, bool ignoreQueryFilters = false) @@ -153,6 +151,56 @@ public IQueryable GetAll(Expression> sel } } + /// + /// Gets all entities. This method is not recommended + /// + /// The selector for projection. + /// A function to test each element for a condition. + /// A function to order elements. + /// A function to include navigation properties + /// true to disable changing tracking; otherwise, false. Default to true. + /// Ignore query filters + /// An that contains elements that satisfy the condition specified by . + /// Ex: This method defaults to a read-only, no-tracking query. + public async Task> GetAllAsync(Expression> selector, + Expression> predicate = null, + Func, IOrderedQueryable> orderBy = null, + Func, IIncludableQueryable> include = null, + bool disableTracking = true, bool ignoreQueryFilters = false) + { + IQueryable query = _dbSet; + + if (disableTracking) + { + query = query.AsNoTracking(); + } + + if (include != null) + { + query = include(query); + } + + if (predicate != null) + { + query = query.Where(predicate); + } + + if (ignoreQueryFilters) + { + query = query.IgnoreQueryFilters(); + } + + + if (orderBy != null) + { + return await orderBy(query).Select(selector).ToListAsync(); + } + else + { + return await query.Select(selector).ToListAsync(); + } + } + /// /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query. /// @@ -586,16 +634,20 @@ public virtual async Task GetFirstOrDefaultAsync(Expression /// + /// /// - public virtual int Count(Expression> predicate = null) + public virtual int Count(Expression> predicate = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) { - return _dbSet.Count(); + return query.Count(); } else { - return _dbSet.Count(predicate); + return query.Count(predicate); } } @@ -603,16 +655,20 @@ public virtual int Count(Expression> predicate = null) /// Gets async the count based on a predicate. /// /// + /// /// - public virtual async Task CountAsync(Expression> predicate = null) + public virtual async Task CountAsync(Expression> predicate = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) { - return await _dbSet.CountAsync(); + return await query.CountAsync(); } else { - return await _dbSet.CountAsync(predicate); + return await query.CountAsync(predicate); } } @@ -620,16 +676,20 @@ public virtual async Task CountAsync(Expression> predic /// Gets the long count based on a predicate. /// /// + /// /// - public virtual long LongCount(Expression> predicate = null) + public virtual long LongCount(Expression> predicate = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) { - return _dbSet.LongCount(); + return query.LongCount(); } else { - return _dbSet.LongCount(predicate); + return query.LongCount(predicate); } } @@ -637,16 +697,20 @@ public virtual long LongCount(Expression> predicate = null) /// Gets async the long count based on a predicate. /// /// + /// /// - public virtual async Task LongCountAsync(Expression> predicate = null) + public virtual async Task LongCountAsync(Expression> predicate = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) { - return await _dbSet.LongCountAsync(); + return await query.LongCountAsync(); } else { - return await _dbSet.LongCountAsync(predicate); + return await query.LongCountAsync(predicate); } } @@ -655,13 +719,19 @@ public virtual async Task LongCountAsync(Expression> p /// /// /// /// + /// /// decimal - public virtual T Max(Expression> predicate = null, Expression> selector = null) + public virtual T Max( + Expression> predicate = null, + Expression> selector = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) - return _dbSet.Max(selector); + return query.Max(selector ?? throw new ArgumentNullException(nameof(selector))); else - return _dbSet.Where(predicate).Max(selector); + return query.Where(predicate).Max(selector ?? throw new ArgumentNullException(nameof(selector))); } /// @@ -669,13 +739,17 @@ public virtual T Max(Expression> predicate = null, Expres /// /// /// /// + /// /// decimal - public virtual async Task MaxAsync(Expression> predicate = null, Expression> selector = null) + public virtual async Task MaxAsync(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) - return await _dbSet.MaxAsync(selector); + return await query.MaxAsync(selector ?? throw new ArgumentNullException(nameof(selector))); else - return await _dbSet.Where(predicate).MaxAsync(selector); + return await query.Where(predicate).MaxAsync(selector ?? throw new ArgumentNullException(nameof(selector))); } /// @@ -683,13 +757,17 @@ public virtual async Task MaxAsync(Expression> predica /// /// /// /// + /// /// decimal - public virtual T Min(Expression> predicate = null, Expression> selector = null) + public virtual T Min(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) - return _dbSet.Min(selector); + return query.Min(selector ?? throw new ArgumentNullException(nameof(selector))); else - return _dbSet.Where(predicate).Min(selector); + return query.Where(predicate).Min(selector ?? throw new ArgumentNullException(nameof(selector))); } /// @@ -697,13 +775,17 @@ public virtual T Min(Expression> predicate = null, Expres /// /// /// /// + /// /// decimal - public virtual async Task MinAsync(Expression> predicate = null, Expression> selector = null) + public virtual async Task MinAsync(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) - return await _dbSet.MinAsync(selector); + return await query.MinAsync(selector ?? throw new ArgumentNullException(nameof(selector))); else - return await _dbSet.Where(predicate).MinAsync(selector); + return await query.Where(predicate).MinAsync(selector ?? throw new ArgumentNullException(nameof(selector))); } /// @@ -711,13 +793,17 @@ public virtual async Task MinAsync(Expression> predica /// /// /// /// + /// /// decimal - public virtual decimal Average(Expression> predicate = null, Expression> selector = null) + public virtual decimal Average(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) - return _dbSet.Average(selector); + return query.Average(selector ?? throw new ArgumentNullException(nameof(selector))); else - return _dbSet.Where(predicate).Average(selector); + return query.Where(predicate).Average(selector ?? throw new ArgumentNullException(nameof(selector))); } /// @@ -725,13 +811,17 @@ public virtual decimal Average(Expression> predicate = null, /// /// /// /// + /// /// decimal - public virtual async Task AverageAsync(Expression> predicate = null, Expression> selector = null) + public virtual async Task AverageAsync(Expression> predicate = null, Expression> selector = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) - return await _dbSet.AverageAsync(selector); + return await query.AverageAsync(selector ?? throw new ArgumentNullException(nameof(selector))); else - return await _dbSet.Where(predicate).AverageAsync(selector); + return await query.Where(predicate).AverageAsync(selector ?? throw new ArgumentNullException(nameof(selector))); } /// @@ -739,13 +829,18 @@ public virtual async Task AverageAsync(Expression> /// /// /// /// + /// /// decimal - public virtual decimal Sum(Expression> predicate = null, Expression> selector = null) + public virtual decimal Sum(Expression> predicate = null, + Expression> selector = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) - return _dbSet.Sum(selector); + return query.Sum(selector ?? throw new ArgumentNullException(nameof(selector))); else - return _dbSet.Where(predicate).Sum(selector); + return query.Where(predicate).Sum(selector ?? throw new ArgumentNullException(nameof(selector))); } /// @@ -753,55 +848,51 @@ public virtual decimal Sum(Expression> predicate = null, Exp /// /// /// /// + /// /// decimal - public virtual async Task SumAsync(Expression> predicate = null, Expression> selector = null) + public virtual async Task SumAsync( + Expression> predicate = null, + Expression> selector = null, bool ignoreQueryFilters = false) { + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + if (predicate == null) - return await _dbSet.SumAsync(selector); + return await query.SumAsync(selector ?? throw new ArgumentNullException(nameof(selector))); else - return await _dbSet.Where(predicate).SumAsync(selector); + return await query.Where(predicate).SumAsync(selector ?? throw new ArgumentNullException(nameof(selector))); } /// /// Gets the exists based on a predicate. /// /// + /// /// - public bool Exists(Expression> selector = null) + public bool Exists(Expression> selector = null, bool ignoreQueryFilters = false) { - if (selector == null) - { - return _dbSet.Any(); - } - else - { - return _dbSet.Any(selector); - } + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + return selector == null ? query.Any() : query.Any(selector); } /// /// Gets the async exists based on a predicate. /// /// + /// /// - public async Task ExistsAsync(Expression> selector = null) + public async Task ExistsAsync(Expression> selector = null, bool ignoreQueryFilters = false) { - if (selector == null) - { - return await _dbSet.AnyAsync(); - } - else - { - return await _dbSet.AnyAsync(selector); - } - } + IQueryable query = _dbSet; + if (ignoreQueryFilters) query = query.IgnoreQueryFilters(); + return selector == null ? await query.AnyAsync() : await query.AnyAsync(selector); + } + /// /// Inserts a new entity synchronously. /// /// The entity to insert. - public virtual TEntity Insert(TEntity entity) - { - return _dbSet.Add(entity).Entity; - } + public virtual TEntity Insert(TEntity entity) => _dbSet.Add(entity).Entity; /// /// Inserts a range of entities synchronously. @@ -821,17 +912,13 @@ public virtual TEntity Insert(TEntity entity) /// The entity to insert. /// A to observe while waiting for the task to complete. /// A that represents the asynchronous insert operation. - public virtual ValueTask> InsertAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken)) - { - return _dbSet.AddAsync(entity, cancellationToken); - - // Shadow properties? - //var property = _dbContext.Entry(entity).Property("Created"); - //if (property != null) { - //property.CurrentValue = DateTime.Now; - //} - } + public virtual ValueTask> InsertAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken)) => _dbSet.AddAsync(entity, cancellationToken); + // Shadow properties? + //var property = _dbContext.Entry(entity).Property("Created"); + //if (property != null) { + //property.CurrentValue = DateTime.Now; + //} /// /// Inserts a range of entities asynchronously. /// @@ -851,20 +938,13 @@ public virtual TEntity Insert(TEntity entity) /// Updates the specified entity. /// /// The entity. - public virtual void Update(TEntity entity) - { - _dbSet.Update(entity); - } + public virtual void Update(TEntity entity) => _dbSet.Update(entity); /// /// Updates the specified entity. /// /// The entity. - public virtual void UpdateAsync(TEntity entity) - { - _dbSet.Update(entity); - - } + public virtual void UpdateAsync(TEntity entity) => _dbSet.Update(entity); /// /// Updates the specified entities. @@ -893,7 +973,7 @@ public virtual void Delete(object id) // using a stub entity to mark for deletion var typeInfo = typeof(TEntity).GetTypeInfo(); var key = _dbContext.Model.FindEntityType(typeInfo).FindPrimaryKey().Properties.FirstOrDefault(); - var property = typeInfo.GetProperty(key?.Name); + var property = typeInfo.GetProperty(key?.Name ?? string.Empty); if (property != null) { var entity = Activator.CreateInstance(); @@ -926,10 +1006,7 @@ public virtual void Delete(object id) /// Gets all entities. This method is not recommended /// /// The . - public async Task> GetAllAsync() - { - return await _dbSet.ToListAsync(); - } + public async Task> GetAllAsync() => await _dbSet.ToListAsync(); /// /// Gets all entities. This method is not recommended @@ -979,63 +1056,33 @@ public async Task> GetAllAsync(Expression> pr } /// - /// Gets all entities. This method is not recommended + /// Bulk Delete the specified entity. /// - /// The selector for projection. - /// A function to test each element for a condition. - /// A function to order elements. - /// A function to include navigation properties - /// true to disable changing tracking; otherwise, false. Default to true. - /// Ignore query filters - /// An that contains elements that satisfy the condition specified by . - /// Ex: This method defaults to a read-only, no-tracking query. - public async Task> GetAllAsync(Expression> selector, - Expression> predicate = null, - Func, IOrderedQueryable> orderBy = null, - Func, IIncludableQueryable> include = null, - bool disableTracking = true, bool ignoreQueryFilters = false) - { - IQueryable query = _dbSet; - - if (disableTracking) - { - query = query.AsNoTracking(); - } + public void BulkDelete()=> _dbSet.ExecuteDelete(); - if (include != null) - { - query = include(query); - } + /// + /// Bulk Delete the specified entity. + /// + public async Task BulkDeleteAsync() => await _dbSet.ExecuteDeleteAsync(); - if (predicate != null) - { - query = query.Where(predicate); - } - if (ignoreQueryFilters) - { - query = query.IgnoreQueryFilters(); - } + /// + /// Bulk Update the specified entity. + /// + /// the entity property + public void BulkUpdate(Expression, SetPropertyCalls>> setPropertyCalls) => _dbSet.ExecuteUpdate(setPropertyCalls); - - if (orderBy != null) - { - return await orderBy(query).Select(selector).ToListAsync(); - } - else - { - return await query.Select(selector).ToListAsync(); - } - } + /// + /// Async Bulk Update the specified entity. + /// the entity property + /// + public async Task BulkUpdateAsync(Expression, SetPropertyCalls>> setPropertyCalls) => await _dbSet.ExecuteUpdateAsync(setPropertyCalls); /// /// Change entity state for patch method on web api. /// /// The entity. /// /// The entity state. - public void ChangeEntityState(TEntity entity, EntityState state) - { - _dbContext.Entry(entity).State = state; - } + public void ChangeEntityState(TEntity entity, EntityState state) => _dbContext.Entry(entity).State = state; } } diff --git a/src/UnitOfWork/UnitOfWork.csproj b/src/UnitOfWork/UnitOfWork.csproj index fdf335f..1494a93 100644 --- a/src/UnitOfWork/UnitOfWork.csproj +++ b/src/UnitOfWork/UnitOfWork.csproj @@ -1,25 +1,29 @@  A plugin for Microsoft.EntityFrameworkCore to support repository, unit of work patterns, and multiple database with distributed transaction supported. - 3.1.0 - rigofunc;rigofunc@outlook.com; - netstandard2.0 + 7.1.0 + rigofunc;rigofunc@outlook.com;qermezkon@gmail.com + net7.0 $(NoWarn);CS1591 true true Microsoft.EntityFrameworkCore.UnitOfWork Microsoft.EntityFrameworkCore.UnitOfWork Entity Framework Core;entity-framework-core;EF;Data;O/RM;unitofwork;Unit Of Work;unit-of-work - https://github.com/arch/UnitOfWork + https://github.com/AikiCo/UnitOfWork MIT git - https://github.com/arch/UnitOfWork.git - 3.1.16 + https://github.com/AikiCo/UnitOfWork + 7.1.0 true snupkg + 8 + 7.1.0 + true + cba3a20d-f192-445e-9058-fdbacec3fea3 - - + + diff --git a/test/UnitOfWork.Tests/InMemoryContext.cs b/test/UnitOfWork.Tests/InMemoryContext.cs index cf60438..bf693dc 100644 --- a/test/UnitOfWork.Tests/InMemoryContext.cs +++ b/test/UnitOfWork.Tests/InMemoryContext.cs @@ -8,9 +8,6 @@ public class InMemoryContext : DbContext public DbSet Countries { get; set; } public DbSet Customers { get; set; } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - optionsBuilder.UseInMemoryDatabase("test"); - } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseInMemoryDatabase("test"); } } diff --git a/test/UnitOfWork.Tests/UnitOfWork.Tests.csproj b/test/UnitOfWork.Tests/UnitOfWork.Tests.csproj index 1597ff6..e9dfcfa 100644 --- a/test/UnitOfWork.Tests/UnitOfWork.Tests.csproj +++ b/test/UnitOfWork.Tests/UnitOfWork.Tests.csproj @@ -5,10 +5,11 @@ - - + + + - + all runtime; build; native; contentfiles; analyzers