diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxContext.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxContext.cs index 9fe69a4ca9..34d2ff616b 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxContext.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxContext.cs @@ -23,4 +23,24 @@ namespace Umbraco.Core.Persistence.SqlSyntax set { _sqlSyntaxProvider = value; } } } + + internal static class SqlSyntaxProviderExtensions + { + /// + /// This is used to generate a delete query that uses a sub-query to select the data, it is required because there's a very particular syntax that + /// needs to be used to work for all servers: MySql, SQLCE and MSSQL + /// + /// + /// + /// See: http://issues.umbraco.org/issue/U4-3876 + /// + public static string GetDeleteSubquery(this ISqlSyntaxProvider sqlProvider, string tableName, string columnName, Sql subQuery) + { + return string.Format(@"DELETE FROM {0} WHERE {1} IN (SELECT {1} FROM ({2}) x)", + sqlProvider.GetQuotedTableName(tableName), + sqlProvider.GetQuotedColumnName(columnName), + subQuery.SQL); + } + + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index ea0d8464a2..5ce8beb988 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -10,51 +10,52 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Publishing; namespace Umbraco.Core.Services { /// - /// Represents the Media Service, which is an easy access to operations involving - /// - public class MediaService : IMediaService - { - private readonly IDatabaseUnitOfWorkProvider _uowProvider; - private readonly RepositoryFactory _repositoryFactory; + /// Represents the Media Service, which is an easy access to operations involving + /// + public class MediaService : IMediaService + { + private readonly IDatabaseUnitOfWorkProvider _uowProvider; + private readonly RepositoryFactory _repositoryFactory; //Support recursive locks because some of the methods that require locking call other methods that require locking. //for example, the Move method needs to be locked but this calls the Save method which also needs to be locked. - private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - public MediaService(RepositoryFactory repositoryFactory) - : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory) - { - } + public MediaService(RepositoryFactory repositoryFactory) + : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory) + { + } - public MediaService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory) - { - _uowProvider = provider; - _repositoryFactory = repositoryFactory; - } + public MediaService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory) + { + _uowProvider = provider; + _repositoryFactory = repositoryFactory; + } - /// - /// Creates an object using the alias of the + /// + /// Creates an object using the alias of the /// that this Media should based on. - /// + /// /// /// Note that using this method will simply return a new IMedia without any identity /// as it has not yet been persisted. It is intended as a shortcut to creating new media objects /// that does not invoke a save operation against the database. /// /// Name of the Media object - /// Id of Parent for the new Media item - /// Alias of the - /// Optional id of the user creating the media item - /// - public IMedia CreateMedia(string name, int parentId, string mediaTypeAlias, int userId = 0) - { + /// Id of Parent for the new Media item + /// Alias of the + /// Optional id of the user creating the media item + /// + public IMedia CreateMedia(string name, int parentId, string mediaTypeAlias, int userId = 0) + { var mediaType = FindMediaTypeByAlias(mediaTypeAlias); - var media = new Models.Media(name, parentId, mediaType); + var media = new Models.Media(name, parentId, mediaType); if (Creating.IsRaisedEventCancelled(new NewEventArgs(media, mediaTypeAlias, parentId), this)) { @@ -62,14 +63,14 @@ namespace Umbraco.Core.Services return media; } - media.CreatorId = userId; + media.CreatorId = userId; - Created.RaiseEvent(new NewEventArgs(media, false, mediaTypeAlias, parentId), this); + Created.RaiseEvent(new NewEventArgs(media, false, mediaTypeAlias, parentId), this); Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created", name), media.CreatorId, media.Id); - return media; - } + return media; + } /// /// Creates an object using the alias of the @@ -192,19 +193,19 @@ namespace Umbraco.Core.Services return media; } - /// - /// Gets an object by Id - /// - /// Id of the Content to retrieve - /// - public IMedia GetById(int id) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - return repository.Get(id); - } - } + /// + /// Gets an object by Id + /// + /// Id of the Content to retrieve + /// + public IMedia GetById(int id) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + return repository.Get(id); + } + } /// /// Gets an object by Id @@ -296,7 +297,7 @@ namespace Umbraco.Core.Services public IEnumerable GetAncestors(IMedia media) { var ids = media.Path.Split(',').Where(x => x != "-1" && x != media.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray(); - if(ids.Any() == false) + if (ids.Any() == false) return new List(); using (var repository = _repositoryFactory.CreateMediaRepository(_uowProvider.GetUnitOfWork())) @@ -305,33 +306,33 @@ namespace Umbraco.Core.Services } } - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// An Enumerable list of objects - public IEnumerable GetChildren(int id) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - var query = Query.Builder.Where(x => x.ParentId == id); - var medias = repository.GetByQuery(query); + /// + /// Gets a collection of objects by Parent Id + /// + /// Id of the Parent to retrieve Children from + /// An Enumerable list of objects + public IEnumerable GetChildren(int id) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + var query = Query.Builder.Where(x => x.ParentId == id); + var medias = repository.GetByQuery(query); - return medias; - } - } + return medias; + } + } - /// - /// Gets descendants of a object by its Id - /// - /// Id of the Parent to retrieve descendants from - /// An Enumerable flat list of objects - public IEnumerable GetDescendants(int id) - { + /// + /// Gets descendants of a object by its Id + /// + /// Id of the Parent to retrieve descendants from + /// An Enumerable flat list of objects + public IEnumerable GetDescendants(int id) + { var media = GetById(id); - return GetDescendants(media); - } + return GetDescendants(media); + } /// /// Gets descendants of a object by its Id @@ -374,54 +375,54 @@ namespace Umbraco.Core.Services return GetById(media.ParentId); } - /// - /// Gets a collection of objects by the Id of the - /// - /// Id of the - /// An Enumerable list of objects - public IEnumerable GetMediaOfMediaType(int id) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - var query = Query.Builder.Where(x => x.ContentTypeId == id); - var medias = repository.GetByQuery(query); + /// + /// Gets a collection of objects by the Id of the + /// + /// Id of the + /// An Enumerable list of objects + public IEnumerable GetMediaOfMediaType(int id) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + var query = Query.Builder.Where(x => x.ContentTypeId == id); + var medias = repository.GetByQuery(query); - return medias; - } - } + return medias; + } + } - /// - /// Gets a collection of objects, which reside at the first level / root - /// - /// An Enumerable list of objects - public IEnumerable GetRootMedia() - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - var query = Query.Builder.Where(x => x.ParentId == -1); - var medias = repository.GetByQuery(query); + /// + /// Gets a collection of objects, which reside at the first level / root + /// + /// An Enumerable list of objects + public IEnumerable GetRootMedia() + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + var query = Query.Builder.Where(x => x.ParentId == -1); + var medias = repository.GetByQuery(query); - return medias; - } - } + return medias; + } + } - /// - /// Gets a collection of an objects, which resides in the Recycle Bin - /// - /// An Enumerable list of objects - public IEnumerable GetMediaInRecycleBin() - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - var query = Query.Builder.Where(x => x.Path.Contains("-21")); - var medias = repository.GetByQuery(query); + /// + /// Gets a collection of an objects, which resides in the Recycle Bin + /// + /// An Enumerable list of objects + public IEnumerable GetMediaInRecycleBin() + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + var query = Query.Builder.Where(x => x.Path.Contains("-21")); + var medias = repository.GetByQuery(query); - return medias; - } - } + return medias; + } + } /// /// Gets an object from the path stored in the 'umbracoFile' property. @@ -432,11 +433,11 @@ namespace Umbraco.Core.Services { var umbracoFileValue = mediaPath; var isResized = mediaPath.Contains("_") && mediaPath.Contains("x"); - + // If the image has been resized we strip the "_403x328" of the original "/media/1024/koala_403x328.jpg" url. if (isResized) { - + var underscoreIndex = mediaPath.LastIndexOf('_'); var dotIndex = mediaPath.LastIndexOf('.'); umbracoFileValue = string.Concat(mediaPath.Substring(0, underscoreIndex), mediaPath.Substring(dotIndex)); @@ -472,75 +473,75 @@ namespace Umbraco.Core.Services } } - /// - /// Moves an object to a new location - /// - /// The to move - /// Id of the Media's new Parent - /// Id of the User moving the Media - public void Move(IMedia media, int parentId, int userId = 0) - { - if (media == null) throw new ArgumentNullException("media"); + /// + /// Moves an object to a new location + /// + /// The to move + /// Id of the Media's new Parent + /// Id of the User moving the Media + public void Move(IMedia media, int parentId, int userId = 0) + { + if (media == null) throw new ArgumentNullException("media"); - using (new WriteLock(Locker)) - { - //This ensures that the correct method is called if this method is used to Move to recycle bin. - if (parentId == -21) - { - MoveToRecycleBin(media, userId); - return; - } + using (new WriteLock(Locker)) + { + //This ensures that the correct method is called if this method is used to Move to recycle bin. + if (parentId == -21) + { + MoveToRecycleBin(media, userId); + return; + } - if (Moving.IsRaisedEventCancelled(new MoveEventArgs(media, parentId), this)) - return; + if (Moving.IsRaisedEventCancelled(new MoveEventArgs(media, parentId), this)) + return; media.ParentId = parentId; if (media.Trashed) { media.ChangeTrashedState(false, parentId); } - Save(media, userId); + Save(media, userId); - //Ensure that relevant properties are updated on children - var children = GetChildren(media.Id).ToArray(); - if (children.Any()) - { - var parentPath = media.Path; - var parentLevel = media.Level; - var parentTrashed = media.Trashed; - var updatedDescendants = UpdatePropertiesOnChildren(children, parentPath, parentLevel, parentTrashed); - Save(updatedDescendants, userId); - } + //Ensure that relevant properties are updated on children + var children = GetChildren(media.Id).ToArray(); + if (children.Any()) + { + var parentPath = media.Path; + var parentLevel = media.Level; + var parentTrashed = media.Trashed; + var updatedDescendants = UpdatePropertiesOnChildren(children, parentPath, parentLevel, parentTrashed); + Save(updatedDescendants, userId); + } - Moved.RaiseEvent(new MoveEventArgs(media, false, parentId), this); + Moved.RaiseEvent(new MoveEventArgs(media, false, parentId), this); - Audit.Add(AuditTypes.Move, "Move Media performed by user", userId, media.Id); - } - } + Audit.Add(AuditTypes.Move, "Move Media performed by user", userId, media.Id); + } + } /// - /// Deletes an object by moving it to the Recycle Bin - /// - /// The to delete - /// Id of the User deleting the Media - public void MoveToRecycleBin(IMedia media, int userId = 0) - { + /// Deletes an object by moving it to the Recycle Bin + /// + /// The to delete + /// Id of the User deleting the Media + public void MoveToRecycleBin(IMedia media, int userId = 0) + { if (media == null) throw new ArgumentNullException("media"); if (Trashing.IsRaisedEventCancelled(new MoveEventArgs(media, -21), this)) - return; + return; //Find Descendants, which will be moved to the recycle bin along with the parent/grandparent. var descendants = GetDescendants(media).OrderBy(x => x.Level).ToList(); - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { //Remove 'published' xml from the cmsContentXml table for the unpublished media uow.Database.Delete("WHERE nodeId = @Id", new { Id = media.Id }); - media.ChangeTrashedState(true, -21); - repository.AddOrUpdate(media); + media.ChangeTrashedState(true, -21); + repository.AddOrUpdate(media); //Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId foreach (var descendant in descendants) @@ -552,19 +553,19 @@ namespace Umbraco.Core.Services repository.AddOrUpdate(descendant); } - uow.Commit(); - } + uow.Commit(); + } - Trashed.RaiseEvent(new MoveEventArgs(media, false, -21), this); + Trashed.RaiseEvent(new MoveEventArgs(media, false, -21), this); - Audit.Add(AuditTypes.Move, "Move Media to Recycle Bin performed by user", userId, media.Id); - } + Audit.Add(AuditTypes.Move, "Move Media to Recycle Bin performed by user", userId, media.Id); + } - /// - /// Empties the Recycle Bin by deleting all that resides in the bin - /// - public void EmptyRecycleBin() - { + /// + /// Empties the Recycle Bin by deleting all that resides in the bin + /// + public void EmptyRecycleBin() + { using (new WriteLock(Locker)) { List ids; @@ -588,65 +589,65 @@ namespace Umbraco.Core.Services EmptiedRecycleBin.RaiseEvent(new RecycleBinEventArgs(nodeObjectType, ids, files, success), this); } Audit.Add(AuditTypes.Delete, "Empty Media Recycle Bin performed by user", 0, -21); - } - - /// - /// Deletes all media of specified type. All children of deleted media is moved to Recycle Bin. - /// - /// This needs extra care and attention as its potentially a dangerous and extensive operation - /// Id of the - /// Optional id of the user deleting the media - public void DeleteMediaOfType(int mediaTypeId, int userId = 0) - { - using (new WriteLock(Locker)) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - //NOTE What about media that has the contenttype as part of its composition? - //The ContentType has to be removed from the composition somehow as it would otherwise break - //Dbl.check+test that the ContentType's Id is removed from the ContentType2ContentType table - var query = Query.Builder.Where(x => x.ContentTypeId == mediaTypeId); - var contents = repository.GetByQuery(query).ToArray(); - - if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(contents), this)) - return; - - foreach (var content in contents.OrderByDescending(x => x.ParentId)) - { - //Look for children of current content and move that to trash before the current content is deleted - var c = content; - var childQuery = Query.Builder.Where(x => x.Path.StartsWith(c.Path)); - var children = repository.GetByQuery(childQuery); - - foreach (var child in children) - { - if (child.ContentType.Id != mediaTypeId) - MoveToRecycleBin(child, userId); - } - - //Permantly delete the content - Delete(content, userId); - } - } - - Audit.Add(AuditTypes.Delete, "Delete Media items by Type performed by user", userId, -1); - } } - /// + /// + /// Deletes all media of specified type. All children of deleted media is moved to Recycle Bin. + /// + /// This needs extra care and attention as its potentially a dangerous and extensive operation + /// Id of the + /// Optional id of the user deleting the media + public void DeleteMediaOfType(int mediaTypeId, int userId = 0) + { + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + //NOTE What about media that has the contenttype as part of its composition? + //The ContentType has to be removed from the composition somehow as it would otherwise break + //Dbl.check+test that the ContentType's Id is removed from the ContentType2ContentType table + var query = Query.Builder.Where(x => x.ContentTypeId == mediaTypeId); + var contents = repository.GetByQuery(query).ToArray(); + + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(contents), this)) + return; + + foreach (var content in contents.OrderByDescending(x => x.ParentId)) + { + //Look for children of current content and move that to trash before the current content is deleted + var c = content; + var childQuery = Query.Builder.Where(x => x.Path.StartsWith(c.Path)); + var children = repository.GetByQuery(childQuery); + + foreach (var child in children) + { + if (child.ContentType.Id != mediaTypeId) + MoveToRecycleBin(child, userId); + } + + //Permantly delete the content + Delete(content, userId); + } + } + + Audit.Add(AuditTypes.Delete, "Delete Media items by Type performed by user", userId, -1); + } + } + + /// /// Permanently deletes an object as well as all of its Children. - /// - /// - /// Please note that this method will completely remove the Media from the database, - /// as well as associated media files from the file system. - /// - /// The to delete - /// Id of the User deleting the Media - public void Delete(IMedia media, int userId = 0) - { - if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(media), this)) - return; + /// + /// + /// Please note that this method will completely remove the Media from the database, + /// as well as associated media files from the file system. + /// + /// The to delete + /// Id of the User deleting the Media + public void Delete(IMedia media, int userId = 0) + { + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(media), this)) + return; //Delete children before deleting the 'possible parent' var children = GetChildren(media.Id); @@ -655,17 +656,17 @@ namespace Umbraco.Core.Services Delete(child, userId); } - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - repository.Delete(media); - uow.Commit(); - } + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + repository.Delete(media); + uow.Commit(); + } - Deleted.RaiseEvent(new DeleteEventArgs(media, false), this); + Deleted.RaiseEvent(new DeleteEventArgs(media, false), this); - Audit.Add(AuditTypes.Delete, "Delete Media performed by user", userId, media.Id); - } + Audit.Add(AuditTypes.Delete, "Delete Media performed by user", userId, media.Id); + } /// /// Permanently deletes versions from an object prior to a specific date. @@ -676,19 +677,19 @@ namespace Umbraco.Core.Services /// Optional Id of the User deleting versions of a Content object public void DeleteVersions(int id, DateTime versionDate, int userId = 0) { - if (DeletingVersions.IsRaisedEventCancelled(new DeleteRevisionsEventArgs(id, dateToRetain: versionDate), this)) - return; - - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - repository.DeleteVersions(id, versionDate); - uow.Commit(); - } + if (DeletingVersions.IsRaisedEventCancelled(new DeleteRevisionsEventArgs(id, dateToRetain: versionDate), this)) + return; - DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate), this); + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + repository.DeleteVersions(id, versionDate); + uow.Commit(); + } - Audit.Add(AuditTypes.Delete, "Delete Media by version date performed by user", userId, -1); + DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate), this); + + Audit.Add(AuditTypes.Delete, "Delete Media by version date performed by user", userId, -1); } /// @@ -710,91 +711,91 @@ namespace Umbraco.Core.Services DeleteVersions(id, content.UpdateDate, userId); } - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - repository.DeleteVersion(versionId); - uow.Commit(); - } - - DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, specificVersion: versionId), this); - - Audit.Add(AuditTypes.Delete, "Delete Media by version performed by user", userId, -1); - } - - /// - /// Saves a single object - /// - /// The to save - /// Id of the User saving the Content - /// Optional boolean indicating whether or not to raise events. - public void Save(IMedia media, int userId = 0, bool raiseEvents = true) - { - if(raiseEvents) - { - if (Saving.IsRaisedEventCancelled(new SaveEventArgs(media), this)) - return; + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + repository.DeleteVersion(versionId); + uow.Commit(); } - using (new WriteLock(Locker)) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - media.CreatorId = userId; - repository.AddOrUpdate(media); - uow.Commit(); + DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, specificVersion: versionId), this); - var xml = media.ToXml(); - CreateAndSaveMediaXml(xml, media.Id, uow.Database); - } - } + Audit.Add(AuditTypes.Delete, "Delete Media by version performed by user", userId, -1); + } + + /// + /// Saves a single object + /// + /// The to save + /// Id of the User saving the Content + /// Optional boolean indicating whether or not to raise events. + public void Save(IMedia media, int userId = 0, bool raiseEvents = true) + { + if (raiseEvents) + { + if (Saving.IsRaisedEventCancelled(new SaveEventArgs(media), this)) + return; + } + + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + media.CreatorId = userId; + repository.AddOrUpdate(media); + uow.Commit(); + + var xml = media.ToXml(); + CreateAndSaveMediaXml(xml, media.Id, uow.Database); + } + } if (raiseEvents) Saved.RaiseEvent(new SaveEventArgs(media, false), this); Audit.Add(AuditTypes.Save, "Save Media performed by user", userId, media.Id); - } + } - /// - /// Saves a collection of objects - /// - /// Collection of to save - /// Id of the User saving the Content + /// + /// Saves a collection of objects + /// + /// Collection of to save + /// Id of the User saving the Content /// Optional boolean indicating whether or not to raise events. public void Save(IEnumerable medias, int userId = 0, bool raiseEvents = true) - { - if(raiseEvents) - { + { + if (raiseEvents) + { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(medias), this)) - return; + return; } - using (new WriteLock(Locker)) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - foreach (var media in medias) - { - media.CreatorId = userId; - repository.AddOrUpdate(media); - } + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + foreach (var media in medias) + { + media.CreatorId = userId; + repository.AddOrUpdate(media); + } - //commit the whole lot in one go - uow.Commit(); + //commit the whole lot in one go + uow.Commit(); - foreach (var media in medias) - { - CreateAndSaveMediaXml(media.ToXml(), media.Id, uow.Database); - } - } + foreach (var media in medias) + { + CreateAndSaveMediaXml(media.ToXml(), media.Id, uow.Database); + } + } - if (raiseEvents) - Saved.RaiseEvent(new SaveEventArgs(medias, false), this); + if (raiseEvents) + Saved.RaiseEvent(new SaveEventArgs(medias, false), this); - Audit.Add(AuditTypes.Save, "Save Media items performed by user", userId, -1); - } - } + Audit.Add(AuditTypes.Save, "Save Media items performed by user", userId, -1); + } + } /// /// Sorts a collection of objects by updating the SortOrder according @@ -903,12 +904,22 @@ namespace Umbraco.Core.Services { if (contentTypeIds.Any() == false) { - //Remove all media records from the cmsContentXml table (DO NOT REMOVE Content/Members!) - uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN - (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml - INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id - WHERE nodeObjectType = @nodeObjectType)", - new { nodeObjectType = Constants.ObjectTypes.Media }); + var subQuery = new Sql() + .Select("DISTINCT cmsContentXml.nodeId") + .From() + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .Where(dto => dto.NodeObjectType == Guid.Parse(Constants.ObjectTypes.Media)); + + var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery); + uow.Database.Execute(deleteSql); + + // //Remove all media records from the cmsContentXml table (DO NOT REMOVE Content/Members!) + // uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN + // (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml + // INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id + // WHERE nodeObjectType = @nodeObjectType)", + // new { nodeObjectType = Constants.ObjectTypes.Media }); } else { @@ -952,7 +963,7 @@ namespace Umbraco.Core.Services { child.ChangeTrashedState(parentTrashed, child.ParentId); } - + list.Add(child); var grandkids = GetChildren(child.Id).ToArray(); @@ -993,71 +1004,71 @@ namespace Umbraco.Core.Services } } - #region Event Handlers + #region Event Handlers - /// - /// Occurs before Delete - /// - public static event TypedEventHandler DeletingVersions; + /// + /// Occurs before Delete + /// + public static event TypedEventHandler DeletingVersions; - /// - /// Occurs after Delete - /// - public static event TypedEventHandler DeletedVersions; + /// + /// Occurs after Delete + /// + public static event TypedEventHandler DeletedVersions; - /// - /// Occurs before Delete - /// - public static event TypedEventHandler> Deleting; + /// + /// Occurs before Delete + /// + public static event TypedEventHandler> Deleting; - /// - /// Occurs after Delete - /// - public static event TypedEventHandler> Deleted; + /// + /// Occurs after Delete + /// + public static event TypedEventHandler> Deleted; - /// - /// Occurs before Save - /// - public static event TypedEventHandler> Saving; + /// + /// Occurs before Save + /// + public static event TypedEventHandler> Saving; - /// - /// Occurs after Save - /// - public static event TypedEventHandler> Saved; + /// + /// Occurs after Save + /// + public static event TypedEventHandler> Saved; - /// - /// Occurs before Create - /// - public static event TypedEventHandler> Creating; + /// + /// Occurs before Create + /// + public static event TypedEventHandler> Creating; - /// - /// Occurs after Create - /// - /// - /// Please note that the Media object has been created, but not saved - /// so it does not have an identity yet (meaning no Id has been set). - /// - public static event TypedEventHandler> Created; + /// + /// Occurs after Create + /// + /// + /// Please note that the Media object has been created, but not saved + /// so it does not have an identity yet (meaning no Id has been set). + /// + public static event TypedEventHandler> Created; - /// - /// Occurs before Content is moved to Recycle Bin - /// - public static event TypedEventHandler> Trashing; + /// + /// Occurs before Content is moved to Recycle Bin + /// + public static event TypedEventHandler> Trashing; - /// - /// Occurs after Content is moved to Recycle Bin - /// - public static event TypedEventHandler> Trashed; + /// + /// Occurs after Content is moved to Recycle Bin + /// + public static event TypedEventHandler> Trashed; - /// - /// Occurs before Move - /// - public static event TypedEventHandler> Moving; + /// + /// Occurs before Move + /// + public static event TypedEventHandler> Moving; - /// - /// Occurs after Move - /// - public static event TypedEventHandler> Moved; + /// + /// Occurs after Move + /// + public static event TypedEventHandler> Moved; /// /// Occurs before the Recycle Bin is emptied @@ -1068,6 +1079,6 @@ namespace Umbraco.Core.Services /// Occurs after the Recycle Bin has been Emptied /// public static event TypedEventHandler EmptiedRecycleBin; - #endregion - } + #endregion + } } \ No newline at end of file