Merge branch 'temp-RepoCachePerf' into dev-v7

This commit is contained in:
Shannon
2016-01-28 15:16:02 +01:00
14 changed files with 314 additions and 376 deletions

View File

@@ -18,7 +18,9 @@ namespace Umbraco.Core.Cache
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : DefaultRepositoryCachePolicy<TEntity, TId>
where TEntity : class, IAggregateRoot
{
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache) : base(cache,
private readonly Func<TEntity, TId> _getEntityId;
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func<TEntity, TId> getEntityId) : base(cache,
new RepositoryCachePolicyOptions
{
//Definitely allow zero'd cache entires since this is a full set, in many cases there will be none,
@@ -26,10 +28,25 @@ namespace Umbraco.Core.Cache
GetAllCacheAllowZeroCount = true
})
{
_getEntityId = getEntityId;
}
private bool? _hasZeroCountCache;
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
{
//process the base logic without any Ids - we want to cache them all!
var result = base.GetAll(new TId[] { }, getFromRepo);
//now that the base result has been calculated, they will all be cached.
// Now we can just filter by ids if they have been supplied
return ids.Any()
? result.Where(x => ids.Contains(_getEntityId(x))).ToArray()
: result;
}
/// <summary>
/// For this type of caching policy, we don't cache individual items
/// </summary>

View File

@@ -1,3 +1,4 @@
using System;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
@@ -11,15 +12,17 @@ namespace Umbraco.Core.Cache
where TEntity : class, IAggregateRoot
{
private readonly IRuntimeCacheProvider _runtimeCache;
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache)
private readonly Func<TEntity, TId> _getEntityId;
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, Func<TEntity, TId> getEntityId)
{
_runtimeCache = runtimeCache;
_runtimeCache = runtimeCache;
_getEntityId = getEntityId;
}
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
{
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache);
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _getEntityId);
}
}
}

View File

@@ -53,6 +53,9 @@ namespace Umbraco.Core.Models
/// <summary>
/// Gets or sets the alias of the default Template.
/// TODO: This should be ignored from cloning!!!!!!!!!!!!!!
/// - but to do that we have to implement callback hacks, this needs to be fixed in v8,
/// we should not store direct entity
/// </summary>
[IgnoreDataMember]
public ITemplate DefaultTemplate
@@ -79,6 +82,9 @@ namespace Umbraco.Core.Models
/// <summary>
/// Gets or Sets a list of Templates which are allowed for the ContentType
/// TODO: This should be ignored from cloning!!!!!!!!!!!!!!
/// - but to do that we have to implement callback hacks, this needs to be fixed in v8,
/// we should not store direct entity
/// </summary>
[DataMember]
public IEnumerable<ITemplate> AllowedTemplates

View File

