@ -1,4 +1,3 @@
using JetBrains.Annotations ;
using Microsoft.EntityFrameworkCore ;
using Microsoft.Extensions.DependencyInjection ;
using Microsoft.Extensions.Options ;
@ -6,16 +5,15 @@ using System;
using System.Collections.Generic ;
using System.Data ;
using System.Linq ;
using System.Linq.Dynamic.Core ;
using System.Linq.Expressions ;
using System.Threading ;
using System.Threading.Tasks ;
using Microsoft.EntityFrameworkCore.Storage ;
using Volo.Abp.Data ;
using Volo.Abp.Domain.Entities ;
using Volo.Abp.EntityFrameworkCore ;
using Volo.Abp.EntityFrameworkCore.DependencyInjection ;
using Volo.Abp.Guids ;
using Volo.Abp.MultiTenancy ;
namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore ;
@ -37,30 +35,50 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
[Obsolete("Use GetDbContextAsync() method.")]
private TDbContext GetDbContext ( )
{
TDbContext dbContext ;
// Multi-tenancy unaware entities should always use the host connection string
if ( ! EntityHelper . IsMultiTenant < TEntity > ( ) )
{
using ( CurrentTenant . Change ( null ) )
{
return _d bContextProvider . GetDbContext ( ) ;
dbContext = _d bContextProvider . GetDbContext ( ) ;
}
}
else
{
dbContext = _d bContextProvider . GetDbContext ( ) ;
}
if ( IsReadOnly )
{
dbContext . ChangeTracker . QueryTrackingBehavior = QueryTrackingBehavior . NoTracking ;
}
return _d bContextProvider . GetDbContext ( ) ;
return dbContext ;
}
protected virtual Task < TDbContext > GetDbContextAsync ( )
protected virtual async Task < TDbContext > GetDbContextAsync ( )
{
TDbContext dbContext ;
// Multi-tenancy unaware entities should always use the host connection string
if ( ! EntityHelper . IsMultiTenant < TEntity > ( ) )
{
using ( CurrentTenant . Change ( null ) )
{
return _d bContextProvider . GetDbContextAsync ( ) ;
dbContext = await _d bContextProvider . GetDbContextAsync ( ) ;
}
}
else
{
dbContext = await _d bContextProvider . GetDbContextAsync ( ) ;
}
if ( IsReadOnly )
{
dbContext . ChangeTracker . QueryTrackingBehavior = QueryTrackingBehavior . NoTracking ;
}
return _d bContextProvider . GetDbContextAsync ( ) ;
return dbContext ;
}
[Obsolete("Use GetDbSetAsync() method.")]
@ -75,7 +93,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
{
return ( await GetDbContextAsync ( ) ) . Set < TEntity > ( ) ;
}
protected async Task < IDbConnection > GetDbConnectionAsync ( )
{
return ( await GetDbContextAsync ( ) ) . Database . GetDbConnection ( ) ;
@ -107,8 +125,9 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
) ;
}
public override async Task < TEntity > InsertAsync ( TEntity entity , bool autoSave = false , CancellationToken cancellationToken = default )
public async override Task < TEntity > InsertAsync ( TEntity entity , bool autoSave = false , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
CheckAndSetId ( entity ) ;
var dbContext = await GetDbContextAsync ( ) ;
@ -123,8 +142,9 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
return savedEntity ;
}
public override async Task InsertManyAsync ( IEnumerable < TEntity > entities , bool autoSave = false , CancellationToken cancellationToken = default )
public async override Task InsertManyAsync ( IEnumerable < TEntity > entities , bool autoSave = false , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
var entityArray = entities . ToArray ( ) ;
var dbContext = await GetDbContextAsync ( ) ;
cancellationToken = GetCancellationToken ( cancellationToken ) ;
@ -153,8 +173,9 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
}
}
public override async Task < TEntity > UpdateAsync ( TEntity entity , bool autoSave = false , CancellationToken cancellationToken = default )
public async override Task < TEntity > UpdateAsync ( TEntity entity , bool autoSave = false , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
var dbContext = await GetDbContextAsync ( ) ;
dbContext . Attach ( entity ) ;
@ -169,8 +190,9 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
return updatedEntity ;
}
public override async Task UpdateManyAsync ( IEnumerable < TEntity > entities , bool autoSave = false , CancellationToken cancellationToken = default )
public async override Task UpdateManyAsync ( IEnumerable < TEntity > entities , bool autoSave = false , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
cancellationToken = GetCancellationToken ( cancellationToken ) ;
if ( BulkOperationProvider ! = null )
@ -195,8 +217,9 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
}
}
public override async Task DeleteAsync ( TEntity entity , bool autoSave = false , CancellationToken cancellationToken = default )
public async override Task DeleteAsync ( TEntity entity , bool autoSave = false , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
var dbContext = await GetDbContextAsync ( ) ;
dbContext . Set < TEntity > ( ) . Remove ( entity ) ;
@ -207,8 +230,9 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
}
}
public override async Task DeleteManyAsync ( IEnumerable < TEntity > entities , bool autoSave = false , CancellationToken cancellationToken = default )
public async override Task DeleteManyAsync ( IEnumerable < TEntity > entities , bool autoSave = false , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
cancellationToken = GetCancellationToken ( cancellationToken ) ;
if ( BulkOperationProvider ! = null )
@ -233,26 +257,26 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
}
}
public override async Task < List < TEntity > > GetListAsync ( bool includeDetails = false , CancellationToken cancellationToken = default )
public async override Task < List < TEntity > > GetListAsync ( bool includeDetails = false , CancellationToken cancellationToken = default )
{
return includeDetails
? await ( await WithDetailsAsync ( ) ) . ToListAsync ( GetCancellationToken ( cancellationToken ) )
: await ( await GetDbSetAsync ( ) ) . ToListAsync ( GetCancellationToken ( cancellationToken ) ) ;
}
public override async Task < List < TEntity > > GetListAsync ( Expression < Func < TEntity , bool > > predicate , bool includeDetails = false , CancellationToken cancellationToken = default )
public async override Task < List < TEntity > > GetListAsync ( Expression < Func < TEntity , bool > > predicate , bool includeDetails = false , CancellationToken cancellationToken = default )
{
return includeDetails
? await ( await WithDetailsAsync ( ) ) . Where ( predicate ) . ToListAsync ( GetCancellationToken ( cancellationToken ) )
: await ( await GetDbSetAsync ( ) ) . Where ( predicate ) . ToListAsync ( GetCancellationToken ( cancellationToken ) ) ;
}
public override async Task < long > GetCountAsync ( CancellationToken cancellationToken = default )
public async override Task < long > GetCountAsync ( CancellationToken cancellationToken = default )
{
return await ( await GetDbSetAsync ( ) ) . LongCountAsync ( GetCancellationToken ( cancellationToken ) ) ;
}
public override async Task < List < TEntity > > GetPagedListAsync (
public async override Task < List < TEntity > > GetPagedListAsync (
int skipCount ,
int maxResultCount ,
string sorting ,
@ -275,17 +299,17 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
return DbSet . AsQueryable ( ) ;
}
public override async Task < IQueryable < TEntity > > GetQueryableAsync ( )
public async override Task < IQueryable < TEntity > > GetQueryableAsync ( )
{
return ( await GetDbSetAsync ( ) ) . AsQueryable ( ) ;
}
protected override async Task SaveChangesAsync ( CancellationToken cancellationToken )
protected async override Task SaveChangesAsync ( CancellationToken cancellationToken )
{
await ( await GetDbContextAsync ( ) ) . SaveChangesAsync ( cancellationToken ) ;
}
public override async Task < TEntity > FindAsync (
public async override Task < TEntity > FindAsync (
Expression < Func < TEntity , bool > > predicate ,
bool includeDetails = true ,
CancellationToken cancellationToken = default )
@ -299,8 +323,9 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
. SingleOrDefaultAsync ( GetCancellationToken ( cancellationToken ) ) ;
}
public override async Task DeleteAsync ( Expression < Func < TEntity , bool > > predicate , bool autoSave = false , CancellationToken cancellationToken = default )
public async override Task DeleteAsync ( Expression < Func < TEntity , bool > > predicate , bool autoSave = false , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
var dbContext = await GetDbContextAsync ( ) ;
var dbSet = dbContext . Set < TEntity > ( ) ;
@ -316,8 +341,9 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
}
}
public override async Task DeleteDirectAsync ( Expression < Func < TEntity , bool > > predicate , CancellationToken cancellationToken = default )
public async override Task DeleteDirectAsync ( Expression < Func < TEntity , bool > > predicate , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
var dbContext = await GetDbContextAsync ( ) ;
var dbSet = dbContext . Set < TEntity > ( ) ;
await dbSet . Where ( predicate ) . ExecuteDeleteAsync ( GetCancellationToken ( cancellationToken ) ) ;
@ -358,7 +384,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
return AbpEntityOptions . DefaultWithDetailsFunc ( GetQueryable ( ) ) ;
}
public override async Task < IQueryable < TEntity > > WithDetailsAsync ( )
public async override Task < IQueryable < TEntity > > WithDetailsAsync ( )
{
if ( AbpEntityOptions . DefaultWithDetailsFunc = = null )
{
@ -377,7 +403,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
) ;
}
public override async Task < IQueryable < TEntity > > WithDetailsAsync ( params Expression < Func < TEntity , object > > [ ] propertySelectors )
public async override Task < IQueryable < TEntity > > WithDetailsAsync ( params Expression < Func < TEntity , object > > [ ] propertySelectors )
{
return IncludeDetails (
await GetQueryableAsync ( ) ,
@ -421,6 +447,14 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
true
) ;
}
protected virtual void CheckReadOnly ( )
{
if ( IsReadOnly )
{
throw new AbpRepositoryIsReadOnlyException ( $"Can not call {nameof(InsertAsync)}, {nameof(UpdateAsync)}, {nameof(DeleteAsync)}, {nameof(DeleteManyAsync)} methods on a read-only repository!" ) ;
}
}
}
public class EfCoreRepository < TDbContext , TEntity , TKey > : EfCoreRepository < TDbContext , TEntity > ,
@ -457,6 +491,7 @@ public class EfCoreRepository<TDbContext, TEntity, TKey> : EfCoreRepository<TDbC
public virtual async Task DeleteAsync ( TKey id , bool autoSave = false , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
var entity = await FindAsync ( id , cancellationToken : cancellationToken ) ;
if ( entity = = null )
{
@ -468,6 +503,7 @@ public class EfCoreRepository<TDbContext, TEntity, TKey> : EfCoreRepository<TDbC
public virtual async Task DeleteManyAsync ( IEnumerable < TKey > ids , bool autoSave = false , CancellationToken cancellationToken = default )
{
CheckReadOnly ( ) ;
cancellationToken = GetCancellationToken ( cancellationToken ) ;
var entities = await ( await GetDbSetAsync ( ) ) . Where ( x = > ids . Contains ( x . Id ) ) . ToListAsync ( cancellationToken ) ;