localizationpartdriver refactor (#8366)

* Performance on LocalizationPart
Prevent driver from repeating the same query several times in a request (it used
to try and fetch all of a part's localizations at least twice per request).
Changed query for a MasterContentItem's localizations so it should "hint" sql to
use different indexes.
This commit is contained in:
Matteo Piovanelli
2020-05-07 19:27:58 +02:00
committed by GitHub
parent 8a327cf887
commit 9d1267a94c

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
@@ -18,6 +19,9 @@ namespace Orchard.Localization.Drivers {
_cultureManager = cultureManager;
_localizationService = localizationService;
_contentManager = contentManager;
publishedLocalizations = new Dictionary<int, IEnumerable<LocalizationPart>>();
latestLocalizations = new Dictionary<int, IEnumerable<LocalizationPart>>();
}
protected override DriverResult Display(LocalizationPart part, string displayType, dynamic shapeHelper) {
@@ -69,10 +73,14 @@ namespace Orchard.Localization.Drivers {
protected override DriverResult Editor(LocalizationPart part, IUpdateModel updater, dynamic shapeHelper) {
var model = new EditLocalizationViewModel();
// GetCulture(part) is checked against null value, because the content culture has to be set only if it's not set already.
// model.SelectedCulture is checked against null value, because the editor group may not contain LocalizationPart when the content item is saved for the first time.
if (updater != null && updater.TryUpdateModel(model, TemplatePrefix, null, null) && GetCulture(part) == null && !string.IsNullOrEmpty(model.SelectedCulture)) {
if (updater != null && updater.TryUpdateModel(model, TemplatePrefix, null, null)
// GetCulture(part) is checked against null value, because the content
// culture has to be set only if it's not set already.
&& GetCulture(part) == null
// model.SelectedCulture is checked against null value, because the editor
// group may not contain LocalizationPart when the content item is saved for
// the first time.
&& !string.IsNullOrEmpty(model.SelectedCulture)) {
_localizationService.SetContentCulture(part, model.SelectedCulture);
}
@@ -98,16 +106,52 @@ namespace Orchard.Localization.Drivers {
return part.Culture != null ? part.Culture.Culture : null;
}
private IEnumerable<LocalizationPart> GetDisplayLocalizations(LocalizationPart part, VersionOptions versionOptions) {
return _localizationService.GetLocalizations(part.ContentItem, versionOptions)
.Where(c => c.Culture != null)
.ToList();
private Dictionary<int, IEnumerable<LocalizationPart>> publishedLocalizations;
private Dictionary<int, IEnumerable<LocalizationPart>> latestLocalizations;
private IEnumerable<LocalizationPart> GetDisplayLocalizations(
LocalizationPart part, VersionOptions versionOptions) {
Func<IEnumerable<LocalizationPart>> actualMethod = () =>
_localizationService.GetLocalizations(part.ContentItem, versionOptions)
.Where(c => c.Culture != null)
.ToList();
// if the part has no assigned culture, and it does not belong to
// a translation group, it cannot possibly have localizations
if (GetCulture(part) == null && !part.HasTranslationGroup) {
actualMethod = () => Enumerable.Empty<LocalizationPart>();
// this empty list will be "cached" for the part for the duration
// a request, in order to prevent asking the db to return something
// that we know to not be there. This should prevent a class of
// deadlocks on the indexes for the LocalizationPartRecord table.
// The reasoning:
// part.HasTranslationGroup is false when the content is not a
// localization of any other content. It may be a MasterContent,
// but if that were the case it would have a value for its Culture.
// The condition here represents a new ContentItem, that has never
// had an assigned culture (whether it's actually new, or the
// LocalizationPart has just been welded to its type)
}
if (versionOptions.IsPublished) {
if (!publishedLocalizations.ContainsKey(part.Id)) {
publishedLocalizations.Add(
part.Id,
actualMethod());
}
return publishedLocalizations[part.Id];
} else if (versionOptions.IsLatest) {
if (!latestLocalizations.ContainsKey(part.Id)) {
latestLocalizations.Add(
part.Id,
actualMethod());
}
return latestLocalizations[part.Id];
}
return actualMethod();
}
private IEnumerable<LocalizationPart> GetEditorLocalizations(LocalizationPart part) {
return _localizationService.GetLocalizations(part.ContentItem, VersionOptions.Latest)
.Where(c => c.Culture != null)
.ToList();
return GetDisplayLocalizations(part, VersionOptions.Latest);
}
protected override void Importing(LocalizationPart part, ImportContentContext context) {