@@ -584,14 +584,13 @@ AND umbracoNode.id <> @id",
}
}
public static IEnumerable<IMediaType> GetMediaTypes<TRepo, TId>(
TId[] mediaTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
public static IEnumerable<IMediaType> GetMediaTypes<TRepo>(
Database db, ISqlSyntaxProvider sqlSyntax,
TRepo contentTypeRepository)
where TRepo : IReadRepository<TId, TEntity>
where TId: struct
where TRepo : IReadRepository<int, TEntity>
{
IDictionary<TId, IEnumerable<TId>> allParentMediaTypeIds;
var mediaTypes = MapMediaTypes(mediaTypeIds, db, sqlSyntax, out allParentMediaTypeIds)
IDictionary<int, List<int>> allParentMediaTypeIds;
var mediaTypes = MapMediaTypes(db, sqlSyntax, out allParentMediaTypeIds)
.ToArray();
MapContentTypeChildren(mediaTypes, db, sqlSyntax, contentTypeRepository, allParentMediaTypeIds);
@@ -599,16 +598,15 @@ AND umbracoNode.id <> @id",
return mediaTypes;
}
public static IEnumerable<IContentType> GetContentTypes<TRepo, TId>(
TId[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
public static IEnumerable<IContentType> GetContentTypes<TRepo>(
Database db, ISqlSyntaxProvider sqlSyntax,
TRepo contentTypeRepository,
ITemplateRepository templateRepository)
where TRepo : IReadRepository<TId, TEntity>
where TId : struct
where TRepo : IReadRepository<int, TEntity>
{
IDictionary<TId, IEnumerable<AssociatedTemplate>> allAssociatedTemplates;
IDictionary<TId, IEnumerable<TId>> allParentContentTypeIds;
var contentTypes = MapContentTypes(contentTypeIds, db, sqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
IDictionary<int, List<AssociatedTemplate>> allAssociatedTemplates;
IDictionary<int, List<int>> allParentContentTypeIds;
var contentTypes = MapContentTypes(db, sqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
.ToArray();
if (contentTypes.Any())
@@ -623,12 +621,11 @@ AND umbracoNode.id <> @id",
return contentTypes;
}
internal static void MapContentTypeChildren<TRepo, TId>(IContentTypeComposition[] contentTypes,
internal static void MapContentTypeChildren<TRepo>(IContentTypeComposition[] contentTypes,
Database db, ISqlSyntaxProvider sqlSyntax,
TRepo contentTypeRepository,
IDictionary<TId, IEnumerable<TId>> allParentContentTypeIds)
where TRepo : IReadRepository<TId, TEntity>
where TId : struct
IDictionary<int, List<int>> allParentContentTypeIds)
where TRepo : IReadRepository<int, TEntity>
{
//NOTE: SQL call #2
@@ -650,20 +647,20 @@ AND umbracoNode.id <> @id",
var allParentIdsAsArray = allParentContentTypeIds.SelectMany(x => x.Value).Distinct().ToArray();
if (allParentIdsAsArray.Any())
{
var allParentContentTypes = contentTypeRepository.GetAll(allParentIdsAsArray).ToArray();
//NO!!!!!!!!!!! Do not recurse lookup, we've already looked them all up
//var allParentContentTypes = contentTypeRepository.GetAll(allParentIdsAsArray).ToArray();
var allParentContentTypes = contentTypes.Where(x => allParentIdsAsArray.Contains(x.Id)).ToArray();
foreach (var contentType in contentTypes)
{
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
var entityId = typeof(TId) == typeof(int) ? contentType.Id : (object)contentType.Key;
var entityId = contentType.Id;
var parentContentTypes = allParentContentTypes.Where(x =>
{
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
var parentEntityId = typeof(TId) == typeof(int) ? x.Id : (object)x.Key;
{
var parentEntityId = x.Id;
return allParentContentTypeIds[(TId)entityId].Contains((TId)parentEntityId);
return allParentContentTypeIds[entityId].Contains(parentEntityId);
});
foreach (var parentContentType in parentContentTypes)
{
@@ -681,13 +678,12 @@ AND umbracoNode.id <> @id",
}
internal static void MapContentTypeTemplates<TRepo, TId>(IContentType[] contentTypes,
internal static void MapContentTypeTemplates<TRepo>(IContentType[] contentTypes,
Database db,
TRepo contentTypeRepository,
ITemplateRepository templateRepository,
IDictionary<TId, IEnumerable<AssociatedTemplate>> associatedTemplates)
where TRepo : IReadRepository<TId, TEntity>
where TId: struct
IDictionary<int, List<AssociatedTemplate>> associatedTemplates)
where TRepo : IReadRepository<int, TEntity>
{
if (associatedTemplates == null || associatedTemplates.Any() == false) return;
@@ -704,11 +700,9 @@ AND umbracoNode.id <> @id",
foreach (var contentType in contentTypes)
{
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
var entityId = typeof(TId) == typeof(int) ? contentType.Id : (object)contentType.Key;
var entityId = contentType.Id;
var associatedTemplateIds = associatedTemplates[(TId)entityId].Select(x => x.TemplateId)
var associatedTemplateIds = associatedTemplates[entityId].Select(x => x.TemplateId)
.Distinct()
.ToArray();
@@ -720,15 +714,10 @@ AND umbracoNode.id <> @id",
}
internal static IEnumerable<IMediaType> MapMediaTypes<TId>(TId[] mediaTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<TId, IEnumerable<TId>> parentMediaTypeIds)
where TId : struct
{
Mandate.That(mediaTypeIds.Any(), () => new InvalidOperationException("must be at least one content type id specified"));
Mandate.ParameterNotNull(db, "db");
//ensure they are unique
mediaTypeIds = mediaTypeIds.Distinct().ToArray();
internal static IEnumerable<IMediaType> MapMediaTypes(Database db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<int, List<int>> parentMediaTypeIds)
{
Mandate.ParameterNotNull(db, "db");
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
@@ -754,27 +743,10 @@ AND umbracoNode.id <> @id",
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
) ParentTypes
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
if (mediaTypeIds.Any())
{
//TODO: This is all sorts of hacky but i don't have time to refactor a lot to get both ints and guids working nicely... this will
// work for the time being.
if (typeof(TId) == typeof(int))
{
sql = sql + " AND (umbracoNode.id IN (@contentTypeIds))";
}
else if (typeof(TId) == typeof(Guid))
{
sql = sql + " AND (umbracoNode.uniqueID IN (@contentTypeIds))";
}
}
//NOTE: we are going to assume there's not going to be more than 2100 content type ids since that is the max SQL param count!
if ((mediaTypeIds.Length - 1) > 2000)
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.MediaType), contentTypeIds = mediaTypeIds });
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
ORDER BY ctId";
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.MediaType) });
if (result.Any() == false)
{
@@ -782,87 +754,109 @@ AND umbracoNode.id <> @id",
return Enumerable.Empty<IMediaType>();
}
parentMediaTypeIds = new Dictionary<TId, IEnumerable<TId>>();
parentMediaTypeIds = new Dictionary<int, List<int>>();
var mappedMediaTypes = new List<IMediaType>();
foreach (var contentTypeId in mediaTypeIds)
//loop through each result and fill in our required values, each row will contain different requried data than the rest.
// it is much quicker to iterate each result and populate instead of looking up the values over and over in the result like
// we used to do.
var queue = new Queue<dynamic>(result);
var currAllowedContentTypes = new List<ContentTypeSort>();
while (queue.Count > 0)
{
//the current content type id that we're working with
var currentCtId = contentTypeId;
//first we want to get the main content type data this is 1 : 1 with umbraco node data
var ct = result
.Where(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof (TId) == typeof (int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
.Select(x => new { x.ctPk, x.ctId, x.ctAlias, x.ctAllowAtRoot, x.ctDesc, x.ctIcon, x.ctIsContainer, x.ctThumb, x.nName, x.nCreateDate, x.nLevel, x.nObjectType, x.nUser, x.nParentId, x.nPath, x.nSortOrder, x.nTrashed, x.nUniqueId })
.DistinctBy(x => (int)x.ctId)
.FirstOrDefault();
if (ct == null)
var ct = queue.Dequeue();
//check for allowed content types
int? allowedCtId = ct.ctaAllowedId;
int? allowedCtSort = ct.ctaSortOrder;
string allowedCtAlias = ct.ctaAlias;
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
{
continue;
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
if (currAllowedContentTypes.Contains(ctSort) == false)
{
currAllowedContentTypes.Add(ctSort);
}
}
var contentTypeDto = new ContentTypeDto
//always ensure there's a list for this content type
if (parentMediaTypeIds.ContainsKey(ct.ctId) == false)
parentMediaTypeIds[ct.ctId] = new List<int>();
//check for parent ids and assign to the outgoing collection
int? parentId = ct.chtParentId;
if (parentId.HasValue)
{
Alias = ct.ctAlias,
AllowAtRoot = ct.ctAllowAtRoot,
Description = ct.ctDesc,
Icon = ct.ctIcon,
IsContainer = ct.ctIsContainer,
NodeId = ct.ctId,
PrimaryKey = ct.ctPk,
Thumbnail = ct.ctThumb,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = ct.nCreateDate,
Level = (short)ct.nLevel,
NodeId = ct.ctId,
NodeObjectType = ct.nObjectType,
ParentId = ct.nParentId,
Path = ct.nPath,
SortOrder = ct.nSortOrder,
Text = ct.nName,
Trashed = ct.nTrashed,
UniqueId = ct.nUniqueId,
UserId = ct.nUser
}
};
var associatedParentIds = parentMediaTypeIds[ct.ctId];
if (associatedParentIds.Contains(parentId.Value) == false)
associatedParentIds.Add(parentId.Value);
}
//now create the media type object
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
{
//it's the last in the queue or the content type is changing (moving to the next one)
var mediaType = CreateForMapping(ct, currAllowedContentTypes);
mappedMediaTypes.Add(mediaType);
var factory = new ContentTypeFactory();
var mediaType = factory.BuildMediaTypeEntity(contentTypeDto);
//map the allowed content types
//map the child content type ids
MapCommonContentTypeObjects(mediaType, currentCtId, result, parentMediaTypeIds);
mappedMediaTypes.Add(mediaType);
}
//Here we need to reset the current variables, we're now collecting data for a different content type
currAllowedContentTypes = new List<ContentTypeSort>();
}
}
return mappedMediaTypes;
}
internal static IEnumerable<IContentType> MapContentTypes<TId>(TId[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<TId, IEnumerable<AssociatedTemplate>> associatedTemplates,
out IDictionary<TId, IEnumerable<TId>> parentContentTypeIds)
where TId : struct
private static IMediaType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes)
{
// * create the DTO object
// * create the content type object
// * map the allowed content types
// * add to the outgoing list
var contentTypeDto = new ContentTypeDto
{
Alias = currCt.ctAlias,
AllowAtRoot = currCt.ctAllowAtRoot,
Description = currCt.ctDesc,
Icon = currCt.ctIcon,
IsContainer = currCt.ctIsContainer,
NodeId = currCt.ctId,
PrimaryKey = currCt.ctPk,
Thumbnail = currCt.ctThumb,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = currCt.nCreateDate,
Level = (short)currCt.nLevel,
NodeId = currCt.ctId,
NodeObjectType = currCt.nObjectType,
ParentId = currCt.nParentId,
Path = currCt.nPath,
SortOrder = currCt.nSortOrder,
Text = currCt.nName,
Trashed = currCt.nTrashed,
UniqueId = currCt.nUniqueId,
UserId = currCt.nUser
}
};
//now create the content type object
var factory = new ContentTypeFactory();
var mediaType = factory.BuildMediaTypeEntity(contentTypeDto);
//map the allowed content types
mediaType.AllowedContentTypes = currAllowedContentTypes;
return mediaType;
}
internal static IEnumerable<IContentType> MapContentTypes(Database db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<int, List<AssociatedTemplate>> associatedTemplates,
out IDictionary<int, List<int>> parentContentTypeIds)
{
Mandate.ParameterNotNull(db, "db");
//ensure they are unique
contentTypeIds = contentTypeIds.Distinct().ToArray();
var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId,
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
@@ -897,28 +891,10 @@ AND umbracoNode.id <> @id",
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
) ParentTypes
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
if (contentTypeIds.Any())
{
//TODO: This is all sorts of hacky but i don't have time to refactor a lot to get both ints and guids working nicely... this will
// work for the time being.
if (typeof(TId) == typeof(int))
{
sql = sql + " AND (umbracoNode.id IN (@contentTypeIds))";
}
else if (typeof(TId) == typeof(Guid))
{
sql = sql + " AND (umbracoNode.uniqueID IN (@contentTypeIds))";
}
}
//NOTE: we are going to assume there's not going to be more than 2100 content type ids since that is the max SQL param count!
if ((contentTypeIds.Length - 1) > 2000)
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), contentTypeIds = contentTypeIds });
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
ORDER BY ctId";
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType)});
if (result.Any() == false)
{
@@ -927,170 +903,139 @@ AND umbracoNode.id <> @id",
return Enumerable.Empty<IContentType>();
}
parentContentTypeIds = new Dictionary<TId, IEnumerable<TId>>();
associatedTemplates = new Dictionary<TId, IEnumerable<AssociatedTemplate>>();
parentContentTypeIds = new Dictionary<int, List<int>>();
associatedTemplates = new Dictionary<int, List<AssociatedTemplate>>();
var mappedContentTypes = new List<IContentType>();
foreach (var contentTypeId in contentTypeIds)
var queue = new Queue<dynamic>(result);
var currDefaultTemplate = -1;
var currAllowedContentTypes = new List<ContentTypeSort>();
while (queue.Count > 0)
{
//the current content type id that we're working with
var ct = queue.Dequeue();
var currentCtId = contentTypeId;
//first we want to get the main content type data this is 1 : 1 with umbraco node data
var ct = result
.Where(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
.Select(x => new { x.ctPk, x.ctId, x.ctAlias, x.ctAllowAtRoot, x.ctDesc, x.ctIcon, x.ctIsContainer, x.ctThumb, x.nName, x.nCreateDate, x.nLevel, x.nObjectType, x.nUser, x.nParentId, x.nPath, x.nSortOrder, x.nTrashed, x.nUniqueId })
.DistinctBy(x => (int)x.ctId)
.FirstOrDefault();
if (ct == null)
//check for default templates
bool? isDefaultTemplate = Convert.ToBoolean(ct.dtIsDefault);
int? templateId = ct.dtTemplateId;
if (currDefaultTemplate == -1 && isDefaultTemplate.HasValue && templateId.HasValue)
{
continue;
currDefaultTemplate = templateId.Value;
}
//get the unique list of associated templates
var defaultTemplates = result
.Where(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
//use a tuple so that distinct checks both values (in some rare cases the dtIsDefault will not compute as bool?, so we force it with Convert.ToBoolean)
.Select(x => new Tuple<bool?, int?>(Convert.ToBoolean(x.dtIsDefault), x.dtTemplateId))
.Where(x => x.Item1.HasValue && x.Item2.HasValue)
.Distinct()
.OrderByDescending(x => x.Item1.Value)
.ToArray();
//if there isn't one set to default explicitly, we'll pick the first one
var defaultTemplate = defaultTemplates.FirstOrDefault(x => x.Item1.Value)
?? defaultTemplates.FirstOrDefault();
//always ensure there's a list for this content type
if (associatedTemplates.ContainsKey(ct.ctId) == false)
associatedTemplates[ct.ctId] = new List<AssociatedTemplate>();
var dtDto = new ContentTypeTemplateDto
//check for associated templates and assign to the outgoing collection
if (ct.tId != null)
{
//create the content type dto
ContentTypeDto = new ContentTypeDto
var associatedTemplate = new AssociatedTemplate(ct.tId, ct.tAlias, ct.tText);
var associatedList = associatedTemplates[ct.ctId];
if (associatedList.Contains(associatedTemplate) == false)
associatedList.Add(associatedTemplate);
}
//check for allowed content types
int? allowedCtId = ct.ctaAllowedId;
int? allowedCtSort = ct.ctaSortOrder;
string allowedCtAlias = ct.ctaAlias;
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
{
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
if (currAllowedContentTypes.Contains(ctSort) == false)
{
Alias = ct.ctAlias,
AllowAtRoot = ct.ctAllowAtRoot,
Description = ct.ctDesc,
Icon = ct.ctIcon,
IsContainer = ct.ctIsContainer,
NodeId = ct.ctId,
PrimaryKey = ct.ctPk,
Thumbnail = ct.ctThumb,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = ct.nCreateDate,
Level = (short)ct.nLevel,
NodeId = ct.ctId,
NodeObjectType = ct.nObjectType,
ParentId = ct.nParentId,
Path = ct.nPath,
SortOrder = ct.nSortOrder,
Text = ct.nName,
Trashed = ct.nTrashed,
UniqueId = ct.nUniqueId,
UserId = ct.nUser
}
},
ContentTypeNodeId = ct.ctId,
IsDefault = defaultTemplate != null,
TemplateNodeId = defaultTemplate != null ? defaultTemplate.Item2.Value : 0,
};
currAllowedContentTypes.Add(ctSort);
}
}
// We will map a subset of the associated template - alias, id, name
//always ensure there's a list for this content type
if (parentContentTypeIds.ContainsKey(ct.ctId) == false)
parentContentTypeIds[ct.ctId] = new List<int>();
associatedTemplates.Add(currentCtId, result
.Where(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
.Where(x => x.tId != null)
.Select(x => new AssociatedTemplate(x.tId, x.tAlias, x.tText))
.Distinct()
.ToArray());
//check for parent ids and assign to the outgoing collection
int? parentId = ct.chtParentId;
if (parentId.HasValue)
{
var associatedParentIds = parentContentTypeIds[ct.ctId];
//now create the content type object
if (associatedParentIds.Contains(parentId.Value) == false)
associatedParentIds.Add(parentId.Value);
}
var factory = new ContentTypeFactory();
var contentType = factory.BuildContentTypeEntity(dtDto.ContentTypeDto);
// NOTE
// that was done by the factory but makes little sense, moved here, so
// now we have to reset dirty props again (as the factory does it) and yet,
// we are not managing allowed templates... the whole thing is weird.
((ContentType) contentType).DefaultTemplateId = dtDto.TemplateNodeId;
contentType.ResetDirtyProperties(false);
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
{
//it's the last in the queue or the content type is changing (moving to the next one)
var contentType = CreateForMapping(ct, currAllowedContentTypes, currDefaultTemplate);
mappedContentTypes.Add(contentType);
//map the allowed content types
//map the child content type ids
MapCommonContentTypeObjects(contentType, currentCtId, result, parentContentTypeIds);
mappedContentTypes.Add(contentType);
//Here we need to reset the current variables, we're now collecting data for a different content type
currDefaultTemplate = -1;
currAllowedContentTypes = new List<ContentTypeSort>();
}
}
return mappedContentTypes;
}
private static void MapCommonContentTypeObjects<T, TId>(T contentType, TId currentCtId, List<dynamic> result, IDictionary<TId, IEnumerable<TId>> parentContentTypeIds)
where T : IContentTypeBase
where TId : struct
private static IContentType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes, int currDefaultTemplate)
{
//map the allowed content types
contentType.AllowedContentTypes = result
.Where(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
//use tuple so we can use distinct on all vals
.Select(x => new Tuple<int?, int?, string>(x.ctaAllowedId, x.ctaSortOrder, x.ctaAlias))
.Where(x => x.Item1.HasValue && x.Item2.HasValue && x.Item3 != null)
.Distinct()
.Select(x => new ContentTypeSort(new Lazy<int>(() => x.Item1.Value), x.Item2.Value, x.Item3))
.ToList();
// * set the default template to the first one if a default isn't found
// * create the DTO object
// * create the content type object
// * map the allowed content types
// * add to the outgoing list
//map the child content type ids
parentContentTypeIds.Add(currentCtId, result
.Where(x =>
var dtDto = new ContentTypeTemplateDto
{
//create the content type dto
ContentTypeDto = new ContentTypeDto
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
.Select(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? (TId?)x.chtParentId
: (TId?)x.chtParentKey;
})
.Where(x => x.HasValue)
.Distinct()
.Select(x => x.Value).ToList());
Alias = currCt.ctAlias,
AllowAtRoot = currCt.ctAllowAtRoot,
Description = currCt.ctDesc,
Icon = currCt.ctIcon,
IsContainer = currCt.ctIsContainer,
NodeId = currCt.ctId,
PrimaryKey = currCt.ctPk,
Thumbnail = currCt.ctThumb,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = currCt.nCreateDate,
Level = (short)currCt.nLevel,
NodeId = currCt.ctId,
NodeObjectType = currCt.nObjectType,
ParentId = currCt.nParentId,
Path = currCt.nPath,
SortOrder = currCt.nSortOrder,
Text = currCt.nName,
Trashed = currCt.nTrashed,
UniqueId = currCt.nUniqueId,
UserId = currCt.nUser
}
},
ContentTypeNodeId = currCt.ctId,
IsDefault = currDefaultTemplate != -1,
TemplateNodeId = currDefaultTemplate != -1 ? currDefaultTemplate : 0,
};
//now create the content type object
var factory = new ContentTypeFactory();
var contentType = factory.BuildContentTypeEntity(dtDto.ContentTypeDto);
// NOTE
// that was done by the factory but makes little sense, moved here, so
// now we have to reset dirty props again (as the factory does it) and yet,
// we are not managing allowed templates... the whole thing is weird.
((ContentType)contentType).DefaultTemplateId = dtDto.TemplateNodeId;
contentType.ResetDirtyProperties(false);
//map the allowed content types
contentType.AllowedContentTypes = currAllowedContentTypes;
return contentType;
}
internal static void MapGroupsAndProperties(int[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,

View File

@@ -37,7 +37,7 @@ namespace Umbraco.Core.Persistence.Repositories
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IContentType, int>(RuntimeCache));
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IContentType, int>(RuntimeCache, GetEntityId));
}
}
@@ -51,14 +51,12 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (ids.Any())
{
return ContentTypeQueryMapper.GetContentTypes(ids, Database, SqlSyntax, this, _templateRepository);
}
else
{
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
var allIds = Database.Fetch<int>(sql).ToArray();
return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
//NOTE: This logic should never be executed according to our cache policy
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, this, _templateRepository)
.Where(x => ids.Contains(x.Id));
}
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, this, _templateRepository);
}
protected override IEnumerable<IContentType> PerformGetByQuery(IQuery<IContentType> query)
@@ -300,9 +298,6 @@ namespace Umbraco.Core.Persistence.Repositories
else
{
return GetAll();
//var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
//var allIds = Database.Fetch<int>(sql).ToArray();
//return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
}
}

