Moves the CRUD logic from the media service to the media repo for dealing with content xml items and ensures it's done in the same transaction, streamlines how this process is done between the content, media, member services, adds test for it.

This commit is contained in:
Shannon
2014-04-28 18:53:21 +10:00
parent c5bce3b8cc
commit 2e96de5449
10 changed files with 100 additions and 65 deletions

View File

@@ -8,12 +8,13 @@ namespace Umbraco.Core.Models
/// Used in content/media/member repositories in order to add this type of entity to the persisted collection to be saved
/// in a single transaction during saving an entity
/// </summary>
internal class ContentXmlEntity : IAggregateRoot
internal class ContentXmlEntity<TContent> : IAggregateRoot
where TContent : IContentBase
{
private readonly bool _entityExists;
private readonly Func<XElement> _xml;
private readonly Func<TContent, XElement> _xml;
public ContentXmlEntity(bool entityExists, IContentBase content, Func<XElement> xml)
public ContentXmlEntity(bool entityExists, TContent content, Func<TContent, XElement> xml)
{
if (content == null) throw new ArgumentNullException("content");
_entityExists = entityExists;
@@ -23,9 +24,9 @@ namespace Umbraco.Core.Models
public XElement Xml
{
get { return _xml(); }
get { return _xml(Content); }
}
public IContentBase Content { get; private set; }
public TContent Content { get; private set; }
public int Id
{
@@ -44,7 +45,7 @@ namespace Umbraco.Core.Models
public object DeepClone()
{
var clone = (ContentXmlEntity)MemberwiseClone();
var clone = (ContentXmlEntity<TContent>)MemberwiseClone();
//Automatically deep clone ref properties that are IDeepCloneable
DeepCloneHelper.DeepCloneRefProperties(this, clone);
return clone;

View File

@@ -13,6 +13,7 @@ using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
@@ -26,7 +27,7 @@ namespace Umbraco.Core.Persistence.Repositories
private readonly ITemplateRepository _templateRepository;
private readonly CacheHelper _cacheHelper;
private readonly ContentPreviewRepository _contentPreviewRepository;
private readonly ContentXmlRepository _contentXmlRepository;
private readonly ContentXmlRepository<IContent> _contentXmlRepository;
public ContentRepository(IDatabaseUnitOfWork work, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, CacheHelper cacheHelper)
: base(work)
@@ -35,7 +36,7 @@ namespace Umbraco.Core.Persistence.Repositories
_templateRepository = templateRepository;
_cacheHelper = cacheHelper;
_contentPreviewRepository = new ContentPreviewRepository(work, NullCacheProvider.Current);
_contentXmlRepository = new ContentXmlRepository(work, NullCacheProvider.Current);
_contentXmlRepository = new ContentXmlRepository<IContent>(work, NullCacheProvider.Current);
EnsureUniqueNaming = true;
}
@@ -47,7 +48,7 @@ namespace Umbraco.Core.Persistence.Repositories
_templateRepository = templateRepository;
_cacheHelper = cacheHelper;
_contentPreviewRepository = new ContentPreviewRepository(work, NullCacheProvider.Current);
_contentXmlRepository = new ContentXmlRepository(work, NullCacheProvider.Current);
_contentXmlRepository = new ContentXmlRepository<IContent>(work, NullCacheProvider.Current);
EnsureUniqueNaming = true;
}
@@ -566,18 +567,20 @@ namespace Umbraco.Core.Persistence.Repositories
/// Adds/updates content/published xml
/// </summary>
/// <param name="content"></param>
public void AddOrUpdateContentXml(IContent content, Func<XElement> xml)
/// <param name="xml"></param>
public void AddOrUpdateContentXml(IContent content, Func<IContent, XElement> xml)
{
var contentExists = Database.ExecuteScalar<int>("SELECT COUNT(nodeId) FROM cmsContentXml WHERE nodeId = @Id", new { Id = content.Id }) != 0;
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity(contentExists, content, xml));
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IContent>(contentExists, content, xml));
}
/// <summary>
/// Adds/updates preview xml
/// </summary>
/// <param name="content"></param>
public void AddOrUpdatePreviewXml(IContent content, Func<XElement> xml)
/// <param name="xml"></param>
public void AddOrUpdatePreviewXml(IContent content, Func<IContent, XElement> xml)
{
var previewExists =
Database.ExecuteScalar<int>("SELECT COUNT(nodeId) FROM cmsPreviewXml WHERE nodeId = @Id AND versionId = @Version",
@@ -585,7 +588,7 @@ namespace Umbraco.Core.Persistence.Repositories
_contentPreviewRepository.AddOrUpdate(new ContentPreviewEntity(previewExists, content, xml));
}
#endregion
/// <summary>
@@ -653,9 +656,9 @@ namespace Umbraco.Core.Persistence.Repositories
/// Used content repository in order to add an entity to the persisted collection to be saved
/// in a single transaction during saving an entity
/// </summary>
private class ContentPreviewEntity : ContentXmlEntity
private class ContentPreviewEntity : ContentXmlEntity<IContent>
{
public ContentPreviewEntity(bool previewExists, IContentBase content, Func<XElement> xml)
public ContentPreviewEntity(bool previewExists, IContent content, Func<IContent, XElement> xml)
: base(previewExists, content, xml)
{
Version = content.Version;

View File

@@ -12,7 +12,8 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Internal class to handle content/published xml insert/update based on standard principles and units of work with transactions
/// </summary>
internal class ContentXmlRepository : PetaPocoRepositoryBase<int, ContentXmlEntity>
internal class ContentXmlRepository<TContent> : PetaPocoRepositoryBase<int, ContentXmlEntity<TContent>>
where TContent : IContentBase
{
public ContentXmlRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
@@ -20,17 +21,17 @@ namespace Umbraco.Core.Persistence.Repositories
}
#region Not implemented (don't need to for the purposes of this repo)
protected override ContentXmlEntity PerformGet(int id)
protected override ContentXmlEntity<TContent> PerformGet(int id)
{
throw new NotImplementedException();
}
protected override IEnumerable<ContentXmlEntity> PerformGetAll(params int[] ids)
protected override IEnumerable<ContentXmlEntity<TContent>> PerformGetAll(params int[] ids)
{
throw new NotImplementedException();
}
protected override IEnumerable<ContentXmlEntity> PerformGetByQuery(IQuery<ContentXmlEntity> query)
protected override IEnumerable<ContentXmlEntity<TContent>> PerformGetByQuery(IQuery<ContentXmlEntity<TContent>> query)
{
throw new NotImplementedException();
}
@@ -55,13 +56,13 @@ namespace Umbraco.Core.Persistence.Repositories
get { throw new NotImplementedException(); }
}
protected override void PersistDeletedItem(ContentXmlEntity entity)
protected override void PersistDeletedItem(ContentXmlEntity<TContent> entity)
{
throw new NotImplementedException();
}
#endregion
protected override void PersistNewItem(ContentXmlEntity entity)
protected override void PersistNewItem(ContentXmlEntity<TContent> entity)
{
if (entity.Content.HasIdentity == false)
{
@@ -72,7 +73,7 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Insert(poco);
}
protected override void PersistUpdatedItem(ContentXmlEntity entity)
protected override void PersistUpdatedItem(ContentXmlEntity<TContent> entity)
{
if (entity.Content.HasIdentity == false)
{

View File

@@ -44,13 +44,14 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
/// <param name="content"></param>
/// <param name="xml"></param>
void AddOrUpdateContentXml(IContent content, Func<XElement> xml);
void AddOrUpdateContentXml(IContent content, Func<IContent, XElement> xml);
/// <summary>
/// Used to add/update preview xml for the content item
/// </summary>
/// <param name="content"></param>
/// <param name="xml"></param>
void AddOrUpdatePreviewXml(IContent content, Func<XElement> xml);
void AddOrUpdatePreviewXml(IContent content, Func<IContent, XElement> xml);
}
}

View File

@@ -1,8 +1,18 @@
using Umbraco.Core.Models;
using System;
using System.Xml.Linq;
using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IMediaRepository : IRepositoryVersionable<int, IMedia>
{
/// <summary>
/// Used to add/update published xml for the media item
/// </summary>
/// <param name="content"></param>
/// <param name="xml"></param>
void AddOrUpdateContentXml(IMedia content, Func<IMedia, XElement> xml);
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
@@ -20,11 +21,13 @@ namespace Umbraco.Core.Persistence.Repositories
internal class MediaRepository : VersionableRepositoryBase<int, IMedia>, IMediaRepository
{
private readonly IMediaTypeRepository _mediaTypeRepository;
private readonly ContentXmlRepository<IMedia> _contentXmlRepository;
public MediaRepository(IDatabaseUnitOfWork work, IMediaTypeRepository mediaTypeRepository)
: base(work)
{
_mediaTypeRepository = mediaTypeRepository;
_contentXmlRepository = new ContentXmlRepository<IMedia>(work, NullCacheProvider.Current);
EnsureUniqueNaming = true;
}
@@ -33,6 +36,7 @@ namespace Umbraco.Core.Persistence.Repositories
: base(work, cache)
{
_mediaTypeRepository = mediaTypeRepository;
_contentXmlRepository = new ContentXmlRepository<IMedia>(work, NullCacheProvider.Current);
EnsureUniqueNaming = true;
}
@@ -174,6 +178,13 @@ namespace Umbraco.Core.Persistence.Repositories
return media;
}
public void AddOrUpdateContentXml(IMedia content, Func<IMedia, XElement> xml)
{
var contentExists = Database.ExecuteScalar<int>("SELECT COUNT(nodeId) FROM cmsContentXml WHERE nodeId = @Id", new { Id = content.Id }) != 0;
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IMedia>(contentExists, content, xml));
}
protected override void PerformDeleteVersion(int id, Guid versionId)
{
Database.Delete<PreviewXmlDto>("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId });

View File

@@ -1350,15 +1350,13 @@ namespace Umbraco.Core.Services
repository.AddOrUpdate(content);
//Generate a new preview
var local = content;
repository.AddOrUpdatePreviewXml(content, () => _entitySerializer.Serialize(this, _dataTypeService, local));
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
}
foreach (var content in shouldBePublished)
{
//Create and Save ContentXml DTO
var local = content;
repository.AddOrUpdateContentXml(content, () => _entitySerializer.Serialize(this, _dataTypeService, local));
repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
}
uow.Commit();
@@ -1511,6 +1509,8 @@ namespace Umbraco.Core.Services
//TODO: WE should make a base class for ContentService and MediaService to share!
// currently we have this logic duplicated (nearly the same) for media types and soon to be member types
//TODO: This needs to be put into the ContentRepository, all CUD logic!
/// <summary>
/// Rebuilds all xml content in the cmsContentXml table for all documents
/// </summary>
@@ -1776,13 +1776,12 @@ namespace Umbraco.Core.Services
repository.AddOrUpdate(content);
//Generate a new preview
var local = content;
repository.AddOrUpdatePreviewXml(content, () => _entitySerializer.Serialize(this, _dataTypeService, local));
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
if (published)
{
//Content Xml
repository.AddOrUpdateContentXml(content, () => _entitySerializer.Serialize(this, _dataTypeService, local));
repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
}
uow.Commit();
@@ -1844,8 +1843,7 @@ namespace Umbraco.Core.Services
repository.AddOrUpdate(content);
//Generate a new preview
var local = content;
repository.AddOrUpdatePreviewXml(content, () => _entitySerializer.Serialize(this, _dataTypeService, local));
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
uow.Commit();
}

View File

@@ -10,6 +10,8 @@ using umbraco.interfaces;
namespace Umbraco.Core.Services
{
//TODO: Move the rest of the logic for the PackageService.Export methods to here!
/// <summary>
/// A helper class to serialize entities to XML
/// </summary>

View File

@@ -156,10 +156,10 @@ namespace Umbraco.Core.Services
{
media.CreatorId = userId;
repository.AddOrUpdate(media);
uow.Commit();
var xml = _entitySerializer.Serialize(this, _dataTypeService, media);
CreateAndSaveMediaXml(xml, media.Id, uow.Database);
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, m));
uow.Commit();
}
}
@@ -211,10 +211,8 @@ namespace Umbraco.Core.Services
{
media.CreatorId = userId;
repository.AddOrUpdate(media);
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, m));
uow.Commit();
var xml = _entitySerializer.Serialize(this, _dataTypeService, media);
CreateAndSaveMediaXml(xml, media.Id, uow.Database);
}
}
@@ -809,10 +807,9 @@ namespace Umbraco.Core.Services
{
media.CreatorId = userId;
repository.AddOrUpdate(media);
uow.Commit();
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, m));
var xml = _entitySerializer.Serialize(this, _dataTypeService, media);
CreateAndSaveMediaXml(xml, media.Id, uow.Database);
uow.Commit();
}
}
@@ -847,16 +844,11 @@ namespace Umbraco.Core.Services
{
media.CreatorId = userId;
repository.AddOrUpdate(media);
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, m));
}
//commit the whole lot in one go
uow.Commit();
foreach (var media in asArray)
{
var xml = _entitySerializer.Serialize(this, _dataTypeService, media);
CreateAndSaveMediaXml(xml, media.Id, uow.Database);
}
}
if (raiseEvents)
@@ -884,8 +876,6 @@ namespace Umbraco.Core.Services
return false;
}
var shouldBeCached = new List<IMedia>();
using (new WriteLock(Locker))
{
var uow = _uowProvider.GetUnitOfWork();
@@ -907,17 +897,10 @@ namespace Umbraco.Core.Services
i++;
repository.AddOrUpdate(media);
shouldBeCached.Add(media);
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, m));
}
uow.Commit();
foreach (var content in shouldBeCached)
{
//Create and Save ContentXml DTO
var xml = _entitySerializer.Serialize(this, _dataTypeService, content);
CreateAndSaveMediaXml(xml, content.Id, uow.Database);
}
}
}
@@ -929,6 +912,8 @@ namespace Umbraco.Core.Services
return true;
}
//TODO: This needs to be put into the MediaRepository, all CUD logic!
/// <summary>
/// Rebuilds all xml content in the cmsContentXml table for all media
/// </summary>
@@ -1052,12 +1037,12 @@ namespace Umbraco.Core.Services
return list;
}
private void CreateAndSaveMediaXml(XElement xml, int id, UmbracoDatabase db)
{
var poco = new ContentXmlDto { NodeId = id, Xml = xml.ToString(SaveOptions.None) };
var exists = db.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = id }) != null;
int result = exists ? db.Update(poco) : Convert.ToInt32(db.Insert(poco));
}
//private void CreateAndSaveMediaXml(XElement xml, int id, UmbracoDatabase db)
//{
// var poco = new ContentXmlDto { NodeId = id, Xml = xml.ToString(SaveOptions.None) };
// var exists = db.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = id }) != null;
// int result = exists ? db.Update(poco) : Convert.ToInt32(db.Insert(poco));
//}
private IMediaType FindMediaTypeByAlias(string mediaTypeAlias)
{