Fix build after merge

This commit is contained in:
Bjarke Berg
2021-10-29 10:14:52 +02:00
parent 02bf61667d
commit bf5f1364fd
13 changed files with 1028 additions and 921 deletions

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using NPoco;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models.Entities;
using Umbraco.Cms.Core.Persistence;
@@ -14,38 +15,37 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
{
/// <summary>
/// Provides a base class to all <see cref="IEntity"/> based repositories.
/// Provides a base class to all <see cref="IEntity" /> based repositories.
/// </summary>
/// <typeparam name="TId">The type of the entity's unique identifier.</typeparam>
/// <typeparam name="TEntity">The type of the entity managed by this repository.</typeparam>
public abstract class EntityRepositoryBase<TId, TEntity> : RepositoryBase, IReadWriteQueryRepository<TId, TEntity>
where TEntity : class, IEntity
{
private static RepositoryCachePolicyOptions s_defaultOptions;
private IRepositoryCachePolicy<TEntity, TId> _cachePolicy;
private IQuery<TEntity> _hasIdQuery;
private static RepositoryCachePolicyOptions s_defaultOptions;
/// <summary>
/// Initializes a new instance of the <see cref="EntityRepositoryBase{TId, TEntity}"/> class.
/// Initializes a new instance of the <see cref="EntityRepositoryBase{TId, TEntity}" /> class.
/// </summary>
protected EntityRepositoryBase(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger<EntityRepositoryBase<TId, TEntity>> logger)
: base(scopeAccessor, appCaches)
{
protected EntityRepositoryBase(IScopeAccessor scopeAccessor, AppCaches appCaches,
ILogger<EntityRepositoryBase<TId, TEntity>> logger)
: base(scopeAccessor, appCaches) =>
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// Gets the logger
/// Gets the logger
/// </summary>
protected ILogger<EntityRepositoryBase<TId, TEntity>> Logger { get; }
/// <summary>
/// Gets the isolated cache for the <see cref="TEntity"/>
/// Gets the isolated cache for the <see cref="TEntity" />
/// </summary>
protected IAppPolicyCache GlobalIsolatedCache => AppCaches.IsolatedCaches.GetOrCreate<TEntity>();
/// <summary>
/// Gets the isolated cache.
/// Gets the isolated cache.
/// </summary>
/// <remarks>Depends on the ambient scope cache mode.</remarks>
protected IAppPolicyCache IsolatedCache
@@ -67,19 +67,20 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
}
/// <summary>
/// Gets the default <see cref="RepositoryCachePolicyOptions"/>
/// Gets the default <see cref="RepositoryCachePolicyOptions" />
/// </summary>
protected virtual RepositoryCachePolicyOptions DefaultOptions => s_defaultOptions ?? (s_defaultOptions
= new RepositoryCachePolicyOptions(() =>
{
// get count of all entities of current type (TEntity) to ensure cached result is correct
// create query once if it is needed (no need for locking here) - query is static!
IQuery<TEntity> query = _hasIdQuery ?? (_hasIdQuery = AmbientScope.SqlContext.Query<TEntity>().Where(x => x.Id != 0));
return PerformCount(query);
}));
= new RepositoryCachePolicyOptions(() =>
{
// get count of all entities of current type (TEntity) to ensure cached result is correct
// create query once if it is needed (no need for locking here) - query is static!
IQuery<TEntity> query = _hasIdQuery ??
(_hasIdQuery = AmbientScope.SqlContext.Query<TEntity>().Where(x => x.Id != 0));
return PerformCount(query);
}));
/// <summary>
/// Gets the repository cache policy
/// Gets the repository cache policy
/// </summary>
protected IRepositoryCachePolicy<TEntity, TId> CachePolicy
{
@@ -110,21 +111,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
}
/// <summary>
/// Get the entity id for the <see cref="TEntity"/>
/// Adds or Updates an entity of type TEntity
/// </summary>
protected virtual TId GetEntityId(TEntity entity)
=> (TId)(object)entity.Id;
/// <summary>
/// Create the repository cache policy
/// </summary>
protected virtual IRepositoryCachePolicy<TEntity, TId> CreateCachePolicy()
=> new DefaultRepositoryCachePolicy<TEntity, TId>(GlobalIsolatedCache, ScopeAccessor, DefaultOptions);
/// <summary>
/// Adds or Updates an entity of type TEntity
/// </summary>
/// <remarks>This method is backed by an <see cref="IAppPolicyCache"/> cache</remarks>
/// <remarks>This method is backed by an <see cref="IAppPolicyCache" /> cache</remarks>
public virtual void Save(TEntity entity)
{
if (entity.HasIdentity == false)
@@ -138,11 +127,77 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
}
/// <summary>
/// Deletes the passed in entity
/// Deletes the passed in entity
/// </summary>
public virtual void Delete(TEntity entity)
=> CachePolicy.Delete(entity, PersistDeletedItem);
/// <summary>
/// Gets an entity by the passed in Id utilizing the repository's cache policy
/// </summary>
public TEntity Get(TId id)
=> CachePolicy.Get(id, PerformGet, PerformGetAll);
/// <summary>
/// Gets all entities of type TEntity or a list according to the passed in Ids
/// </summary>
public IEnumerable<TEntity> GetMany(params TId[] ids)
{
// ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries
ids = ids.Distinct()
// don't query by anything that is a default of T (like a zero)
// TODO: I think we should enabled this in case accidental calls are made to get all with invalid ids
// .Where(x => Equals(x, default(TId)) == false)
.ToArray();
// can't query more than 2000 ids at a time... but if someone is really querying 2000+ entities,
// the additional overhead of fetching them in groups is minimal compared to the lookup time of each group
if (ids.Length <= Constants.Sql.MaxParameterCount)
{
return CachePolicy.GetAll(ids, PerformGetAll);
}
var entities = new List<TEntity>();
foreach (IEnumerable<TId> group in ids.InGroupsOf(Constants.Sql.MaxParameterCount))
{
entities.AddRange(CachePolicy.GetAll(group.ToArray(), PerformGetAll));
}
return entities;
}
/// <summary>
/// Gets a list of entities by the passed in query
/// </summary>
public IEnumerable<TEntity> Get(IQuery<TEntity> query)
=> PerformGetByQuery(query)
.WhereNotNull(); // ensure we don't include any null refs in the returned collection!
/// <summary>
/// Returns a boolean indicating whether an entity with the passed Id exists
/// </summary>
public bool Exists(TId id)
=> CachePolicy.Exists(id, PerformExists, PerformGetAll);
/// <summary>
/// Returns an integer with the count of entities found with the passed in query
/// </summary>
public int Count(IQuery<TEntity> query)
=> PerformCount(query);
/// <summary>
/// Get the entity id for the <see cref="TEntity" />
/// </summary>
protected virtual TId GetEntityId(TEntity entity)
=> (TId)(object)entity.Id;
/// <summary>
/// Create the repository cache policy
/// </summary>
protected virtual IRepositoryCachePolicy<TEntity, TId> CreateCachePolicy()
=> new DefaultRepositoryCachePolicy<TEntity, TId>(GlobalIsolatedCache, ScopeAccessor, DefaultOptions);
protected abstract TEntity PerformGet(TId id);
protected abstract IEnumerable<TEntity> PerformGetAll(params TId[] ids);
@@ -162,24 +217,24 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
protected virtual bool PerformExists(TId id)
{
var sql = GetBaseQuery(true);
sql.Where(GetBaseWhereClause(), new { id = id });
Sql<ISqlContext> sql = GetBaseQuery(true);
sql.Where(GetBaseWhereClause(), new { id });
var count = Database.ExecuteScalar<int>(sql);
return count == 1;
}
protected virtual int PerformCount(IQuery<TEntity> query)
{
var sqlClause = GetBaseQuery(true);
Sql<ISqlContext> sqlClause = GetBaseQuery(true);
var translator = new SqlTranslator<TEntity>(sqlClause, query);
var sql = translator.Translate();
Sql<ISqlContext> sql = translator.Translate();
return Database.ExecuteScalar<int>(sql);
}
protected virtual void PersistDeletedItem(TEntity entity)
{
var deletes = GetDeleteClauses();
IEnumerable<string> deletes = GetDeleteClauses();
foreach (var delete in deletes)
{
Database.Execute(delete, new { id = GetEntityId(entity) });
@@ -187,59 +242,5 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
entity.DeleteDate = DateTime.Now;
}
/// <summary>
/// Gets an entity by the passed in Id utilizing the repository's cache policy
/// </summary>
public TEntity Get(TId id)
=> CachePolicy.Get(id, PerformGet, PerformGetAll);
/// <summary>
/// Gets all entities of type TEntity or a list according to the passed in Ids
/// </summary>
public IEnumerable<TEntity> GetMany(params TId[] ids)
{
// ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries
ids = ids.Distinct()
// don't query by anything that is a default of T (like a zero)
// TODO: I think we should enabled this in case accidental calls are made to get all with invalid ids
// .Where(x => Equals(x, default(TId)) == false)
.ToArray();
// can't query more than 2000 ids at a time... but if someone is really querying 2000+ entities,
// the additional overhead of fetching them in groups is minimal compared to the lookup time of each group
if (ids.Length <= Constants.Sql.MaxParameterCount)
{
return CachePolicy.GetAll(ids, PerformGetAll);
}
var entities = new List<TEntity>();
foreach (var group in ids.InGroupsOf(Constants.Sql.MaxParameterCount))
{
entities.AddRange(CachePolicy.GetAll(group.ToArray(), PerformGetAll));
}
return entities;
}
/// <summary>
/// Gets a list of entities by the passed in query
/// </summary>
public IEnumerable<TEntity> Get(IQuery<TEntity> query)
=> PerformGetByQuery(query)
.WhereNotNull(); // ensure we don't include any null refs in the returned collection!
/// <summary>
/// Returns a boolean indicating whether an entity with the passed Id exists
/// </summary>
public bool Exists(TId id)
=> CachePolicy.Exists(id, PerformExists, PerformGetAll);
/// <summary>
/// Returns an integer with the count of entities found with the passed in query
/// </summary>
public int Count(IQuery<TEntity> query)
=> PerformCount(query);
}
}