View File

@@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Repositories
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IDomain, int>(RuntimeCache));
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IDomain, int>(RuntimeCache, GetEntityId));
}
}

View File

@@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ILanguage, int>(RuntimeCache));
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ILanguage, int>(RuntimeCache, GetEntityId));
}
}

View File

@@ -34,31 +34,26 @@ namespace Umbraco.Core.Persistence.Repositories
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMediaType, int>(RuntimeCache));
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMediaType, int>(RuntimeCache, GetEntityId));
}
}
protected override IMediaType PerformGet(int id)
{
var contentTypes = ContentTypeQueryMapper.GetMediaTypes(
new[] { id }, Database, SqlSyntax, this);
var contentType = contentTypes.SingleOrDefault();
return contentType;
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Id == id);
}
protected override IEnumerable<IMediaType> PerformGetAll(params int[] ids)
{
if (ids.Any())
{
return ContentTypeQueryMapper.GetMediaTypes(ids, Database, SqlSyntax, this);
}
else
{
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
var allIds = Database.Fetch<int>(sql).ToArray();
return ContentTypeQueryMapper.GetMediaTypes(allIds, Database, SqlSyntax, this);
//NOTE: This logic should never be executed according to our cache policy
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, this)
.Where(x => ids.Contains(x.Id));
}
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, this);
}
protected override IEnumerable<IMediaType> PerformGetByQuery(IQuery<IMediaType> query)
@@ -178,9 +173,6 @@ namespace Umbraco.Core.Persistence.Repositories
else
{
return GetAll();
//var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
//var allIds = Database.Fetch<int>(sql).ToArray();
//return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
}
}

