Try your search with a different keyword or use * as a wildcard.
using System.Linq.Expressions;
using System.Transactions;
using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.Configuration;
using Nop.Core.Domain.Common;
using Nop.Core.Events;
namespace Nop.Data;
///
/// Represents the entity repository implementation
///
/// Entity type
public partial class EntityRepository : IRepository where TEntity : BaseEntity
{
#region Fields
protected readonly IEventPublisher _eventPublisher;
protected readonly INopDataProvider _dataProvider;
protected readonly IShortTermCacheManager _shortTermCacheManager;
protected readonly IStaticCacheManager _staticCacheManager;
protected readonly bool _usingDistributedCache;
#endregion
#region Ctor
public EntityRepository(IEventPublisher eventPublisher,
INopDataProvider dataProvider,
IShortTermCacheManager shortTermCacheManager,
IStaticCacheManager staticCacheManager,
AppSettings appSettings)
{
_eventPublisher = eventPublisher;
_dataProvider = dataProvider;
_shortTermCacheManager = shortTermCacheManager;
_staticCacheManager = staticCacheManager;
_usingDistributedCache = appSettings.Get().DistributedCacheType switch
{
DistributedCacheType.Redis => true,
DistributedCacheType.SqlServer => true,
_ => false
};
}
#endregion
#region Utilities
///
/// Get all entity entries
///
/// Function to select entries
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
///
/// A task that represents the asynchronous operation
/// The task result contains the entity entries
///
protected virtual async Task> GetEntitiesAsync(Func>> getAllAsync, Func getCacheKey)
{
if (getCacheKey == null)
return await getAllAsync();
//caching
var cacheKey = getCacheKey(_staticCacheManager)
?? _staticCacheManager.PrepareKeyForDefaultCache(NopEntityCacheDefaults.AllCacheKey);
return await _staticCacheManager.GetAsync(cacheKey, getAllAsync);
}
///
/// Get all entity entries
///
/// Function to select entries
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
/// Entity entries
protected virtual IList GetEntities(Func> getAll, Func getCacheKey)
{
if (getCacheKey == null)
return getAll();
//caching
var cacheKey = getCacheKey(_staticCacheManager)
?? _staticCacheManager.PrepareKeyForDefaultCache(NopEntityCacheDefaults.AllCacheKey);
return _staticCacheManager.Get(cacheKey, getAll);
}
///
/// Get all entity entries
///
/// Function to select entries
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
///
/// A task that represents the asynchronous operation
/// The task result contains the entity entries
///
protected virtual async Task> GetEntitiesAsync(Func>> getAllAsync, Func> getCacheKey)
{
if (getCacheKey == null)
return await getAllAsync();
//caching
var cacheKey = await getCacheKey(_staticCacheManager)
?? _staticCacheManager.PrepareKeyForDefaultCache(NopEntityCacheDefaults.AllCacheKey);
return await _staticCacheManager.GetAsync(cacheKey, getAllAsync);
}
///
/// Adds "deleted" filter to query which contains entries, if its need
///
/// Entity entries
/// Whether to include deleted items
/// Entity entries
protected virtual IQueryable AddDeletedFilter(IQueryable query, in bool includeDeleted)
{
if (includeDeleted)
return query;
if (typeof(TEntity).GetInterface(nameof(ISoftDeletedEntity)) == null)
return query;
return query.OfType().Where(entry => !entry.Deleted).OfType();
}
///
/// Transactionally deletes a list of entities
///
/// Entities to delete
protected virtual async Task DeleteAsync(IList entities)
{
using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
await _dataProvider.BulkDeleteEntitiesAsync(entities);
transaction.Complete();
}
///
/// Soft-deletes entities
///
/// Entities to delete
protected virtual async Task DeleteAsync(IList entities) where T : ISoftDeletedEntity, TEntity
{
foreach (var entity in entities)
entity.Deleted = true;
await _dataProvider.UpdateEntitiesAsync(entities);
}
#endregion
#region Methods
///
/// Get the entity entry
///
/// Entity entry identifier
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
/// Whether to include deleted items (applies only to entities)
/// Whether to use short term cache instead of static cache
///
/// A task that represents the asynchronous operation
/// The task result contains the entity entry
///
public virtual async Task GetByIdAsync(int? id, Func getCacheKey = null, bool includeDeleted = true, bool useShortTermCache = false)
{
if (!id.HasValue || id == 0)
return null;
async Task getEntityAsync()
{
return await AddDeletedFilter(Table, includeDeleted).FirstOrDefaultAsync(entity => entity.Id == Convert.ToInt32(id));
}
if (getCacheKey == null)
return await getEntityAsync();
ICacheKeyService cacheKeyService = useShortTermCache ? _shortTermCacheManager : _staticCacheManager;
//caching
var cacheKey = getCacheKey(cacheKeyService)
?? cacheKeyService.PrepareKeyForDefaultCache(NopEntityCacheDefaults.ByIdCacheKey, id);
if (useShortTermCache)
return await _shortTermCacheManager.GetAsync(getEntityAsync, cacheKey);
return await _staticCacheManager.GetAsync(cacheKey, getEntityAsync);
}
///
/// Get the entity entry
///
/// Entity entry identifier
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
/// Whether to include deleted items (applies only to entities)
///
/// The entity entry
///
public virtual TEntity GetById(int? id, Func getCacheKey = null, bool includeDeleted = true)
{
if (!id.HasValue || id == 0)
return null;
TEntity getEntity()
{
return AddDeletedFilter(Table, includeDeleted).FirstOrDefault(entity => entity.Id == Convert.ToInt32(id));
}
if (getCacheKey == null)
return getEntity();
//caching
var cacheKey = getCacheKey(_staticCacheManager)
?? _staticCacheManager.PrepareKeyForDefaultCache(NopEntityCacheDefaults.ByIdCacheKey, id);
return _staticCacheManager.Get(cacheKey, getEntity);
}
///
/// Get entity entries by identifiers
///
/// Entity entry identifiers
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
/// Whether to include deleted items (applies only to entities)
///
/// A task that represents the asynchronous operation
/// The task result contains the entity entries
///
public virtual async Task> GetByIdsAsync(IList ids, Func getCacheKey = null, bool includeDeleted = true)
{
if (ids?.Any() != true)
return new List();
static IList sortByIdList(IList listOfId, IDictionary entitiesById)
{
var sortedEntities = new List(listOfId.Count);
foreach (var id in listOfId)
if (entitiesById.TryGetValue(id, out var entry))
sortedEntities.Add(entry);
return sortedEntities;
}
async Task> getByIdsAsync(IList listOfId, bool sort = true)
{
var query = AddDeletedFilter(Table, includeDeleted)
.Where(entry => listOfId.Contains(entry.Id));
return sort
? sortByIdList(listOfId, await query.ToDictionaryAsync(entry => entry.Id))
: await query.ToListAsync();
}
if (getCacheKey == null)
return await getByIdsAsync(ids);
//caching
var cacheKey = getCacheKey(_staticCacheManager);
if (cacheKey == null && _usingDistributedCache)
cacheKey = _staticCacheManager.PrepareKeyForDefaultCache(NopEntityCacheDefaults.ByIdsCacheKey, ids);
if (cacheKey != null)
return await _staticCacheManager.GetAsync(cacheKey, async () => await getByIdsAsync(ids));
//if we are using an in-memory cache, we can optimize by caching each entity individually for maximum reusability.
//with a distributed cache, the overhead would be too high.
var cachedById = await ids
.Distinct()
.SelectAwait(async id => await _staticCacheManager.GetAsync(
_staticCacheManager.PrepareKeyForDefaultCache(NopEntityCacheDefaults.ByIdCacheKey, id),
default(TEntity)))
.Where(entity => entity != default)
.ToDictionaryAsync(entity => entity.Id, entity => entity);
var missingIds = ids.Except(cachedById.Keys).ToList();
var missingEntities = missingIds.Count > 0 ? await getByIdsAsync(missingIds, false) : new List();
foreach (var entity in missingEntities)
{
await _staticCacheManager.SetAsync(_staticCacheManager.PrepareKeyForDefaultCache(NopEntityCacheDefaults.ByIdCacheKey, entity.Id), entity);
cachedById[entity.Id] = entity;
}
return sortByIdList(ids, cachedById);
}
///
/// Get all entity entries
///
/// Function to select entries
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
/// Whether to include deleted items (applies only to entities)
///
/// A task that represents the asynchronous operation
/// The task result contains the entity entries
///
public virtual async Task> GetAllAsync(Func, IQueryable> func = null,
Func getCacheKey = null, bool includeDeleted = true)
{
async Task> getAllAsync()
{
var query = AddDeletedFilter(Table, includeDeleted);
query = func != null ? func(query) : query;
return await query.ToListAsync();
}
return await GetEntitiesAsync(getAllAsync, getCacheKey);
}
///
/// Get all entity entries
///
/// Function to select entries
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
/// Whether to include deleted items (applies only to entities)
/// Entity entries
public virtual IList GetAll(Func, IQueryable> func = null,
Func getCacheKey = null, bool includeDeleted = true)
{
IList getAll()
{
var query = AddDeletedFilter(Table, includeDeleted);
query = func != null ? func(query) : query;
return query.ToList();
}
return GetEntities(getAll, getCacheKey);
}
///
/// Get all entity entries
///
/// Function to select entries
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
/// Whether to include deleted items (applies only to entities)
///
/// A task that represents the asynchronous operation
/// The task result contains the entity entries
///
public virtual async Task> GetAllAsync(
Func, Task>> func = null,
Func getCacheKey = null, bool includeDeleted = true)
{
async Task> getAllAsync()
{
var query = AddDeletedFilter(Table, includeDeleted);
query = func != null ? await func(query) : query;
return await query.ToListAsync();
}
return await GetEntitiesAsync(getAllAsync, getCacheKey);
}
///
/// Get all entity entries
///
/// Function to select entries
/// Function to get a cache key; pass null to don't cache; return null from this function to use the default key
/// Whether to include deleted items (applies only to entities)
///
/// A task that represents the asynchronous operation
/// The task result contains the entity entries
///
public virtual async Task> GetAllAsync(
Func, Task>> func = null,
Func> getCacheKey = null, bool includeDeleted = true)
{
async Task> getAllAsync()
{
var query = AddDeletedFilter(Table, includeDeleted);
query = func != null ? await func(query) : query;
return await query.ToListAsync();
}
return await GetEntitiesAsync(getAllAsync, getCacheKey);
}
///
/// Get paged list of all entity entries
///
/// Function to select entries
/// Page index
/// Page size
/// Whether to get only the total number of entries without actually loading data
/// Whether to include deleted items (applies only to entities)
///
/// A task that represents the asynchronous operation
/// The task result contains the paged list of entity entries
///
public virtual async Task> GetAllPagedAsync(Func, IQueryable> func = null,
int pageIndex = 0, int pageSize = int.MaxValue, bool getOnlyTotalCount = false, bool includeDeleted = true)
{
var query = AddDeletedFilter(Table, includeDeleted);
query = func != null ? func(query) : query;
return await query.ToPagedListAsync(pageIndex, pageSize, getOnlyTotalCount);
}
///
/// Get paged list of all entity entries
///
/// Function to select entries
/// Page index
/// Page size
/// Whether to get only the total number of entries without actually loading data
/// Whether to include deleted items (applies only to entities)
///
/// A task that represents the asynchronous operation
/// The task result contains the paged list of entity entries
///
public virtual async Task> GetAllPagedAsync(Func, Task>> func = null,
int pageIndex = 0, int pageSize = int.MaxValue, bool getOnlyTotalCount = false, bool includeDeleted = true)
{
var query = AddDeletedFilter(Table, includeDeleted);
query = func != null ? await func(query) : query;
return await query.ToPagedListAsync(pageIndex, pageSize, getOnlyTotalCount);
}
///
/// Insert the entity entry
///
/// Entity entry
/// Whether to publish event notification
/// A task that represents the asynchronous operation
public virtual async Task InsertAsync(TEntity entity, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entity);
await _dataProvider.InsertEntityAsync(entity);
//event notification
if (publishEvent)
await _eventPublisher.EntityInsertedAsync(entity);
}
///
/// Insert the entity entry
///
/// Entity entry
/// Whether to publish event notification
public virtual void Insert(TEntity entity, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entity);
_dataProvider.InsertEntity(entity);
//event notification
if (publishEvent)
_eventPublisher.EntityInserted(entity);
}
///
/// Insert entity entries
///
/// Entity entries
/// Whether to publish event notification
/// A task that represents the asynchronous operation
public virtual async Task InsertAsync(IList entities, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entities);
using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
await _dataProvider.BulkInsertEntitiesAsync(entities);
transaction.Complete();
if (!publishEvent)
return;
//event notification
foreach (var entity in entities)
await _eventPublisher.EntityInsertedAsync(entity);
}
///
/// Insert entity entries
///
/// Entity entries
/// Whether to publish event notification
public virtual void Insert(IList entities, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entities);
using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
_dataProvider.BulkInsertEntities(entities);
transaction.Complete();
if (!publishEvent)
return;
//event notification
foreach (var entity in entities)
_eventPublisher.EntityInserted(entity);
}
///
/// Loads the original copy of the entity
///
/// Entity
///
/// A task that represents the asynchronous operation
/// The task result contains the copy of the passed entity
///
public virtual async Task LoadOriginalCopyAsync(TEntity entity)
{
return await _dataProvider.GetTable()
.FirstOrDefaultAsync(e => e.Id == Convert.ToInt32(entity.Id));
}
///
/// Update the entity entry
///
/// Entity entry
/// Whether to publish event notification
/// A task that represents the asynchronous operation
public virtual async Task UpdateAsync(TEntity entity, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entity);
await _dataProvider.UpdateEntityAsync(entity);
//event notification
if (publishEvent)
await _eventPublisher.EntityUpdatedAsync(entity);
}
///
/// Update the entity entry
///
/// Entity entry
/// Whether to publish event notification
public virtual void Update(TEntity entity, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entity);
_dataProvider.UpdateEntity(entity);
//event notification
if (publishEvent)
_eventPublisher.EntityUpdated(entity);
}
///
/// Update entity entries
///
/// Entity entries
/// Whether to publish event notification
/// A task that represents the asynchronous operation
public virtual async Task UpdateAsync(IList entities, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entities);
if (!entities.Any())
return;
await _dataProvider.UpdateEntitiesAsync(entities);
//event notification
if (!publishEvent)
return;
foreach (var entity in entities)
await _eventPublisher.EntityUpdatedAsync(entity);
}
///
/// Update entity entries
///
/// Entity entries
/// Whether to publish event notification
public virtual void Update(IList entities, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entities);
if (!entities.Any())
return;
_dataProvider.UpdateEntities(entities);
//event notification
if (!publishEvent)
return;
foreach (var entity in entities)
_eventPublisher.EntityUpdated(entity);
}
///
/// Delete the entity entry
///
/// Entity entry
/// Whether to publish event notification
/// A task that represents the asynchronous operation
public virtual async Task DeleteAsync(TEntity entity, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entity);
switch (entity)
{
case ISoftDeletedEntity softDeletedEntity:
softDeletedEntity.Deleted = true;
await _dataProvider.UpdateEntityAsync(entity);
break;
default:
await _dataProvider.DeleteEntityAsync(entity);
break;
}
//event notification
if (publishEvent)
await _eventPublisher.EntityDeletedAsync(entity);
}
///
/// Delete the entity entry
///
/// Entity entry
/// Whether to publish event notification
public virtual void Delete(TEntity entity, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entity);
switch (entity)
{
case ISoftDeletedEntity softDeletedEntity:
softDeletedEntity.Deleted = true;
_dataProvider.UpdateEntity(entity);
break;
default:
_dataProvider.DeleteEntity(entity);
break;
}
//event notification
if (publishEvent)
_eventPublisher.EntityDeleted(entity);
}
///
/// Delete entity entries
///
/// Entity entries
/// Whether to publish event notification
/// A task that represents the asynchronous operation
public virtual async Task DeleteAsync(IList entities, bool publishEvent = true)
{
ArgumentNullException.ThrowIfNull(entities);
if (!entities.Any())
return;
await DeleteAsync(entities);
//event notification
if (!publishEvent)
return;
foreach (var entity in entities)
await _eventPublisher.EntityDeletedAsync(entity);
}
///
/// Delete entity entries by the passed predicate
///
/// A function to test each element for a condition
///
/// A task that represents the asynchronous operation
/// The task result contains the number of deleted records
///
public virtual async Task DeleteAsync(Expression> predicate)
{
ArgumentNullException.ThrowIfNull(predicate);
using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
var countDeletedRecords = await _dataProvider.BulkDeleteEntitiesAsync(predicate);
transaction.Complete();
return countDeletedRecords;
}
///
/// Delete entity entries by the passed predicate
///
/// A function to test each element for a condition
///
/// The number of deleted records
///
public virtual int Delete(Expression> predicate)
{
ArgumentNullException.ThrowIfNull(predicate);
using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
var countDeletedRecords = _dataProvider.BulkDeleteEntities(predicate);
transaction.Complete();
return countDeletedRecords;
}
///
/// Truncates database table
///
/// Performs reset identity column
/// A task that represents the asynchronous operation
public virtual async Task TruncateAsync(bool resetIdentity = false)
{
await _dataProvider.TruncateAsync(resetIdentity);
}
#endregion
#region Properties
///
/// Gets a table
///
public virtual IQueryable Table => _dataProvider.GetTable();
#endregion
}