Merge branch 'temp8' into temp8-dirty-tracking-on-variants
This commit is contained in:
@@ -19,6 +19,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <remarks>Current version is first, and then versions are ordered with most recent first.</remarks>
|
||||
IEnumerable<TEntity> GetAllVersions(int nodeId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets versions.
|
||||
/// </summary>
|
||||
/// <remarks>Current version is first, and then versions are ordered with most recent first.</remarks>
|
||||
IEnumerable<TEntity> GetAllVersionsSlim(int nodeId, int skip, int take);
|
||||
|
||||
/// <summary>
|
||||
/// Gets version identifiers.
|
||||
/// </summary>
|
||||
|
||||
@@ -53,6 +53,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// gets all versions, current first
|
||||
public abstract IEnumerable<TEntity> GetAllVersions(int nodeId);
|
||||
|
||||
// gets all versions, current first
|
||||
public virtual IEnumerable<TEntity> GetAllVersionsSlim(int nodeId, int skip, int take)
|
||||
=> GetAllVersions(nodeId).Skip(skip).Take(take);
|
||||
|
||||
// gets all version ids, current first
|
||||
public virtual IEnumerable<int> GetVersionIds(int nodeId, int maxRows)
|
||||
{
|
||||
@@ -252,8 +256,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// if we do not do this then we end up with issues where we are ordering by a field that has duplicate values (i.e. the 'text' column
|
||||
// is empty for many nodes) - see: http://issues.umbraco.org/issue/U4-8831
|
||||
|
||||
var dbfield = GetQuotedFieldName("umbracoNode", "id");
|
||||
(dbfield, _) = SqlContext.Visit<NodeDto>(x => x.NodeId); // fixme?!
|
||||
var (dbfield, _) = SqlContext.VisitDto<NodeDto>(x => x.NodeId);
|
||||
if (ordering.IsCustomField || !ordering.OrderBy.InvariantEquals("id"))
|
||||
{
|
||||
psql.OrderBy(GetAliasedField(dbfield, sql)); // fixme why aliased?
|
||||
@@ -262,7 +265,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// create prepared sql
|
||||
// ensure it's single-line as NPoco PagingHelper has issues with multi-lines
|
||||
psql = Sql(psql.SQL.ToSingleLine(), psql.Arguments);
|
||||
|
||||
|
||||
// replace the magic culture parameter (see DocumentRepository.GetBaseQuery())
|
||||
if (!ordering.Culture.IsNullOrWhiteSpace())
|
||||
@@ -353,6 +355,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (ordering.Culture.IsNullOrWhiteSpace())
|
||||
return GetAliasedField(SqlSyntax.GetFieldName<NodeDto>(x => x.Text), sql);
|
||||
|
||||
// "variantName" alias is defined in DocumentRepository.GetBaseQuery
|
||||
// fixme - what if it is NOT a document but a ... media or whatever?
|
||||
// previously, we inserted the join+select *here* so we were sure to have it,
|
||||
// but now that's not the case anymore!
|
||||
return "variantName";
|
||||
}
|
||||
|
||||
@@ -433,7 +439,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// sort and filter
|
||||
sql = PreparePageSql(sql, filter, ordering);
|
||||
|
||||
|
||||
// get a page of DTOs and the total count
|
||||
var pagedResult = Database.Page<TDto>(pageIndex + 1, pageSize, sql);
|
||||
totalRecords = Convert.ToInt32(pagedResult.TotalItems);
|
||||
|
||||
@@ -95,6 +95,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return GetBaseQuery(queryType, true);
|
||||
}
|
||||
|
||||
// gets the COALESCE expression for variant/invariant name
|
||||
private string VariantNameSqlExpression
|
||||
=> SqlContext.VisitDto<ContentVersionCultureVariationDto, NodeDto>((ccv, node) => ccv.Name ?? node.Text, "ccv").Sql;
|
||||
|
||||
protected virtual Sql<ISqlContext> GetBaseQuery(QueryType queryType, bool current)
|
||||
{
|
||||
var sql = SqlContext.Sql();
|
||||
@@ -116,7 +120,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
r1.Select(documentVersionDto => documentVersionDto.ContentVersionDto))
|
||||
.Select(documentDto => documentDto.PublishedVersionDto, "pdv", r1 =>
|
||||
r1.Select(documentVersionDto => documentVersionDto.ContentVersionDto, "pcv")))
|
||||
.AndSelect(SqlContext.Visit<ContentVersionCultureVariationDto, NodeDto>((ccv, node) => ccv.Name ?? node.Text, "ccv").Sql + " AS variantName");
|
||||
|
||||
// select the variant name, coalesce to the invariant name, as "variantName"
|
||||
.AndSelect(VariantNameSqlExpression + " AS variantName");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -135,18 +141,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
.LeftJoin<ContentVersionDto>(nested =>
|
||||
nested.InnerJoin<DocumentVersionDto>("pdv")
|
||||
.On<ContentVersionDto, DocumentVersionDto>((left, right) => left.Id == right.Id && right.Published, "pcv", "pdv"), "pcv")
|
||||
.On<DocumentDto, ContentVersionDto>((left, right) => left.NodeId == right.NodeId, aliasRight: "pcv");
|
||||
.On<DocumentDto, ContentVersionDto>((left, right) => left.NodeId == right.NodeId, aliasRight: "pcv")
|
||||
|
||||
//the magic [[[ISOCODE]]] will be replaced in ContentRepositoryBase.GetPage() by the current Iso code
|
||||
sql
|
||||
// left join on optional culture variation
|
||||
//the magic "[[[ISOCODE]]]" parameter value will be replaced in ContentRepositoryBase.GetPage() by the actual ISO code
|
||||
.LeftJoin<ContentVersionCultureVariationDto>(nested =>
|
||||
nested.InnerJoin<LanguageDto>("lang").On<ContentVersionCultureVariationDto, LanguageDto>((ccv, lang) => ccv.LanguageId == lang.Id && lang.IsoCode == "[[[ISOCODE]]]", "ccv", "lang"), "ccv")
|
||||
.On<ContentVersionDto, ContentVersionCultureVariationDto>((version, ccv) => version.Id == ccv.VersionId, "pcv", "ccv");
|
||||
.On<ContentVersionDto, ContentVersionCultureVariationDto>((version, ccv) => version.Id == ccv.VersionId, aliasRight: "ccv");
|
||||
|
||||
sql
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
|
||||
|
||||
// this would ensure we don't get the published version - keep for reference
|
||||
//sql
|
||||
// .WhereAny(
|
||||
@@ -157,7 +162,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (current)
|
||||
sql.Where<ContentVersionDto>(x => x.Current); // always get the current version
|
||||
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -216,6 +220,16 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return MapDtosToContent(Database.Fetch<DocumentDto>(sql), true);
|
||||
}
|
||||
|
||||
public override IEnumerable<IContent> GetAllVersionsSlim(int nodeId, int skip, int take)
|
||||
{
|
||||
var sql = GetBaseQuery(QueryType.Many, false)
|
||||
.Where<NodeDto>(x => x.NodeId == nodeId)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.Current)
|
||||
.AndByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
|
||||
return MapDtosToContent(Database.Fetch<DocumentDto>(sql), true, true);
|
||||
}
|
||||
|
||||
public override IContent GetVersion(int versionId)
|
||||
{
|
||||
var sql = GetBaseQuery(QueryType.Single, false)
|
||||
@@ -246,7 +260,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// however, it's not just so we have access to AddingEntity
|
||||
// there are tons of things at the end of the methods, that can only work with a true Content
|
||||
// and basically, the repository requires a Content, not an IContent
|
||||
var content = (Content)entity;
|
||||
var content = (Content) entity;
|
||||
|
||||
content.AddingEntity();
|
||||
var publishing = content.PublishedState == PublishedState.Publishing;
|
||||
@@ -420,7 +434,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// however, it's not just so we have access to AddingEntity
|
||||
// there are tons of things at the end of the methods, that can only work with a true Content
|
||||
// and basically, the repository requires a Content, not an IContent
|
||||
var content = (Content)entity;
|
||||
var content = (Content) entity;
|
||||
|
||||
// check if we need to make any database changes at all
|
||||
if ((content.PublishedState == PublishedState.Published || content.PublishedState == PublishedState.Unpublished) && !content.IsEntityDirty() && !content.IsAnyUserPropertyDirty())
|
||||
@@ -707,30 +721,27 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
Sql<ISqlContext> filterSql = null;
|
||||
|
||||
// Here we create a default where clause from a temp IContent which will look in the contentVersion table for the content name
|
||||
// if we are searching in a list view that contains variants, we want to look in the contentVersionCultureVariation table instead.
|
||||
// The resulting clause will be used in the foreach below to compare against the original clause that comes from the "filter" and if they are the same
|
||||
// we know that we are searching a list view and the proper where clause will be replaced to look in contentVersionCultureVariation table for the names.
|
||||
var temp = Query<IContent>().Where(x => x.Name.Contains("foo"));
|
||||
var clause = temp.GetWhereClauses().First().Item1.Split(' ')[0];
|
||||
|
||||
// if we have a filter, map its clauses to an Sql statement
|
||||
if (filter != null)
|
||||
{
|
||||
// if the clause works on "name", we need to swap the field and use the variantName instead,
|
||||
// so that querying also works on variant content (for instance when searching a listview).
|
||||
|
||||
// figure out how the "name" field is going to look like - so we can look for it
|
||||
var nameField = SqlContext.VisitModelField<IContent>(x => x.Name);
|
||||
|
||||
filterSql = Sql();
|
||||
foreach (var filterClause in filter.GetWhereClauses())
|
||||
{
|
||||
// fixme - is this the right way of doing it???
|
||||
var clauseSql = filterClause.Item1;
|
||||
var clauseArgs = filterClause.Item2;
|
||||
|
||||
//
|
||||
var where = filterClause.Item1.Split(' ')[0] == clause
|
||||
// normally, this would be the field alias (variantName) of the coalesce result between ContentVersionCulture and NodeDto names, however
|
||||
// you can't refer to field alias in a WHERE clause so we have to put the coalesce calculation instead which refers to the original field
|
||||
? SqlContext.Visit<ContentVersionCultureVariationDto, NodeDto>((ccv, node) => ccv.Name ?? node.Text, "ccv").Sql
|
||||
: filterClause.Item1;
|
||||
// replace the name field
|
||||
// we cannot reference an aliased field in a WHERE clause, so have to repeat the expression here
|
||||
clauseSql = clauseSql.Replace(nameField, VariantNameSqlExpression);
|
||||
|
||||
filterSql.Append(
|
||||
where.Contains("COALESCE") ? $"AND upper({where}) LIKE upper(@0)" : $"AND ({where})",
|
||||
filterClause.Item2);
|
||||
// append the clause
|
||||
filterSql.Append($"AND ({clauseSql})", clauseArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -910,7 +921,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return base.ApplySystemOrdering(ref sql, ordering);
|
||||
}
|
||||
|
||||
private IEnumerable<IContent> MapDtosToContent(List<DocumentDto> dtos, bool withCache = false)
|
||||
private IEnumerable<IContent> MapDtosToContent(List<DocumentDto> dtos, bool withCache = false, bool slim = false)
|
||||
{
|
||||
var temps = new List<TempContent<Content>>();
|
||||
var contentTypes = new Dictionary<int, IContentType>();
|
||||
@@ -928,7 +939,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var cached = IsolatedCache.GetCacheItem<IContent>(RepositoryCacheKeys.GetKey<IContent>(dto.NodeId));
|
||||
if (cached != null && cached.VersionId == dto.DocumentVersionDto.ContentVersionDto.Id)
|
||||
{
|
||||
content[i] = (Content)cached;
|
||||
content[i] = (Content) cached;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -943,18 +954,21 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
var c = content[i] = ContentBaseFactory.BuildEntity(dto, contentType);
|
||||
|
||||
// need templates
|
||||
var templateId = dto.DocumentVersionDto.TemplateId;
|
||||
if (templateId.HasValue && templateId.Value > 0)
|
||||
templateIds.Add(templateId.Value);
|
||||
if (dto.Published)
|
||||
if (!slim)
|
||||
{
|
||||
templateId = dto.PublishedVersionDto.TemplateId;
|
||||
// need templates
|
||||
var templateId = dto.DocumentVersionDto.TemplateId;
|
||||
if (templateId.HasValue && templateId.Value > 0)
|
||||
templateIds.Add(templateId.Value);
|
||||
if (dto.Published)
|
||||
{
|
||||
templateId = dto.PublishedVersionDto.TemplateId;
|
||||
if (templateId.HasValue && templateId.Value > 0)
|
||||
templateIds.Add(templateId.Value);
|
||||
}
|
||||
}
|
||||
|
||||
// need properties
|
||||
// need temps, for properties, templates and variations
|
||||
var versionId = dto.DocumentVersionDto.Id;
|
||||
var publishedVersionId = dto.Published ? dto.PublishedVersionDto.Id : 0;
|
||||
var temp = new TempContent<Content>(dto.NodeId, versionId, publishedVersionId, contentType, c)
|
||||
@@ -965,25 +979,28 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
temps.Add(temp);
|
||||
}
|
||||
|
||||
// load all required templates in 1 query, and index
|
||||
var templates = _templateRepository.GetMany(templateIds.ToArray())
|
||||
.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
// load all properties for all documents from database in 1 query - indexed by version id
|
||||
var properties = GetPropertyCollections(temps);
|
||||
|
||||
// assign templates and properties
|
||||
foreach (var temp in temps)
|
||||
if (!slim)
|
||||
{
|
||||
// complete the item
|
||||
if (temp.Template1Id.HasValue && templates.TryGetValue(temp.Template1Id.Value, out var template))
|
||||
temp.Content.Template = template;
|
||||
if (temp.Template2Id.HasValue && templates.TryGetValue(temp.Template2Id.Value, out template))
|
||||
temp.Content.PublishTemplate = template;
|
||||
temp.Content.Properties = properties[temp.VersionId];
|
||||
// load all required templates in 1 query, and index
|
||||
var templates = _templateRepository.GetMany(templateIds.ToArray())
|
||||
.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
// reset dirty initial properties (U4-1946)
|
||||
temp.Content.ResetDirtyProperties(false);
|
||||
// load all properties for all documents from database in 1 query - indexed by version id
|
||||
var properties = GetPropertyCollections(temps);
|
||||
|
||||
// assign templates and properties
|
||||
foreach (var temp in temps)
|
||||
{
|
||||
// complete the item
|
||||
if (temp.Template1Id.HasValue && templates.TryGetValue(temp.Template1Id.Value, out var template))
|
||||
temp.Content.Template = template;
|
||||
if (temp.Template2Id.HasValue && templates.TryGetValue(temp.Template2Id.Value, out template))
|
||||
temp.Content.PublishTemplate = template;
|
||||
temp.Content.Properties = properties[temp.VersionId];
|
||||
|
||||
// reset dirty initial properties (U4-1946)
|
||||
temp.Content.ResetDirtyProperties(false);
|
||||
}
|
||||
}
|
||||
|
||||
// set variations, if varying
|
||||
|
||||
@@ -8,12 +8,12 @@ using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
@@ -100,7 +100,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
case QueryType.Many:
|
||||
sql = sql.Select<ContentDto>(r =>
|
||||
r.Select(x => x.NodeDto)
|
||||
.Select(x => x.ContentVersionDto));
|
||||
.Select(x => x.ContentVersionDto))
|
||||
|
||||
// ContentRepositoryBase expects a variantName field to order by name
|
||||
// for now, just return the plain invariant node name
|
||||
// fixme media should support variants !!
|
||||
.AndSelect<NodeDto>(x => Alias(x.Text, "variantName"));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
@@ -114,9 +114,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
case QueryType.Single:
|
||||
case QueryType.Many:
|
||||
sql = sql.Select<MemberDto>(r =>
|
||||
r.Select(x => x.ContentVersionDto)
|
||||
.Select(x => x.ContentDto, r1 =>
|
||||
r1.Select(x => x.NodeDto)));
|
||||
r.Select(x => x.ContentVersionDto)
|
||||
.Select(x => x.ContentDto, r1 =>
|
||||
r1.Select(x => x.NodeDto)))
|
||||
|
||||
// ContentRepositoryBase expects a variantName field to order by name
|
||||
// so get it here, though for members it's just the plain node name
|
||||
.AndSelect<NodeDto>(x => Alias(x.Text, "variantName"));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user