View File

@@ -33,29 +33,14 @@ namespace Umbraco.Core.Persistence.Repositories
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMemberType, int>(RuntimeCache));
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMemberType, int>(RuntimeCache, GetEntityId));
}
}
#region Overrides of RepositoryBase<int, IMemberType>
protected override IMemberType PerformGet(int id)
{
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
var dtos =
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
new PropertyTypePropertyGroupRelator().Map, sql);
if (dtos == null || dtos.Any() == false)
return null;
var factory = new MemberTypeReadOnlyFactory();
var member = factory.BuildEntity(dtos.First());
return member;
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Id == id);
}
protected override IEnumerable<IMemberType> PerformGetAll(params int[] ids)
@@ -63,10 +48,11 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = GetBaseQuery(false);
if (ids.Any())
{
//NOTE: This logic should never be executed according to our cache policy
var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.id='{0}'", x)));
sql.Where(statement);
}
sql.OrderByDescending<NodeDto>(x => x.NodeId);
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
var dtos =
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
@@ -82,7 +68,7 @@ namespace Umbraco.Core.Persistence.Repositories
var subquery = translator.Translate();
var sql = GetBaseQuery(false)
.Append(new Sql("WHERE umbracoNode.id IN (" + subquery.SQL + ")", subquery.Arguments))
.OrderBy<NodeDto>(x => x.SortOrder);
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
var dtos =
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
@@ -90,11 +76,7 @@ namespace Umbraco.Core.Persistence.Repositories
return BuildFromDtos(dtos);
}
#endregion
#region Overrides of PetaPocoRepositoryBase<int, IMemberType>
protected override Sql GetBaseQuery(bool isCount)
{
var sql = new Sql();
@@ -168,11 +150,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
get { return new Guid(Constants.ObjectTypes.MemberType); }
}
#endregion
#region Unit of Work Implementation
protected override void PersistNewItem(IMemberType entity)
{
ValidateAlias(entity);
@@ -243,8 +221,6 @@ namespace Umbraco.Core.Persistence.Repositories
entity.ResetDirtyProperties();
}
#endregion
/// <summary>
/// Override so we can specify explicit db type's on any property types that are built-in.
@@ -282,9 +258,6 @@ namespace Umbraco.Core.Persistence.Repositories
else
{
return GetAll();
//var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
//var allIds = Database.Fetch<int>(sql).ToArray();
//return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
}
}

