From 55db973e82a55a986b0720fb77d150adcacdb02f Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 8 Oct 2020 14:37:17 +0200 Subject: [PATCH] Introduced IRelationRepository.SaveBulk to use internally when performance is important. Fixed issue in RelationRepository.Save not populating Ids on LocalDB/SqlServer --- src/Umbraco.Core/Models/IRelation.cs | 58 ++++++++++++++++--- .../Repositories/IRelationRepository.cs | 6 ++ .../Persistence/Factories/RelationFactory.cs | 2 +- .../Implement/ContentRepositoryBase.cs | 2 +- .../Implement/RelationRepository.cs | 43 +++++++++++++- 5 files changed, 99 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Core/Models/IRelation.cs b/src/Umbraco.Core/Models/IRelation.cs index 6bd348d72f..3cdea02e32 100644 --- a/src/Umbraco.Core/Models/IRelation.cs +++ b/src/Umbraco.Core/Models/IRelation.cs @@ -4,37 +4,81 @@ using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models { - public interface IRelation : IEntity, IRememberBeingDirty + public interface IRelation : IRememberBeingDirty, IRelationReadOnly { + + /// + /// Gets or sets the integer identifier of the entity. + /// + new int Id { get; set; } + /// /// Gets or sets the Parent Id of the Relation (Source) /// [DataMember] - int ParentId { get; set; } + new int ParentId { get; set; } [DataMember] - Guid ParentObjectType { get; set; } + new Guid ParentObjectType { get; set; } /// /// Gets or sets the Child Id of the Relation (Destination) /// [DataMember] - int ChildId { get; set; } + new int ChildId { get; set; } [DataMember] - Guid ChildObjectType { get; set; } + new Guid ChildObjectType { get; set; } /// /// Gets or sets the for the Relation /// [DataMember] - IRelationType RelationType { get; set; } + new IRelationType RelationType { get; set; } /// /// Gets or sets a comment for the Relation /// [DataMember] - string Comment { get; set; } + new string Comment { get; set; } + + /// + /// Gets the Id of the that this Relation is based on. + /// + [IgnoreDataMember] + new int RelationTypeId { get; } + } + + public interface IRelationReadOnly : IEntity + { + /// + /// Gets the integer identifier of the entity. + /// + int Id { get; } + + /// + /// Gets the Parent Id of the Relation (Source) + /// + int ParentId { get; } + + Guid ParentObjectType { get; } + + /// + /// Gets or sets the Child Id of the Relation (Destination) + /// + int ChildId { get; } + + Guid ChildObjectType { get; } + + /// + /// Gets the for the Relation + /// + IRelationType RelationType { get; } + + /// + /// Gets a comment for the Relation + /// + string Comment { get; } /// /// Gets the Id of the that this Relation is based on. diff --git a/src/Umbraco.Core/Persistence/Repositories/IRelationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IRelationRepository.cs index fc1be20e6f..8f17b5f622 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IRelationRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IRelationRepository.cs @@ -17,6 +17,12 @@ namespace Umbraco.Core.Persistence.Repositories /// void Save(IEnumerable relations); + /// + /// Persist multiple at once but Ids are not returned on created relations + /// + /// + void SaveBulk(IEnumerable relations); + /// /// Deletes all relations for a parent for any specified relation type alias /// diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs index d8f100cdbe..2adfe9627c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs @@ -28,7 +28,7 @@ namespace Umbraco.Core.Persistence.Factories } } - public static RelationDto BuildDto(IRelation entity) + public static RelationDto BuildDto(IRelationReadOnly entity) { var dto = new RelationDto { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs index b8edbd051a..e59acb0e81 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -984,7 +984,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement }).WhereNotNull(); // Save bulk relations - RelationRepository.Save(toSave); + RelationRepository.SaveBulk(toSave); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs index 3767fa354c..88231d3658 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs @@ -235,9 +235,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement }, RelationFactory.BuildDto); // value = DTO - // Use NPoco's own InsertBulk command which will automatically re-populate the new Ids on the entities, our own - // BulkInsertRecords does not cater for this. - Database.InsertBulk(entitiesAndDtos.Values); + + foreach (var dto in entitiesAndDtos.Values) + { + Database.Insert(dto); + } // All dtos now have IDs assigned foreach (var de in entitiesAndDtos) @@ -251,6 +253,41 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } } + public void SaveBulk(IEnumerable 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. + foreach (var relation in hasIdentityGroup) + { + relation.UpdatingEntity(); + var dto = RelationFactory.BuildDto(relation); + Database.Update(dto); + } + } + else + { + // Do bulk inserts + var entitiesAndDtos = hasIdentityGroup.ToDictionary( + r => // key = entity + { + r.AddingEntity(); + return r; + }, + RelationFactory.BuildDto); // value = DTO + + + Database.InsertBulk(entitiesAndDtos.Values); + + } + } + } + public IEnumerable GetPagedRelationsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, Ordering ordering) { var sql = GetBaseQuery(false);