Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ContentManagerSession in GetMany #8705

Draft
wants to merge 5 commits into
base: 1.10.x
Choose a base branch
from
103 changes: 83 additions & 20 deletions src/Orchard/ContentManagement/DefaultContentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,40 +281,103 @@ public virtual IEnumerable<ContentItem> GetAllVersions(int id) {
.Where(ci => ci != null);
}

private ContentItemVersionRecord VersionRecordFromSession(int id, VersionOptions options) {

var session = _contentManagerSession();
ContentItem contentItem;

if (options.VersionRecordId != 0) {
if (session.RecallVersionRecordId(options.VersionRecordId, out contentItem)) {
return contentItem.VersionRecord;
}
return _contentItemVersionRepository.Get(options.VersionRecordId);
}
else if (session.RecallContentRecordId(id, out contentItem)) {
return contentItem.VersionRecord;
}

return null;
}
private void StoreVersionInSession(ContentItemVersionRecord versionRecord) {
var session = _contentManagerSession();
// allocate instance and set record property
var contentItem = New(versionRecord.ContentItemRecord.ContentType.Name);
contentItem.VersionRecord = versionRecord;

// store in session prior to loading to avoid some problems with simple circular dependencies
session.Store(contentItem);
}

public IEnumerable<T> GetMany<T>(IEnumerable<int> ids, VersionOptions options, QueryHints hints) where T : class, IContent {
if (!ids.Any()) {
// since there are no ids, I have to get no item, so it makes
// sense to not do anything at all
return Enumerable.Empty<T>();
}
var contentItemVersionRecords = GetManyImplementation(hints, (contentItemCriteria, contentItemVersionCriteria) => {
contentItemCriteria.Add(Restrictions.In("Id", ids.ToArray()));
if (options.IsPublished) {
contentItemVersionCriteria.Add(Restrictions.Eq("Published", true));
}
else if (options.IsLatest) {
contentItemVersionCriteria.Add(Restrictions.Eq("Latest", true));
}
else if (options.IsDraft && !options.IsDraftRequired) {
contentItemVersionCriteria.Add(
Restrictions.And(Restrictions.Eq("Published", false),
Restrictions.Eq("Latest", true)));
}
else if (options.IsDraft || options.IsDraftRequired) {
contentItemVersionCriteria.Add(Restrictions.Eq("Latest", true));
// For each Id passed, check if it's already held in the session, to avoid querying for it
// again. Where this collection has null values, it means the object wasn't in session.
var allVersionRecords = ids
.Select(id => VersionRecordFromSession(id, options))
.ToArray();
// We only need to query for those contents we did not have in session.
var indexedIdsToQuery = ids
.Select((val, idx) => new { Index = idx, Id = val })
.Where(indexedId => allVersionRecords[indexedId.Index] == null)
.ToArray();

if (indexedIdsToQuery.Any()) {
var contentItemVersionRecords = GetManyImplementation(hints, (contentItemCriteria, contentItemVersionCriteria) => {
contentItemCriteria.Add(Restrictions.In("Id", indexedIdsToQuery.Select(o => o.Id).ToArray()));
if (options.IsPublished) {
contentItemVersionCriteria.Add(Restrictions.Eq("Published", true));
}
else if (options.IsLatest) {
contentItemVersionCriteria.Add(Restrictions.Eq("Latest", true));
}
else if (options.IsDraft && !options.IsDraftRequired) {
contentItemVersionCriteria.Add(
Restrictions.And(Restrictions.Eq("Published", false),
Restrictions.Eq("Latest", true)));
}
else if (options.IsDraft || options.IsDraftRequired) {
contentItemVersionCriteria.Add(Restrictions.Eq("Latest", true));
}
});

// Replace null values in the first collection with the records we fetched. Now we have all
// records we were looking for, rather than only those from session.
var currentIndex = 0;
var currentIndexedId = indexedIdsToQuery[0];
foreach (var foundRecord in contentItemVersionRecords) {
var foundRecordId = foundRecord.ContentItemRecord.Id;
// This assumes that the results from the query are in the order of the ids we passed
while (currentIndexedId.Id != foundRecordId) {
currentIndex++;
if (currentIndex >= indexedIdsToQuery.Length) {
break;
}
currentIndexedId = indexedIdsToQuery[currentIndex];
}
if (currentIndexedId.Id != foundRecordId) {
break;
}
// found Index to replace the record we fetched to the null we had initially
allVersionRecords[currentIndexedId.Index] = foundRecord;
StoreVersionInSession(foundRecord);
}
});
}

var itemsById = contentItemVersionRecords
var itemsById = allVersionRecords
.Where(r => r != null)
.Select(r => Get(r.ContentItemRecord.Id, options.IsDraftRequired ? options : VersionOptions.VersionRecord(r.Id)))
.Where(ci => ci != null)
.GroupBy(ci => ci.Id)
.ToDictionary(g => g.Key);

return ids.SelectMany(id => {
IGrouping<int, ContentItem> values;
return itemsById.TryGetValue(id, out values) ? values : Enumerable.Empty<ContentItem>();
}).AsPart<T>().ToArray();
IGrouping<int, ContentItem> values;
return itemsById.TryGetValue(id, out values) ? values : Enumerable.Empty<ContentItem>();
}).AsPart<T>().ToArray();
}


Expand Down
Loading