View File

@@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence.Repositories
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid>(RuntimeCache));
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid>(RuntimeCache, GetEntityId));
}
}

View File

@@ -82,7 +82,11 @@ namespace Umbraco.Core.Persistence.Repositories
{
}
protected virtual TId GetEntityId(TEntity entity)
{
return (TId)(object)entity.Id;
}
/// <summary>
/// The runtime cache used for this repo by default is the isolated cache for this type
@@ -179,7 +183,8 @@ namespace Umbraco.Core.Persistence.Repositories
using (var p = CachePolicyFactory.CreatePolicy())
{
return p.GetAll(ids, PerformGetAll);
var result = p.GetAll(ids, PerformGetAll);
return result;
}
}

View File

@@ -51,7 +51,7 @@ namespace Umbraco.Core.Persistence.Repositories
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ITemplate, int>(RuntimeCache));
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ITemplate, int>(RuntimeCache, GetEntityId));
}
}

View File

@@ -36,7 +36,7 @@ namespace Umbraco.Tests.Cache
return cached.Any() ? new DeepCloneableList<AuditItem>() : null;
});
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object);
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id);
using (defaultPolicy)
{
var found = defaultPolicy.GetAll(new object[] {}, o => new AuditItem[] {});
@@ -46,7 +46,7 @@ namespace Umbraco.Tests.Cache
Assert.IsNotNull(list);
//Do it again, ensure that its coming from the cache!
defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object);
defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id);
using (defaultPolicy)
{
var found = defaultPolicy.GetAll(new object[] { }, o => new AuditItem[] { });
@@ -73,7 +73,7 @@ namespace Umbraco.Tests.Cache
});
cache.Setup(x => x.GetCacheItem(It.IsAny<string>())).Returns(new AuditItem[] { });
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object);
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id);
using (defaultPolicy)
{
var found = defaultPolicy.GetAll(new object[] { }, o => new[]
@@ -98,7 +98,7 @@ namespace Umbraco.Tests.Cache
new AuditItem(2, "blah2", AuditType.Copy, 123)
});
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object);
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id);
using (defaultPolicy)
{
var found = defaultPolicy.GetAll(new object[] { }, o => new[] { (AuditItem)null });

View File

@@ -55,10 +55,11 @@ namespace Umbraco.Tests.Persistence.Querying
transaction.Complete();
}
IDictionary<int, IEnumerable<ContentTypeRepository.ContentTypeQueryMapper.AssociatedTemplate>> allAssociatedTemplates;
IDictionary<int, IEnumerable<int>> allParentContentTypeIds;
IDictionary<int, List<ContentTypeRepository.ContentTypeQueryMapper.AssociatedTemplate>> allAssociatedTemplates;
IDictionary<int, List<int>> allParentContentTypeIds;
var contentTypes = ContentTypeRepository.ContentTypeQueryMapper.MapContentTypes(
new[] {99997, 99998}, DatabaseContext.Database, SqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
DatabaseContext.Database, SqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
.Where(x => (new[] {99997, 99998}).Contains(x.Id))
.ToArray();
var contentType1 = contentTypes.SingleOrDefault(x => x.Id == 99997);
@@ -109,9 +110,10 @@ namespace Umbraco.Tests.Persistence.Querying
transaction.Complete();
}
IDictionary<int, IEnumerable<int>> allParentContentTypeIds;
IDictionary<int, List<int>> allParentContentTypeIds;
var contentTypes = ContentTypeRepository.ContentTypeQueryMapper.MapMediaTypes(
new[] { 99997, 99998 }, DatabaseContext.Database, SqlSyntax, out allParentContentTypeIds)
DatabaseContext.Database, SqlSyntax, out allParentContentTypeIds)
.Where(x => (new[] { 99997, 99998 }).Contains(x.Id))
.ToArray();
var contentType1 = contentTypes.SingleOrDefault(x => x.Id == 99997);