2021-03-11 19:35:43 +11:00
|
|
|
using System;
|
2017-12-07 16:45:25 +01:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2020-09-17 09:42:55 +02:00
|
|
|
using Microsoft.Extensions.Logging;
|
2017-12-07 16:45:25 +01:00
|
|
|
using NPoco;
|
2021-02-09 10:22:42 +01:00
|
|
|
using Umbraco.Cms.Core;
|
|
|
|
|
using Umbraco.Cms.Core.Cache;
|
|
|
|
|
using Umbraco.Cms.Core.Models;
|
|
|
|
|
using Umbraco.Cms.Core.Models.Entities;
|
|
|
|
|
using Umbraco.Cms.Core.Persistence.Querying;
|
|
|
|
|
using Umbraco.Cms.Core.Persistence.Repositories;
|
|
|
|
|
using Umbraco.Cms.Core.Services;
|
2021-02-12 13:36:50 +01:00
|
|
|
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
|
|
|
|
|
using Umbraco.Cms.Infrastructure.Persistence.Factories;
|
|
|
|
|
using Umbraco.Cms.Infrastructure.Persistence.Querying;
|
|
|
|
|
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
|
2022-01-13 17:44:11 +00:00
|
|
|
using Umbraco.Cms.Infrastructure.Scoping;
|
2021-02-09 13:32:34 +01:00
|
|
|
using Umbraco.Extensions;
|
2021-02-09 10:22:42 +01:00
|
|
|
using static Umbraco.Cms.Core.Persistence.SqlExtensionsStatics;
|
2017-12-07 16:45:25 +01:00
|
|
|
|
2021-02-12 13:36:50 +01:00
|
|
|
namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
|
2017-12-07 16:45:25 +01:00
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Represents a repository for doing CRUD operations for <see cref="Relation"/>
|
|
|
|
|
/// </summary>
|
2020-12-22 10:30:16 +11:00
|
|
|
internal class RelationRepository : EntityRepositoryBase<int, IRelation>, IRelationRepository
|
2017-12-07 16:45:25 +01:00
|
|
|
{
|
|
|
|
|
private readonly IRelationTypeRepository _relationTypeRepository;
|
2022-01-13 23:22:19 +00:00
|
|
|
private readonly IEntityRepositoryExtended _entityRepository;
|
2017-12-07 16:45:25 +01:00
|
|
|
|
2022-01-13 23:22:19 +00:00
|
|
|
public RelationRepository(IScopeAccessor scopeAccessor, ILogger<RelationRepository> logger, IRelationTypeRepository relationTypeRepository, IEntityRepositoryExtended entityRepository)
|
2019-01-17 08:34:29 +01:00
|
|
|
: base(scopeAccessor, AppCaches.NoCache, logger)
|
2017-12-07 16:45:25 +01:00
|
|
|
{
|
|
|
|
|
_relationTypeRepository = relationTypeRepository;
|
2019-11-06 12:43:10 +11:00
|
|
|
_entityRepository = entityRepository;
|
2017-12-07 16:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region Overrides of RepositoryBase<int,Relation>
|
|
|
|
|
|
|
|
|
|
protected override IRelation PerformGet(int id)
|
|
|
|
|
{
|
|
|
|
|
var sql = GetBaseQuery(false);
|
|
|
|
|
sql.Where(GetBaseWhereClause(), new { id });
|
|
|
|
|
|
|
|
|
|
var dto = Database.Fetch<RelationDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
|
|
|
|
if (dto == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var relationType = _relationTypeRepository.Get(dto.RelationType);
|
|
|
|
|
if (relationType == null)
|
2019-10-24 21:32:00 +11:00
|
|
|
throw new InvalidOperationException(string.Format("RelationType with Id: {0} doesn't exist", dto.RelationType));
|
2017-12-07 16:45:25 +01:00
|
|
|
|
2019-10-24 21:32:00 +11:00
|
|
|
return DtoToEntity(dto, relationType);
|
2017-12-07 16:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override IEnumerable<IRelation> PerformGetAll(params int[] ids)
|
|
|
|
|
{
|
|
|
|
|
var sql = GetBaseQuery(false);
|
|
|
|
|
if (ids.Length > 0)
|
|
|
|
|
sql.WhereIn<RelationDto>(x => x.Id, ids);
|
|
|
|
|
sql.OrderBy<RelationDto>(x => x.RelationType);
|
|
|
|
|
var dtos = Database.Fetch<RelationDto>(sql);
|
|
|
|
|
return DtosToEntities(dtos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override IEnumerable<IRelation> PerformGetByQuery(IQuery<IRelation> query)
|
|
|
|
|
{
|
|
|
|
|
var sqlClause = GetBaseQuery(false);
|
|
|
|
|
var translator = new SqlTranslator<IRelation>(sqlClause, query);
|
|
|
|
|
var sql = translator.Translate();
|
|
|
|
|
sql.OrderBy<RelationDto>(x => x.RelationType);
|
|
|
|
|
var dtos = Database.Fetch<RelationDto>(sql);
|
|
|
|
|
return DtosToEntities(dtos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IEnumerable<IRelation> DtosToEntities(IEnumerable<RelationDto> dtos)
|
|
|
|
|
{
|
2019-10-24 21:32:00 +11:00
|
|
|
//NOTE: This is N+1, BUT ALL relation types are cached so shouldn't matter
|
2017-12-07 16:45:25 +01:00
|
|
|
|
2019-10-24 21:32:00 +11:00
|
|
|
return dtos.Select(x => DtoToEntity(x, _relationTypeRepository.Get(x.RelationType))).ToList();
|
2017-12-07 16:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-24 21:32:00 +11:00
|
|
|
private static IRelation DtoToEntity(RelationDto dto, IRelationType relationType)
|
2017-12-07 16:45:25 +01:00
|
|
|
{
|
2019-10-24 21:32:00 +11:00
|
|
|
var entity = RelationFactory.BuildEntity(dto, relationType);
|
2017-12-07 16:45:25 +01:00
|
|
|
|
|
|
|
|
// reset dirty initial properties (U4-1946)
|
2019-10-24 21:32:00 +11:00
|
|
|
entity.ResetDirtyProperties(false);
|
2017-12-07 16:45:25 +01:00
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2020-12-22 10:30:16 +11:00
|
|
|
#region Overrides of EntityRepositoryBase<int,Relation>
|
2017-12-07 16:45:25 +01:00
|
|
|
|
|
|
|
|
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
|
|
|
|
{
|
2019-10-24 21:32:00 +11:00
|
|
|
if (isCount)
|
|
|
|
|
{
|
|
|
|
|
return Sql().SelectCount().From<RelationDto>();
|
|
|
|
|
}
|
2017-12-07 16:45:25 +01:00
|
|
|
|
2019-10-24 21:32:00 +11:00
|
|
|
var sql = Sql().Select<RelationDto>()
|
|
|
|
|
.AndSelect<NodeDto>("uchild", x => Alias(x.NodeObjectType, "childObjectType"))
|
|
|
|
|
.AndSelect<NodeDto>("uparent", x => Alias(x.NodeObjectType, "parentObjectType"))
|
|
|
|
|
.From<RelationDto>()
|
|
|
|
|
.InnerJoin<NodeDto>("uchild").On<RelationDto, NodeDto>((rel, node) => rel.ChildId == node.NodeId, aliasRight: "uchild")
|
|
|
|
|
.InnerJoin<NodeDto>("uparent").On<RelationDto, NodeDto>((rel, node) => rel.ParentId == node.NodeId, aliasRight: "uparent");
|
2017-12-07 16:45:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
return sql;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override string GetBaseWhereClause()
|
|
|
|
|
{
|
2021-08-06 11:32:16 +02:00
|
|
|
return $"{Constants.DatabaseSchema.Tables.Relation}.id = @id";
|
2017-12-07 16:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override IEnumerable<string> GetDeleteClauses()
|
|
|
|
|
{
|
|
|
|
|
var list = new List<string>
|
|
|
|
|
{
|
|
|
|
|
"DELETE FROM umbracoRelation WHERE id = @id"
|
|
|
|
|
};
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Unit of Work Implementation
|
|
|
|
|
|
|
|
|
|
protected override void PersistNewItem(IRelation entity)
|
|
|
|
|
{
|
2019-06-28 09:19:11 +02:00
|
|
|
entity.AddingEntity();
|
2017-12-07 16:45:25 +01:00
|
|
|
|
2019-10-24 21:32:00 +11:00
|
|
|
var dto = RelationFactory.BuildDto(entity);
|
2017-12-07 16:45:25 +01:00
|
|
|
|
|
|
|
|
var id = Convert.ToInt32(Database.Insert(dto));
|
2019-10-24 21:32:00 +11:00
|
|
|
|
2017-12-07 16:45:25 +01:00
|
|
|
entity.Id = id;
|
2019-10-24 21:32:00 +11:00
|
|
|
PopulateObjectTypes(entity);
|
2017-12-07 16:45:25 +01:00
|
|
|
|
|
|
|
|
entity.ResetDirtyProperties();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void PersistUpdatedItem(IRelation entity)
|
|
|
|
|
{
|
2019-06-28 09:19:11 +02:00
|
|
|
entity.UpdatingEntity();
|
2017-12-07 16:45:25 +01:00
|
|
|
|
2019-10-24 21:32:00 +11:00
|
|
|
var dto = RelationFactory.BuildDto(entity);
|
2017-12-07 16:45:25 +01:00
|
|
|
Database.Update(dto);
|
|
|
|
|
|
2019-10-24 21:32:00 +11:00
|
|
|
PopulateObjectTypes(entity);
|
|
|
|
|
|
2017-12-07 16:45:25 +01:00
|
|
|
entity.ResetDirtyProperties();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
2019-10-24 16:48:21 +11:00
|
|
|
|
2019-11-15 14:14:09 +11:00
|
|
|
/// <summary>
|
|
|
|
|
/// Used for joining the entity query with relations for the paging methods
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sql"></param>
|
|
|
|
|
private void SqlJoinRelations(Sql<ISqlContext> sql)
|
2019-11-06 12:43:10 +11:00
|
|
|
{
|
2019-11-15 14:14:09 +11:00
|
|
|
// add left joins for relation tables (this joins on both child or parent, so beware that this will normally return entities for
|
|
|
|
|
// both sides of the relation type unless the IUmbracoEntity query passed in filters one side out).
|
|
|
|
|
sql.LeftJoin<RelationDto>().On<NodeDto, RelationDto>((left, right) => left.NodeId == right.ChildId || left.NodeId == right.ParentId);
|
|
|
|
|
sql.LeftJoin<RelationTypeDto>().On<RelationDto, RelationTypeDto>((left, right) => left.RelationType == right.Id);
|
|
|
|
|
}
|
2019-11-06 12:43:10 +11:00
|
|
|
|
2019-11-15 14:49:46 +11:00
|
|
|
public IEnumerable<IUmbracoEntity> GetPagedParentEntitiesByChildId(int childId, long pageIndex, int pageSize, out long totalRecords, params Guid[] entityTypes)
|
2019-11-15 14:14:09 +11:00
|
|
|
{
|
2019-11-06 13:16:28 +11:00
|
|
|
// var contentObjectTypes = new[] { Constants.ObjectTypes.Document, Constants.ObjectTypes.Media, Constants.ObjectTypes.Member }
|
|
|
|
|
// we could pass in the contentObjectTypes so that the entity repository sql is configured to do full entity lookups so that we get the full data
|
|
|
|
|
// required to populate content, media or members, else we get the bare minimum data needed to populate an entity. BUT if we do this it
|
|
|
|
|
// means that the SQL is less efficient and returns data that is probably not needed for what we need this lookup for. For the time being we
|
|
|
|
|
// will just return the bare minimum entity data.
|
|
|
|
|
|
2019-11-15 14:49:46 +11:00
|
|
|
return _entityRepository.GetPagedResultsByQuery(Query<IUmbracoEntity>(), entityTypes, pageIndex, pageSize, out totalRecords, null, null, sql =>
|
2019-11-15 14:14:09 +11:00
|
|
|
{
|
|
|
|
|
SqlJoinRelations(sql);
|
|
|
|
|
|
2019-11-15 14:49:46 +11:00
|
|
|
sql.Where<RelationDto>(rel => rel.ChildId == childId);
|
2019-11-15 14:14:09 +11:00
|
|
|
sql.Where<RelationDto, NodeDto>((rel, node) => rel.ParentId == childId || node.NodeId != childId);
|
|
|
|
|
});
|
2019-11-06 13:08:03 +11:00
|
|
|
}
|
|
|
|
|
|
2019-11-15 14:49:46 +11:00
|
|
|
public IEnumerable<IUmbracoEntity> GetPagedChildEntitiesByParentId(int parentId, long pageIndex, int pageSize, out long totalRecords, params Guid[] entityTypes)
|
2019-11-06 13:08:03 +11:00
|
|
|
{
|
2019-11-06 13:16:28 +11:00
|
|
|
// var contentObjectTypes = new[] { Constants.ObjectTypes.Document, Constants.ObjectTypes.Media, Constants.ObjectTypes.Member }
|
|
|
|
|
// we could pass in the contentObjectTypes so that the entity repository sql is configured to do full entity lookups so that we get the full data
|
|
|
|
|
// required to populate content, media or members, else we get the bare minimum data needed to populate an entity. BUT if we do this it
|
|
|
|
|
// means that the SQL is less efficient and returns data that is probably not needed for what we need this lookup for. For the time being we
|
|
|
|
|
// will just return the bare minimum entity data.
|
|
|
|
|
|
2019-11-15 14:49:46 +11:00
|
|
|
return _entityRepository.GetPagedResultsByQuery(Query<IUmbracoEntity>(), entityTypes, pageIndex, pageSize, out totalRecords, null, null, sql =>
|
2019-11-15 14:14:09 +11:00
|
|
|
{
|
|
|
|
|
SqlJoinRelations(sql);
|
|
|
|
|
|
2019-11-15 14:49:46 +11:00
|
|
|
sql.Where<RelationDto>(rel => rel.ParentId == parentId);
|
2019-11-15 14:14:09 +11:00
|
|
|
sql.Where<RelationDto, NodeDto>((rel, node) => rel.ChildId == parentId || node.NodeId != parentId);
|
|
|
|
|
});
|
2019-11-06 12:43:10 +11:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 16:45:28 +11:00
|
|
|
public void Save(IEnumerable<IRelation> relations)
|
|
|
|
|
{
|
|
|
|
|
foreach (var hasIdentityGroup in relations.GroupBy(r => r.HasIdentity))
|
|
|
|
|
{
|
|
|
|
|
if (hasIdentityGroup.Key)
|
|
|
|
|
{
|
|
|
|
|
// Do updates, we can't really do a bulk update so this is still a 1 by 1 operation
|
|
|
|
|
// however we can bulk populate the object types. It might be possible to bulk update
|
|
|
|
|
// with SQL but would be pretty ugly and we're not really too worried about that for perf,
|
|
|
|
|
// it's the bulk inserts we care about.
|
|
|
|
|
var asArray = hasIdentityGroup.ToArray();
|
|
|
|
|
foreach (var relation in hasIdentityGroup)
|
|
|
|
|
{
|
|
|
|
|
relation.UpdatingEntity();
|
|
|
|
|
var dto = RelationFactory.BuildDto(relation);
|
|
|
|
|
Database.Update(dto);
|
|
|
|
|
}
|
|
|
|
|
PopulateObjectTypes(asArray);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Do bulk inserts
|
|
|
|
|
var entitiesAndDtos = hasIdentityGroup.ToDictionary(
|
|
|
|
|
r => // key = entity
|
|
|
|
|
{
|
|
|
|
|
r.AddingEntity();
|
|
|
|
|
return r;
|
|
|
|
|
},
|
|
|
|
|
RelationFactory.BuildDto); // value = DTO
|
|
|
|
|
|
2020-10-08 14:37:17 +02:00
|
|
|
|
|
|
|
|
foreach (var dto in entitiesAndDtos.Values)
|
|
|
|
|
{
|
|
|
|
|
Database.Insert(dto);
|
|
|
|
|
}
|
2019-11-06 16:45:28 +11:00
|
|
|
|
|
|
|
|
// All dtos now have IDs assigned
|
|
|
|
|
foreach (var de in entitiesAndDtos)
|
|
|
|
|
{
|
|
|
|
|
// re-assign ID to the entity
|
|
|
|
|
de.Key.Id = de.Value.Id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PopulateObjectTypes(entitiesAndDtos.Keys.ToArray());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-09 09:32:32 +02:00
|
|
|
public void SaveBulk(IEnumerable<ReadOnlyRelation> relations)
|
2020-10-08 14:37:17 +02:00
|
|
|
{
|
|
|
|
|
foreach (var hasIdentityGroup in relations.GroupBy(r => r.HasIdentity))
|
|
|
|
|
{
|
|
|
|
|
if (hasIdentityGroup.Key)
|
|
|
|
|
{
|
|
|
|
|
// Do updates, we can't really do a bulk update so this is still a 1 by 1 operation
|
|
|
|
|
// however we can bulk populate the object types. It might be possible to bulk update
|
|
|
|
|
// with SQL but would be pretty ugly and we're not really too worried about that for perf,
|
|
|
|
|
// it's the bulk inserts we care about.
|
|
|
|
|
foreach (var relation in hasIdentityGroup)
|
|
|
|
|
{
|
|
|
|
|
var dto = RelationFactory.BuildDto(relation);
|
|
|
|
|
Database.Update(dto);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Do bulk inserts
|
2020-10-09 09:32:32 +02:00
|
|
|
var dtos = hasIdentityGroup.Select(RelationFactory.BuildDto);
|
2020-10-08 14:37:17 +02:00
|
|
|
|
2020-10-09 09:32:32 +02:00
|
|
|
Database.InsertBulk(dtos);
|
2020-10-08 14:37:17 +02:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-06 14:35:15 +11:00
|
|
|
public IEnumerable<IRelation> GetPagedRelationsByQuery(IQuery<IRelation> query, long pageIndex, int pageSize, out long totalRecords, Ordering ordering)
|
|
|
|
|
{
|
|
|
|
|
var sql = GetBaseQuery(false);
|
|
|
|
|
|
|
|
|
|
if (ordering == null || ordering.IsEmpty)
|
2021-02-09 10:22:42 +01:00
|
|
|
ordering = Ordering.By(SqlSyntax.GetQuotedColumn(Cms.Core.Constants.DatabaseSchema.Tables.Relation, "id"));
|
2019-11-06 14:35:15 +11:00
|
|
|
|
|
|
|
|
var translator = new SqlTranslator<IRelation>(sql, query);
|
|
|
|
|
sql = translator.Translate();
|
|
|
|
|
|
|
|
|
|
// apply ordering
|
|
|
|
|
ApplyOrdering(ref sql, ordering);
|
|
|
|
|
|
|
|
|
|
var pageIndexToFetch = pageIndex + 1;
|
|
|
|
|
var page = Database.Page<RelationDto>(pageIndexToFetch, pageSize, sql);
|
|
|
|
|
var dtos = page.Items;
|
|
|
|
|
totalRecords = page.TotalItems;
|
|
|
|
|
|
|
|
|
|
var relTypes = _relationTypeRepository.GetMany(dtos.Select(x => x.RelationType).Distinct().ToArray())
|
|
|
|
|
.ToDictionary(x => x.Id, x => x);
|
|
|
|
|
|
|
|
|
|
var result = dtos.Select(r =>
|
|
|
|
|
{
|
|
|
|
|
if (!relTypes.TryGetValue(r.RelationType, out var relType))
|
|
|
|
|
throw new InvalidOperationException(string.Format("RelationType with Id: {0} doesn't exist", r.RelationType));
|
|
|
|
|
return DtoToEntity(r, relType);
|
|
|
|
|
}).ToList();
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 12:37:52 +01:00
|
|
|
|
2019-10-24 16:48:21 +11:00
|
|
|
public void DeleteByParent(int parentId, params string[] relationTypeAliases)
|
|
|
|
|
{
|
2020-12-08 10:26:52 +13:00
|
|
|
if (Database.DatabaseType.IsSqlCe())
|
2019-10-24 16:48:21 +11:00
|
|
|
{
|
2020-12-08 10:26:52 +13:00
|
|
|
var subQuery = Sql().Select<RelationDto>(x => x.Id)
|
2020-12-16 13:04:11 +11:00
|
|
|
.From<RelationDto>()
|
|
|
|
|
.InnerJoin<RelationTypeDto>().On<RelationDto, RelationTypeDto>(x => x.RelationType, x => x.Id)
|
|
|
|
|
.Where<RelationDto>(x => x.ParentId == parentId);
|
2020-12-08 10:26:52 +13:00
|
|
|
|
|
|
|
|
if (relationTypeAliases.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
subQuery.WhereIn<RelationTypeDto>(x => x.Alias, relationTypeAliases);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Database.Execute(Sql().Delete<RelationDto>().WhereIn<RelationDto>(x => x.Id, subQuery));
|
|
|
|
|
|
2019-10-24 16:48:21 +11:00
|
|
|
}
|
2020-12-07 23:09:16 +13:00
|
|
|
else
|
2019-10-24 16:48:21 +11:00
|
|
|
{
|
2020-12-08 10:26:52 +13:00
|
|
|
if (relationTypeAliases.Length > 0)
|
|
|
|
|
{
|
2020-12-16 13:04:11 +11:00
|
|
|
var template = SqlContext.Templates.Get(
|
2021-02-09 10:22:42 +01:00
|
|
|
Cms.Core.Constants.SqlTemplates.RelationRepository.DeleteByParentIn,
|
2020-12-16 13:04:11 +11:00
|
|
|
tsql => Sql().Delete<RelationDto>()
|
|
|
|
|
.From<RelationDto>()
|
|
|
|
|
.InnerJoin<RelationTypeDto>().On<RelationDto, RelationTypeDto>(x => x.RelationType, x => x.Id)
|
|
|
|
|
.Where<RelationDto>(x => x.ParentId == SqlTemplate.Arg<int>("parentId"))
|
2020-12-16 13:13:09 +11:00
|
|
|
.WhereIn<RelationTypeDto>(x => x.Alias, SqlTemplate.ArgIn<string>("relationTypeAliases")));
|
2019-10-24 16:48:21 +11:00
|
|
|
|
2020-12-16 13:04:11 +11:00
|
|
|
var sql = template.Sql(parentId, relationTypeAliases);
|
|
|
|
|
|
2020-12-08 10:26:52 +13:00
|
|
|
Database.Execute(sql);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-12-16 13:04:11 +11:00
|
|
|
var template = SqlContext.Templates.Get(
|
2021-02-09 10:22:42 +01:00
|
|
|
Cms.Core.Constants.SqlTemplates.RelationRepository.DeleteByParentAll,
|
2020-12-16 13:04:11 +11:00
|
|
|
tsql => Sql().Delete<RelationDto>()
|
|
|
|
|
.From<RelationDto>()
|
|
|
|
|
.InnerJoin<RelationTypeDto>().On<RelationDto, RelationTypeDto>(x => x.RelationType, x => x.Id)
|
|
|
|
|
.Where<RelationDto>(x => x.ParentId == SqlTemplate.Arg<int>("parentId")));
|
|
|
|
|
|
|
|
|
|
var sql = template.Sql(parentId);
|
2020-12-08 10:26:52 +13:00
|
|
|
|
|
|
|
|
Database.Execute(sql);
|
|
|
|
|
}
|
2019-10-24 16:48:21 +11:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-24 21:32:00 +11:00
|
|
|
|
2019-11-06 16:45:28 +11:00
|
|
|
/// <summary>
|
|
|
|
|
/// Used to populate the object types after insert/update
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="entities"></param>
|
|
|
|
|
private void PopulateObjectTypes(params IRelation[] entities)
|
2019-10-24 21:32:00 +11:00
|
|
|
{
|
2019-11-06 16:45:28 +11:00
|
|
|
var entityIds = entities.Select(x => x.ParentId).Concat(entities.Select(y => y.ChildId)).Distinct();
|
2019-10-29 09:57:32 +01:00
|
|
|
|
2019-11-06 16:45:28 +11:00
|
|
|
var nodes = Database.Fetch<NodeDto>(Sql().Select<NodeDto>().From<NodeDto>()
|
|
|
|
|
.WhereIn<NodeDto>(x => x.NodeId, entityIds))
|
|
|
|
|
.ToDictionary(x => x.NodeId, x => x.NodeObjectType);
|
2019-10-29 09:57:32 +01:00
|
|
|
|
2019-11-06 16:45:28 +11:00
|
|
|
foreach (var e in entities)
|
2019-10-29 09:57:32 +01:00
|
|
|
{
|
2019-11-06 16:45:28 +11:00
|
|
|
if (nodes.TryGetValue(e.ParentId, out var parentObjectType))
|
|
|
|
|
{
|
|
|
|
|
e.ParentObjectType = parentObjectType.GetValueOrDefault();
|
|
|
|
|
}
|
|
|
|
|
if (nodes.TryGetValue(e.ChildId, out var childObjectType))
|
|
|
|
|
{
|
|
|
|
|
e.ChildObjectType = childObjectType.GetValueOrDefault();
|
|
|
|
|
}
|
2019-10-29 09:57:32 +01:00
|
|
|
}
|
2019-10-24 21:32:00 +11:00
|
|
|
}
|
2019-11-06 14:35:15 +11:00
|
|
|
|
|
|
|
|
private void ApplyOrdering(ref Sql<ISqlContext> sql, Ordering ordering)
|
|
|
|
|
{
|
|
|
|
|
if (sql == null) throw new ArgumentNullException(nameof(sql));
|
|
|
|
|
if (ordering == null) throw new ArgumentNullException(nameof(ordering));
|
|
|
|
|
|
|
|
|
|
// TODO: although this works for name, it probably doesn't work for others without an alias of some sort
|
|
|
|
|
var orderBy = ordering.OrderBy;
|
|
|
|
|
|
|
|
|
|
if (ordering.Direction == Direction.Ascending)
|
|
|
|
|
sql.OrderBy(orderBy);
|
|
|
|
|
else
|
|
|
|
|
sql.OrderByDescending(orderBy);
|
|
|
|
|
}
|
2017-12-07 16:45:25 +01:00
|
|
|
}
|
|
|
|
|
}
|