Files
Umbraco-CMS/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs
Bjarke Berg 1ea39f2762 Merge remote-tracking branch 'origin/v8/dev' into netcore/dev
# Conflicts:
#	src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs
#	src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs
#	src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs
#	src/Umbraco.Core/Packaging/ConflictingPackageData.cs
#	src/Umbraco.Core/Packaging/PackagesRepository.cs
#	src/Umbraco.Core/PublishedCache/PublishedMember.cs
#	src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs
#	src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs
#	src/Umbraco.PublishedCache.NuCache/PublishedContent.cs
#	src/Umbraco.Tests/Persistence/Repositories/MacroRepositoryTest.cs
#	src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs
#	src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs
#	src/Umbraco.Web/PublishedContentExtensions.cs
#	src/Umbraco.Web/Trees/MediaTypeTreeController.cs
2020-03-02 08:34:52 +01:00

223 lines
7.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Scoping;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Persistence.Repositories.Implement
{
internal class MacroRepository : NPocoRepositoryBase<int, IMacro>, IMacroRepository
{
private readonly IShortStringHelper _shortStringHelper;
public MacroRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IShortStringHelper shortStringHelper)
: base(scopeAccessor, cache, logger)
{
_shortStringHelper = shortStringHelper;
}
protected override IMacro PerformGet(int id)
{
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { id });
return GetBySql(sql);
}
public IMacro Get(Guid id)
{
var sql = GetBaseQuery().Where("uniqueId=@Id", new { Id = id });
return GetBySql(sql);
}
private IMacro GetBySql(Sql sql)
{
var macroDto = Database
.FetchOneToMany<MacroDto>(x => x.MacroPropertyDtos, sql)
.FirstOrDefault();
if (macroDto == null)
return null;
var entity = MacroFactory.BuildEntity(_shortStringHelper, macroDto);
// reset dirty initial properties (U4-1946)
((BeingDirtyBase)entity).ResetDirtyProperties(false);
return entity;
}
public IEnumerable<IMacro> GetMany(params Guid[] ids)
{
return ids.Length > 0 ? ids.Select(Get) : GetAllNoIds();
}
public bool Exists(Guid id)
{
return Get(id) != null;
}
protected override IEnumerable<IMacro> PerformGetAll(params int[] ids)
{
return ids.Length > 0 ? ids.Select(Get) : GetAllNoIds();
}
private IEnumerable<IMacro> GetAllNoIds()
{
var sql = GetBaseQuery(false)
//must be sorted this way for the relator to work
.OrderBy<MacroDto>(x => x.Id);
return Database
.FetchOneToMany<MacroDto>(x => x.MacroPropertyDtos, sql)
.Transform(ConvertFromDtos)
.ToArray(); // do it now and once
}
private IEnumerable<IMacro> ConvertFromDtos(IEnumerable<MacroDto> dtos)
{
foreach (var entity in dtos.Select(x => MacroFactory.BuildEntity(_shortStringHelper, x)))
{
// reset dirty initial properties (U4-1946)
((BeingDirtyBase)entity).ResetDirtyProperties(false);
yield return entity;
}
}
protected override IEnumerable<IMacro> PerformGetByQuery(IQuery<IMacro> query)
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IMacro>(sqlClause, query);
var sql = translator.Translate();
return Database
.FetchOneToMany<MacroDto>(x => x.MacroPropertyDtos, sql)
.Select(x => Get(x.Id));
}
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
{
return isCount ? Sql().SelectCount().From<MacroDto>() : GetBaseQuery();
}
private Sql<ISqlContext> GetBaseQuery()
{
return Sql()
.SelectAll()
.From<MacroDto>()
.LeftJoin<MacroPropertyDto>()
.On<MacroDto, MacroPropertyDto>(left => left.Id, right => right.Macro);
}
protected override string GetBaseWhereClause()
{
return "cmsMacro.id = @id";
}
protected override IEnumerable<string> GetDeleteClauses()
{
var list = new List<string>
{
"DELETE FROM cmsMacroProperty WHERE macro = @id",
"DELETE FROM cmsMacro WHERE id = @id"
};
return list;
}
protected override Guid NodeObjectTypeId => throw new NotImplementedException();
protected override void PersistNewItem(IMacro entity)
{
entity.AddingEntity();
var dto = MacroFactory.BuildDto(entity);
var id = Convert.ToInt32(Database.Insert(dto));
entity.Id = id;
foreach (var propDto in dto.MacroPropertyDtos)
{
//need to set the id explicitly here
propDto.Macro = id;
var propId = Convert.ToInt32(Database.Insert(propDto));
entity.Properties[propDto.Alias].Id = propId;
}
entity.ResetDirtyProperties();
}
protected override void PersistUpdatedItem(IMacro entity)
{
entity.UpdatingEntity();
var dto = MacroFactory.BuildDto(entity);
Database.Update(dto);
//update the properties if they've changed
var macro = (Macro)entity;
if (macro.IsPropertyDirty("Properties") || macro.Properties.Values.Any(x => x.IsDirty()))
{
var ids = dto.MacroPropertyDtos.Where(x => x.Id > 0).Select(x => x.Id).ToArray();
if (ids.Length > 0)
Database.Delete<MacroPropertyDto>("WHERE macro=@macro AND id NOT IN (@ids)", new { macro = dto.Id, ids });
else
Database.Delete<MacroPropertyDto>("WHERE macro=@macro", new { macro = dto.Id });
// detect new aliases, replace with temp aliases
// this ensures that we don't have collisions, ever
var aliases = new Dictionary<string, string>();
foreach (var propDto in dto.MacroPropertyDtos)
{
var prop = macro.Properties.Values.FirstOrDefault(x => x.Id == propDto.Id);
if (prop == null) throw new Exception("oops: property.");
if (propDto.Id == 0 || prop.IsPropertyDirty("Alias"))
{
var tempAlias = Guid.NewGuid().ToString("N").Substring(0, 8);
aliases[tempAlias] = propDto.Alias;
propDto.Alias = tempAlias;
}
}
// insert or update existing properties, with temp aliases
foreach (var propDto in dto.MacroPropertyDtos)
{
if (propDto.Id == 0)
{
// insert
propDto.Id = Convert.ToInt32(Database.Insert(propDto));
macro.Properties[aliases[propDto.Alias]].Id = propDto.Id;
}
else
{
// update
var property = macro.Properties.Values.FirstOrDefault(x => x.Id == propDto.Id);
if (property == null) throw new Exception("oops: property.");
if (property.IsDirty())
Database.Update(propDto);
}
}
// replace the temp aliases with the real ones
foreach (var propDto in dto.MacroPropertyDtos)
{
if (aliases.ContainsKey(propDto.Alias) == false) continue;
propDto.Alias = aliases[propDto.Alias];
Database.Update(propDto);
}
}
entity.ResetDirtyProperties();
}
}
}