Updates the versionable repo (content, members, media) to far more efficiently load in property and pre-value data, in fact the performance tests have show that this improves performance even more! The real underlying reason for these changes is so that we don't end up with a giant SQL 'IN' clause for these queries, and that these queries are far faster than IN clause queries.
This commit is contained in:
@@ -75,13 +75,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.Where<DocumentDto>(x => x.Newest)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
|
||||
|
||||
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
|
||||
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var content = CreateContentFromDto(dto, dto.ContentVersionDto.VersionId);
|
||||
var content = CreateContentFromDto(dto, dto.ContentVersionDto.VersionId, sql);
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -93,10 +93,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
sql.Where("umbracoNode.id in (@ids)", new {ids = ids});
|
||||
}
|
||||
else
|
||||
{
|
||||
sql.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
}
|
||||
|
||||
//we only want the newest ones with this method
|
||||
sql.Where<DocumentDto>(x => x.Newest);
|
||||
|
||||
return ProcessQuery(sql);
|
||||
}
|
||||
@@ -178,8 +177,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var content = CreateContentFromDto(dto, versionId);
|
||||
|
||||
var content = CreateContentFromDto(dto, versionId, sql);
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -525,7 +524,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return CreateContentFromDto(dto, dto.VersionId);
|
||||
yield return CreateContentFromDto(dto, dto.VersionId, sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -731,9 +730,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql);
|
||||
|
||||
//content types
|
||||
//NOTE: This should be ok for an SQL 'IN' statement, there shouldn't be an insane amount of content types
|
||||
var contentTypes = _contentTypeRepository.GetAll(dtos.Select(x => x.ContentVersionDto.ContentDto.ContentTypeId).ToArray())
|
||||
.ToArray();
|
||||
|
||||
//NOTE: This should be ok for an SQL 'IN' statement, there shouldn't be an insane amount of content types
|
||||
var templates = _templateRepository.GetAll(
|
||||
dtos
|
||||
.Where(dto => dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
|
||||
@@ -741,19 +742,18 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.ToArray();
|
||||
|
||||
//Go get the property data for each document
|
||||
var docDefs = dtos.Select(dto => new Tuple<int, Guid, IContentTypeComposition, DateTime, DateTime>(
|
||||
var docDefs = dtos.Select(dto => new DocumentDefinition(
|
||||
dto.NodeId,
|
||||
dto.VersionId,
|
||||
contentTypes.First(ct => ct.Id == dto.ContentVersionDto.ContentDto.ContentTypeId),
|
||||
dto.ContentVersionDto.VersionDate,
|
||||
dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
|
||||
dto.ContentVersionDto.VersionDate))
|
||||
contentTypes.First(ct => ct.Id == dto.ContentVersionDto.ContentDto.ContentTypeId)))
|
||||
.ToArray();
|
||||
|
||||
var propertyData = GetPropertyCollection(docDefs);
|
||||
var propertyData = GetPropertyCollection(sql, docDefs);
|
||||
|
||||
return dtos.Select(dto => CreateContentFromDto(
|
||||
dto,
|
||||
dto.ContentVersionDto.VersionId,
|
||||
contentTypes.First(ct => ct.Id == dto.ContentVersionDto.ContentDto.ContentTypeId),
|
||||
templates.FirstOrDefault(tem => tem.Id == (dto.TemplateId.HasValue ? dto.TemplateId.Value : -1)),
|
||||
propertyData[dto.NodeId]));
|
||||
@@ -763,18 +763,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="template"></param>
|
||||
/// <param name="propCollection"></param>
|
||||
/// <returns></returns>
|
||||
private IContent CreateContentFromDto(DocumentDto dto, Guid versionId,
|
||||
IContentType contentType = null,
|
||||
ITemplate template = null,
|
||||
Models.PropertyCollection propCollection = null)
|
||||
private IContent CreateContentFromDto(DocumentDto dto,
|
||||
IContentType contentType,
|
||||
ITemplate template,
|
||||
Models.PropertyCollection propCollection)
|
||||
{
|
||||
contentType = contentType ?? _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
|
||||
|
||||
var factory = new ContentFactory(contentType, NodeObjectTypeId, dto.NodeId);
|
||||
var content = factory.BuildEntity(dto);
|
||||
|
||||
@@ -784,8 +781,39 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
content.Template = template ?? _templateRepository.Get(dto.TemplateId.Value);
|
||||
}
|
||||
|
||||
content.Properties = propCollection ??
|
||||
GetPropertyCollection(dto.NodeId, versionId, contentType, content.CreateDate, content.UpdateDate);
|
||||
content.Properties = propCollection;
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
((Entity)content).ResetDirtyProperties(false);
|
||||
return content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="docSql"></param>
|
||||
/// <returns></returns>
|
||||
private IContent CreateContentFromDto(DocumentDto dto, Guid versionId, Sql docSql)
|
||||
{
|
||||
var contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
|
||||
|
||||
var factory = new ContentFactory(contentType, NodeObjectTypeId, dto.NodeId);
|
||||
var content = factory.BuildEntity(dto);
|
||||
|
||||
//Check if template id is set on DocumentDto, and get ITemplate if it is.
|
||||
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
|
||||
{
|
||||
content.Template = _templateRepository.Get(dto.TemplateId.Value);
|
||||
}
|
||||
|
||||
var docDef = new DocumentDefinition(dto.NodeId, versionId, content.UpdateDate, content.CreateDate, contentType);
|
||||
|
||||
var properties = GetPropertyCollection(docSql, docDef);
|
||||
|
||||
content.Properties = properties[dto.NodeId];
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var content = CreateMediaFromDto(dto, dto.VersionId);
|
||||
var content = CreateMediaFromDto(dto, dto.VersionId, sql);
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -78,10 +78,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
sql.Where("umbracoNode.id in (@ids)", new { ids = ids });
|
||||
}
|
||||
else
|
||||
{
|
||||
sql.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
}
|
||||
|
||||
return ProcessQuery(sql);
|
||||
}
|
||||
@@ -164,7 +160,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var factory = new MediaFactory(mediaType, NodeObjectTypeId, dto.NodeId);
|
||||
var media = factory.BuildEntity(dto);
|
||||
|
||||
media.Properties = GetPropertyCollection(dto.NodeId, dto.VersionId, mediaType, media.CreateDate, media.UpdateDate);
|
||||
var properties = GetPropertyCollection(sql, new DocumentDefinition(dto.NodeId, dto.VersionId, media.UpdateDate, media.CreateDate, mediaType));
|
||||
|
||||
media.Properties = properties[dto.NodeId];
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
@@ -450,19 +448,18 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.ToArray();
|
||||
|
||||
//Go get the property data for each document
|
||||
var docDefs = dtos.Select(dto => new Tuple<int, Guid, IContentTypeComposition, DateTime, DateTime>(
|
||||
var docDefs = dtos.Select(dto => new DocumentDefinition(
|
||||
dto.NodeId,
|
||||
dto.VersionId,
|
||||
contentTypes.First(ct => ct.Id == dto.ContentDto.ContentTypeId),
|
||||
dto.VersionDate,
|
||||
dto.ContentDto.NodeDto.CreateDate,
|
||||
dto.VersionDate))
|
||||
contentTypes.First(ct => ct.Id == dto.ContentDto.ContentTypeId)))
|
||||
.ToArray();
|
||||
|
||||
var propertyData = GetPropertyCollection(docDefs);
|
||||
var propertyData = GetPropertyCollection(sql, docDefs);
|
||||
|
||||
return dtos.Select(dto => CreateMediaFromDto(
|
||||
dto,
|
||||
dto.VersionId,
|
||||
contentTypes.First(ct => ct.Id == dto.ContentDto.ContentTypeId),
|
||||
propertyData[dto.NodeId]));
|
||||
}
|
||||
@@ -497,21 +494,43 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// Private method to create a media object from a ContentDto
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="propCollection"></param>
|
||||
/// <returns></returns>
|
||||
private IMedia CreateMediaFromDto(ContentVersionDto dto, Guid versionId,
|
||||
IMediaType contentType = null,
|
||||
Models.PropertyCollection propCollection = null)
|
||||
private IMedia CreateMediaFromDto(ContentVersionDto dto,
|
||||
IMediaType contentType,
|
||||
PropertyCollection propCollection)
|
||||
{
|
||||
contentType = contentType ?? _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
|
||||
var factory = new MediaFactory(contentType, NodeObjectTypeId, dto.NodeId);
|
||||
var media = factory.BuildEntity(dto);
|
||||
|
||||
media.Properties = propCollection;
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
((Entity)media).ResetDirtyProperties(false);
|
||||
return media;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Private method to create a media object from a ContentDto
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="docSql"></param>
|
||||
/// <returns></returns>
|
||||
private IMedia CreateMediaFromDto(ContentVersionDto dto, Guid versionId, Sql docSql)
|
||||
{
|
||||
var contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
|
||||
|
||||
var factory = new MediaFactory(contentType, NodeObjectTypeId, dto.NodeId);
|
||||
var media = factory.BuildEntity(dto);
|
||||
|
||||
media.Properties = propCollection ??
|
||||
GetPropertyCollection(dto.NodeId, versionId, contentType, media.CreateDate, media.UpdateDate);
|
||||
|
||||
var docDef = new DocumentDefinition(dto.NodeId, versionId, media.UpdateDate, media.CreateDate, contentType);
|
||||
|
||||
var properties = GetPropertyCollection(docSql, docDef);
|
||||
|
||||
media.Properties = properties[dto.NodeId];
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
|
||||
new PropertyDataRelator().Map, sql);
|
||||
|
||||
return BuildFromDto(dtos);
|
||||
return BuildFromDto(dtos, sql);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMember> PerformGetAll(params int[] ids)
|
||||
@@ -82,7 +82,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
|
||||
new PropertyDataRelator().Map, sql);
|
||||
|
||||
return BuildFromDtos(dtos);
|
||||
return BuildFromDtos(dtos, sql);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMember> PerformGetByQuery(IQuery<IMember> query)
|
||||
@@ -99,7 +99,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
|
||||
new PropertyDataRelator().Map, sql);
|
||||
|
||||
return BuildFromDtos(dtos);
|
||||
return BuildFromDtos(dtos, sql);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -439,7 +439,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
|
||||
new PropertyDataRelator().Map, sql);
|
||||
|
||||
return BuildFromDto(dtos);
|
||||
return BuildFromDto(dtos, sql);
|
||||
}
|
||||
|
||||
protected override void PerformDeleteVersion(int id, Guid versionId)
|
||||
@@ -523,7 +523,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
|
||||
new PropertyDataRelator().Map, sql);
|
||||
|
||||
return BuildFromDtos(dtos);
|
||||
return BuildFromDtos(dtos, sql);
|
||||
}
|
||||
|
||||
public bool Exists(string username)
|
||||
@@ -640,7 +640,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
_contentPreviewRepository.AddOrUpdate(new ContentPreviewEntity<IMember>(previewExists, content, xml));
|
||||
}
|
||||
|
||||
private IMember BuildFromDto(List<MemberReadOnlyDto> dtos)
|
||||
private IMember BuildFromDto(List<MemberReadOnlyDto> dtos, Sql docSql)
|
||||
{
|
||||
if (dtos == null || dtos.Any() == false)
|
||||
return null;
|
||||
@@ -657,18 +657,22 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var factory = new MemberReadOnlyFactory(memberTypes);
|
||||
var member = factory.BuildEntity(dto);
|
||||
|
||||
member.Properties = GetPropertyCollection(dto.NodeId, dto.VersionId, member.ContentType, dto.CreateDate, dto.UpdateDate);
|
||||
var properties = GetPropertyCollection(docSql, new DocumentDefinition(dto.NodeId, dto.VersionId, dto.UpdateDate, dto.CreateDate, member.ContentType));
|
||||
|
||||
member.Properties = properties[dto.NodeId];
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
private IEnumerable<IMember> BuildFromDtos(List<MemberReadOnlyDto> dtos)
|
||||
private IEnumerable<IMember> BuildFromDtos(List<MemberReadOnlyDto> dtos, Sql docSql)
|
||||
{
|
||||
if (dtos == null || dtos.Any() == false)
|
||||
return Enumerable.Empty<IMember>();
|
||||
|
||||
//We assume that there won't exist a lot of MemberTypes, so the following should be fairly fast
|
||||
var memberTypes = new Dictionary<string, IMemberType>();
|
||||
|
||||
//TODO: We should do an SQL 'IN' here
|
||||
var memberTypeList = _memberTypeRepository.GetAll();
|
||||
memberTypeList.ForEach(x => memberTypes.Add(x.Alias, x));
|
||||
|
||||
@@ -677,7 +681,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
foreach (var dto in dtos)
|
||||
{
|
||||
var entity = factory.BuildEntity(dto);
|
||||
entity.Properties = GetPropertyCollection(dto.NodeId, dto.VersionId, entity.ContentType, dto.CreateDate, dto.UpdateDate);
|
||||
|
||||
var properties = GetPropertyCollection(docSql,new DocumentDefinition(dto.NodeId, dto.VersionId, dto.UpdateDate, dto.CreateDate, entity.ContentType));
|
||||
|
||||
entity.Properties = properties[dto.NodeId];
|
||||
|
||||
entities.Add(entity);
|
||||
}
|
||||
return entities;
|
||||
|
||||
@@ -218,154 +218,66 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a fix for U4-1407 - when property types are added to a content type - the property of the entity are not actually created
|
||||
/// and we get YSODs
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="createDate"></param>
|
||||
/// <param name="updateDate"></param>
|
||||
/// <returns></returns>
|
||||
protected PropertyCollection GetPropertyCollection(int id, Guid versionId, IContentTypeComposition contentType, DateTime createDate, DateTime updateDate)
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select("cmsPropertyData.*, cmsDataTypePreValues.id as preValId, cmsDataTypePreValues.value, cmsDataTypePreValues.sortorder, cmsDataTypePreValues.alias, cmsDataTypePreValues.datatypeNodeId")
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>()
|
||||
.On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
|
||||
|
||||
.LeftOuterJoin<DataTypePreValueDto>()
|
||||
.On<PropertyTypeDto, DataTypePreValueDto>(left => left.DataTypeId, right => right.DataTypeNodeId)
|
||||
|
||||
.Where<PropertyDataDto>(x => x.NodeId == id)
|
||||
.Where<PropertyDataDto>(x => x.VersionId == versionId);
|
||||
|
||||
var allData = Database.Fetch<dynamic>(sql);
|
||||
|
||||
var propertyDataDtos = allData.Select(x => new PropertyDataDto
|
||||
{
|
||||
Date = x.dataDate,
|
||||
Id = x.id,
|
||||
Integer = x.dataInt,
|
||||
NodeId = x.contentNodeId,
|
||||
Text = x.dataNtext,
|
||||
VarChar = x.dataNvarchar,
|
||||
VersionId = x.versionId,
|
||||
PropertyTypeId = x.propertytypeid,
|
||||
//NOTE: This get's used for nothing so we don't need to map it
|
||||
//PropertyTypeDto = new PropertyTypeDto()
|
||||
}).Distinct();
|
||||
|
||||
var propertyFactory = new PropertyFactory(contentType, versionId, id, createDate, updateDate);
|
||||
var properties = propertyFactory.BuildEntity(propertyDataDtos).ToArray();
|
||||
|
||||
var newProperties = properties.Where(x => x.HasIdentity == false && x.PropertyType.HasIdentity);
|
||||
foreach (var property in newProperties)
|
||||
{
|
||||
var propertyDataDto = new PropertyDataDto { NodeId = id, PropertyTypeId = property.PropertyTypeId, VersionId = versionId };
|
||||
int primaryKey = Convert.ToInt32(Database.Insert(propertyDataDto));
|
||||
|
||||
property.Version = versionId;
|
||||
property.Id = primaryKey;
|
||||
}
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
//NOTE: The benchmarks run with and without the following code show very little change so this is not a perf bottleneck
|
||||
var editor = PropertyEditorResolver.Current.GetByAlias(property.PropertyType.PropertyEditorAlias);
|
||||
var tagSupport = TagExtractor.GetAttribute(editor);
|
||||
|
||||
if (tagSupport != null)
|
||||
{
|
||||
|
||||
//this property has tags, so we need to extract them and for that we need the prevals which we've already looked up
|
||||
|
||||
var preValData = allData.Where(x => x.propertytypeid == property.PropertyTypeId && x.preValId != null)
|
||||
.Select(x => new DataTypePreValueDto
|
||||
{
|
||||
Alias = x.alias,
|
||||
DataTypeNodeId = x.datatypeNodeId,
|
||||
Id = x.preValId,
|
||||
SortOrder = x.sortorder,
|
||||
Value = x.value
|
||||
})
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
var asDictionary = preValData.ToDictionary(x => x.Alias, x => new PreValue(x.Id, x.Value, x.SortOrder));
|
||||
|
||||
var preVals = new PreValueCollection(asDictionary);
|
||||
|
||||
var contentPropData = new ContentPropertyData(property.Value,
|
||||
preVals,
|
||||
new Dictionary<string, object>());
|
||||
|
||||
TagExtractor.SetPropertyTags(property, contentPropData, property.Value, tagSupport);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new PropertyCollection(properties);
|
||||
}
|
||||
|
||||
|
||||
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
|
||||
Tuple<int, Guid, IContentTypeComposition, DateTime, DateTime>[] documentDefs)
|
||||
Sql docSql,
|
||||
params DocumentDefinition[] documentDefs)
|
||||
{
|
||||
|
||||
if (documentDefs.Length <= 0) return new Dictionary<int, PropertyCollection>();
|
||||
|
||||
//FIXME: we need to split on 2100 max SQL server parameters
|
||||
// since there will be 2 params per single row it will be half that amount
|
||||
if ((documentDefs.Length / 2) > 2000)
|
||||
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
|
||||
//we need to parse the original SQL statement and reduce the columns to just cmsContent.nodeId, cmsContentVersion.VersionId so that we can use
|
||||
// the statement to go get the property data for all of the items by using an inner join
|
||||
var parsedOriginalSql = "SELECT {0} " + docSql.SQL.Substring(docSql.SQL.IndexOf("FROM", StringComparison.Ordinal));
|
||||
//now remove everything from an Orderby clause and beyond
|
||||
if (parsedOriginalSql.InvariantContains("ORDER BY "))
|
||||
{
|
||||
parsedOriginalSql = parsedOriginalSql.Substring(0, parsedOriginalSql.IndexOf("ORDER BY ", System.StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("cmsPropertyData.*, cmsDataTypePreValues.id as preValId, cmsDataTypePreValues.value, cmsDataTypePreValues.sortorder, cmsDataTypePreValues.alias, cmsDataTypePreValues.datatypeNodeId")
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>()
|
||||
.On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
|
||||
var propSql = new Sql(@"SELECT cmsPropertyData.*
|
||||
FROM cmsPropertyData
|
||||
INNER JOIN cmsPropertyType
|
||||
ON cmsPropertyData.propertytypeid = cmsPropertyType.id
|
||||
INNER JOIN
|
||||
(" + string.Format(parsedOriginalSql, "cmsContent.nodeId, cmsContentVersion.VersionId") + @") as docData
|
||||
ON cmsPropertyData.versionId = docData.VersionId AND cmsPropertyData.contentNodeId = docData.nodeId
|
||||
LEFT OUTER JOIN cmsDataTypePreValues
|
||||
ON cmsPropertyType.dataTypeId = cmsDataTypePreValues.datatypeNodeId", docSql.Arguments);
|
||||
|
||||
.LeftOuterJoin<DataTypePreValueDto>()
|
||||
.On<PropertyTypeDto, DataTypePreValueDto>(left => left.DataTypeId, right => right.DataTypeNodeId)
|
||||
|
||||
.Where("cmsPropertyData.contentNodeId IN (@nodeIds) AND cmsPropertyData.versionId IN (@versionIds)",
|
||||
new { nodeIds = documentDefs.Select(x => x.Item1), versionIds = documentDefs.Select(x => x.Item2) });
|
||||
var allPropertyData = Database.Fetch<PropertyDataDto>(propSql);
|
||||
|
||||
var allData = Database.Fetch<dynamic>(sql);
|
||||
//This is a lazy access call to get all prevalue data for the data types that make up all of these properties which we use
|
||||
// below if any property requires tag support
|
||||
var allPreValues = new Lazy<IEnumerable<DataTypePreValueDto>>(() =>
|
||||
{
|
||||
var preValsSql = new Sql(@"SELECT DISTINCT
|
||||
cmsDataTypePreValues.id as preValId, cmsDataTypePreValues.value, cmsDataTypePreValues.sortorder, cmsDataTypePreValues.alias, cmsDataTypePreValues.datatypeNodeId
|
||||
FROM cmsDataTypePreValues
|
||||
INNER JOIN cmsPropertyType
|
||||
ON cmsDataTypePreValues.datatypeNodeId = cmsPropertyType.dataTypeId
|
||||
INNER JOIN
|
||||
(" + string.Format(parsedOriginalSql, "cmsContent.contentType") + @") as docData
|
||||
ON cmsPropertyType.contentTypeId = docData.contentType", docSql.Arguments);
|
||||
|
||||
return Database.Fetch<DataTypePreValueDto>(preValsSql);
|
||||
});
|
||||
|
||||
var result = new Dictionary<int, PropertyCollection>();
|
||||
|
||||
foreach (var def in documentDefs)
|
||||
{
|
||||
var propertyDataDtos = allData.Select(x => new PropertyDataDto
|
||||
{
|
||||
Date = x.dataDate,
|
||||
Id = x.id,
|
||||
Integer = x.dataInt,
|
||||
NodeId = x.contentNodeId,
|
||||
Text = x.dataNtext,
|
||||
VarChar = x.dataNvarchar,
|
||||
VersionId = x.versionId,
|
||||
PropertyTypeId = x.propertytypeid,
|
||||
//NOTE: This get's used for nothing so we don't need to map it
|
||||
//PropertyTypeDto = new PropertyTypeDto()
|
||||
})
|
||||
.Where(x => x.NodeId == def.Item1)
|
||||
.Distinct();
|
||||
var propertyDataDtos = allPropertyData.Where(x => x.NodeId == def.Id).Distinct();
|
||||
|
||||
var propertyFactory = new PropertyFactory(def.Item3, def.Item2, def.Item1, def.Item4, def.Item5);
|
||||
var propertyFactory = new PropertyFactory(def.Composition, def.Version, def.Id, def.CreateDate, def.VersionDate);
|
||||
var properties = propertyFactory.BuildEntity(propertyDataDtos).ToArray();
|
||||
|
||||
var newProperties = properties.Where(x => x.HasIdentity == false && x.PropertyType.HasIdentity);
|
||||
foreach (var property in newProperties)
|
||||
{
|
||||
var propertyDataDto = new PropertyDataDto { NodeId = def.Item1, PropertyTypeId = property.PropertyTypeId, VersionId = def.Item2 };
|
||||
var propertyDataDto = new PropertyDataDto { NodeId = def.Id, PropertyTypeId = property.PropertyTypeId, VersionId = def.Version };
|
||||
int primaryKey = Convert.ToInt32(Database.Insert(propertyDataDto));
|
||||
|
||||
property.Version = def.Item2;
|
||||
property.Version = def.Version;
|
||||
property.Id = primaryKey;
|
||||
}
|
||||
|
||||
@@ -377,18 +289,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (tagSupport != null)
|
||||
{
|
||||
|
||||
//this property has tags, so we need to extract them and for that we need the prevals which we've already looked up
|
||||
|
||||
var preValData = allData.Where(x => x.propertytypeid == property.PropertyTypeId && x.preValId != null)
|
||||
.Select(x => new DataTypePreValueDto
|
||||
{
|
||||
Alias = x.alias,
|
||||
DataTypeNodeId = x.datatypeNodeId,
|
||||
Id = x.preValId,
|
||||
SortOrder = x.sortorder,
|
||||
Value = x.value
|
||||
})
|
||||
var preValData = allPreValues.Value.Where(x => x.DataTypeNodeId == property.PropertyType.DataTypeDefinitionId)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
@@ -404,11 +306,32 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(def.Item1, new PropertyCollection(properties));
|
||||
result.Add(def.Id, new PropertyCollection(properties));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public class DocumentDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
|
||||
/// </summary>
|
||||
public DocumentDefinition(int id, Guid version, DateTime versionDate, DateTime createDate, IContentTypeComposition composition)
|
||||
{
|
||||
Id = id;
|
||||
Version = version;
|
||||
VersionDate = versionDate;
|
||||
CreateDate = createDate;
|
||||
Composition = composition;
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public Guid Version { get; set; }
|
||||
public DateTime VersionDate { get; set; }
|
||||
public DateTime CreateDate { get; set; }
|
||||
public IContentTypeComposition Composition { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -332,6 +332,37 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Get_All_With_Many_Version()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider();
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
ContentTypeRepository contentTypeRepository;
|
||||
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
|
||||
{
|
||||
var result = repository.GetAll().ToArray();
|
||||
foreach (var content in result)
|
||||
{
|
||||
content.ChangePublishedState(PublishedState.Saved);
|
||||
repository.AddOrUpdate(content);
|
||||
}
|
||||
unitOfWork.Commit();
|
||||
foreach (var content in result)
|
||||
{
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
repository.AddOrUpdate(content);
|
||||
}
|
||||
unitOfWork.Commit();
|
||||
|
||||
//re-get
|
||||
|
||||
var result2 = repository.GetAll().ToArray();
|
||||
|
||||
Assert.AreEqual(result.Count(), result2.Count());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_GetPagedResultsByQuery_ForFirstPage_On_ContentRepository()
|
||||
{
|
||||
|
||||
@@ -38,7 +38,13 @@ namespace Umbraco.Tests.Services
|
||||
public void Retrieving_All_Content_In_Site()
|
||||
{
|
||||
//NOTE: Doing this the old 1 by 1 way and based on the results of the ContentServicePerformanceTest.Retrieving_All_Content_In_Site
|
||||
// the old way takes 143795ms, the new above way takes: 14249ms that is a 90% savings of processing and sql calls!
|
||||
// the old way takes 143795ms, the new above way takes:
|
||||
// 14249ms
|
||||
//
|
||||
// ... NOPE, made some new changes, it is now....
|
||||
// 5290ms !!!!!!
|
||||
//
|
||||
// that is a 96% savings of processing and sql calls!
|
||||
|
||||
var contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "test1");
|
||||
var contentType2 = MockedContentTypes.CreateTextpageContentType("test2", "test2");
|
||||
|
||||
Reference in New Issue
Block a user