diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs
index 655801dddf..306033b08e 100644
--- a/src/Umbraco.Core/DatabaseContext.cs
+++ b/src/Umbraco.Core/DatabaseContext.cs
@@ -49,7 +49,10 @@ namespace Umbraco.Core
///
public Database Database
{
- get { return DatabaseFactory.Current.Database; }
+ get
+ {
+ return DatabaseFactory.Current.Database;
+ }
}
///
diff --git a/src/Umbraco.Core/EventArgs.cs b/src/Umbraco.Core/EventArgs.cs
index 2d5fee1bcd..24edc6003f 100644
--- a/src/Umbraco.Core/EventArgs.cs
+++ b/src/Umbraco.Core/EventArgs.cs
@@ -1,8 +1,11 @@
using Umbraco.Core.Models;
+using Umbraco.Core.Persistence.UnitOfWork;
+using Umbraco.Core.Services;
namespace Umbraco.Core
{
- //Publishing Events
+
+ //Publishing Events
public class PublishingEventArgs : System.ComponentModel.CancelEventArgs { }
public class SendToPublishEventArgs : System.ComponentModel.CancelEventArgs { }
@@ -39,7 +42,30 @@ namespace Umbraco.Core
///
public int Id { get; set; }
}
- public class SaveEventArgs : System.ComponentModel.CancelEventArgs { }
+ public class SaveEventArgs : System.ComponentModel.CancelEventArgs
+ {
+ ///
+ /// public constructor
+ ///
+ public SaveEventArgs()
+ {
+
+ }
+
+ ///
+ /// internal constructor used for unit testing
+ ///
+ ///
+ internal SaveEventArgs(IUnitOfWork unitOfWork)
+ {
+ UnitOfWork = unitOfWork;
+ }
+
+ ///
+ /// Used for unit testing
+ ///
+ internal IUnitOfWork UnitOfWork { get; private set; }
+ }
public class NewEventArgs : System.ComponentModel.CancelEventArgs
{
///
diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs
index fa5b470979..0639bfa86f 100644
--- a/src/Umbraco.Core/Models/ContentExtensions.cs
+++ b/src/Umbraco.Core/Models/ContentExtensions.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Repositories;
@@ -51,7 +52,7 @@ namespace Umbraco.Core.Models
public static IProfile GetCreatorProfile(this IContent content)
{
var repository = RepositoryResolver.Current.Factory.CreateUserRepository(
- new PetaPocoUnitOfWork());
+ new PetaPocoUnitOfWork(DatabaseContext.Current.Database));
return repository.GetProfileById(content.CreatorId);
}
@@ -61,7 +62,7 @@ namespace Umbraco.Core.Models
public static IProfile GetWriterProfile(this IContent content)
{
var repository = RepositoryResolver.Current.Factory.CreateUserRepository(
- new PetaPocoUnitOfWork());
+ new PetaPocoUnitOfWork(DatabaseContext.Current.Database));
return repository.GetProfileById(content.WriterId);
}
}
diff --git a/src/Umbraco.Core/Persistence/DatabaseFactory.cs b/src/Umbraco.Core/Persistence/DatabaseFactory.cs
index ded49f887c..28daf4967d 100644
--- a/src/Umbraco.Core/Persistence/DatabaseFactory.cs
+++ b/src/Umbraco.Core/Persistence/DatabaseFactory.cs
@@ -1,23 +1,27 @@
using System;
+using System.Collections.Concurrent;
+using System.Threading;
+using System.Web;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence
{
///
- /// Provides access to the PetaPoco database as Singleton, so the database is created once in app lifetime.
- /// This is necessary for transactions to work properly.
+ /// Creates a database object for PetaPoco depending on the context. If we are running in an http context
+ /// it will create on per context, otherwise it will create a global singleton
///
///
/// Because the Database is created static, the configuration has to be checked and set in
/// another class, which is where the DatabaseContext comes in.
///
- public sealed class DatabaseFactory
+ internal sealed class DatabaseFactory
{
+
#region Singleton
- private static readonly Database _database = new Database(GlobalSettings.UmbracoConnectionName);
- private static readonly Lazy lazy = new Lazy(() => new DatabaseFactory());
-
+ private static readonly Lazy lazy = new Lazy(() => new DatabaseFactory());
+ private static volatile Database _globalInstance = null;
+ private static readonly object Locker = new object();
public static DatabaseFactory Current { get { return lazy.Value; } }
private DatabaseFactory()
@@ -26,12 +30,41 @@ namespace Umbraco.Core.Persistence
#endregion
- ///
- /// Returns an instance of the PetaPoco database
- ///
- public Database Database
- {
- get { return _database; }
- }
+ ///
+ /// Returns an instance of the PetaPoco database
+ ///
+ ///
+ /// If we are running in an http context
+ /// it will create on per context, otherwise it will create transient objects (new instance each time)
+ ///
+ public Database Database
+ {
+ get
+ {
+ //no http context, create the singleton global object
+ if (HttpContext.Current == null)
+ {
+ if (_globalInstance == null)
+ {
+ lock(Locker)
+ {
+ //double check
+ if (_globalInstance == null)
+ {
+ _globalInstance = new Database(GlobalSettings.UmbracoConnectionName);
+ }
+ }
+ }
+ return _globalInstance;
+ }
+
+ //we have an http context, so only create one per request
+ if (!HttpContext.Current.Items.Contains(typeof (DatabaseFactory)))
+ {
+ HttpContext.Current.Items.Add(typeof (DatabaseFactory), new Database(GlobalSettings.UmbracoConnectionName));
+ }
+ return (Database) HttpContext.Current.Items[typeof (DatabaseFactory)];
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
index 8452f81ac9..ce2874e1af 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
@@ -20,14 +20,14 @@ namespace Umbraco.Core.Persistence.Repositories
private readonly IContentTypeRepository _contentTypeRepository;
private readonly ITemplateRepository _templateRepository;
- public ContentRepository(IUnitOfWork work, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository)
+ public ContentRepository(IDatabaseUnitOfWork work, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository)
: base(work)
{
_contentTypeRepository = contentTypeRepository;
_templateRepository = templateRepository;
}
- public ContentRepository(IUnitOfWork work, IRepositoryCacheProvider cache, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository)
+ public ContentRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository)
: base(work, cache)
{
_contentTypeRepository = contentTypeRepository;
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
index 818dec4f49..0f7918b680 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
@@ -22,11 +22,13 @@ namespace Umbraco.Core.Persistence.Repositories
internal abstract class ContentTypeBaseRepository : PetaPocoRepositoryBase
where TEntity : IContentTypeComposition
{
- protected ContentTypeBaseRepository(IUnitOfWork work) : base(work)
+ protected ContentTypeBaseRepository(IDatabaseUnitOfWork work)
+ : base(work)
{
}
- protected ContentTypeBaseRepository(IUnitOfWork work, IRepositoryCacheProvider cache) : base(work, cache)
+ protected ContentTypeBaseRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
+ : base(work, cache)
{
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs
index 6ae710f903..2984b5a43d 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs
@@ -18,13 +18,13 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly ITemplateRepository _templateRepository;
- public ContentTypeRepository(IUnitOfWork work, ITemplateRepository templateRepository)
+ public ContentTypeRepository(IDatabaseUnitOfWork work, ITemplateRepository templateRepository)
: base(work)
{
_templateRepository = templateRepository;
}
- public ContentTypeRepository(IUnitOfWork work, IRepositoryCacheProvider cache, ITemplateRepository templateRepository)
+ public ContentTypeRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, ITemplateRepository templateRepository)
: base(work, cache)
{
_templateRepository = templateRepository;
diff --git a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs
index 0c7820a541..5ef72413be 100644
--- a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs
@@ -17,11 +17,12 @@ namespace Umbraco.Core.Persistence.Repositories
///
internal class DataTypeDefinitionRepository : PetaPocoRepositoryBase, IDataTypeDefinitionRepository
{
- public DataTypeDefinitionRepository(IUnitOfWork work) : base(work)
+ public DataTypeDefinitionRepository(IDatabaseUnitOfWork work)
+ : base(work)
{
}
- public DataTypeDefinitionRepository(IUnitOfWork work, IRepositoryCacheProvider cache)
+ public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
{
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/DictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DictionaryRepository.cs
index b6b64716d6..1daf2cf2fe 100644
--- a/src/Umbraco.Core/Persistence/Repositories/DictionaryRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/DictionaryRepository.cs
@@ -19,12 +19,13 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly ILanguageRepository _languageRepository;
- public DictionaryRepository(IUnitOfWork work, ILanguageRepository languageRepository) : base(work)
+ public DictionaryRepository(IDatabaseUnitOfWork work, ILanguageRepository languageRepository)
+ : base(work)
{
_languageRepository = languageRepository;
}
- public DictionaryRepository(IUnitOfWork work, IRepositoryCacheProvider cache, ILanguageRepository languageRepository)
+ public DictionaryRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, ILanguageRepository languageRepository)
: base(work, cache)
{
_languageRepository = languageRepository;
diff --git a/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs b/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs
index b1a28a74cd..7cf63b33ba 100644
--- a/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs
@@ -8,7 +8,7 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
- internal abstract class FileRepository : IUnitOfWorkRepository, IRepository
+ internal abstract class FileRepository : DisposableObject, IUnitOfWorkRepository, IRepository
where TEntity : IFile
{
private IUnitOfWork _work;
@@ -110,5 +110,16 @@ namespace Umbraco.Core.Persistence.Repositories
}
#endregion
+
+ ///
+ /// Dispose any disposable properties
+ ///
+ ///
+ /// Dispose the unit of work
+ ///
+ protected override void DisposeResources()
+ {
+ _work.DisposeIfDisposable();
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepository.cs
index 55c2381391..2a825d3449 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepository.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -9,7 +10,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// Currently this interface is empty but it is useful for flagging a repository without having generic parameters, it also might
/// come in handy if we need to add anything to the base/non-generic repository interface.
///
- public interface IRepository
+ public interface IRepository : IDisposable
{
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs
index 3b85317be4..c215d08580 100644
--- a/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs
@@ -16,11 +16,12 @@ namespace Umbraco.Core.Persistence.Repositories
///
internal class LanguageRepository : PetaPocoRepositoryBase, ILanguageRepository
{
- public LanguageRepository(IUnitOfWork work) : base(work)
+ public LanguageRepository(IDatabaseUnitOfWork work)
+ : base(work)
{
}
- public LanguageRepository(IUnitOfWork work, IRepositoryCacheProvider cache)
+ public LanguageRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
{
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/MacroRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MacroRepository.cs
index 51e8d2a6aa..72345c19e0 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MacroRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MacroRepository.cs
@@ -20,12 +20,13 @@ namespace Umbraco.Core.Persistence.Repositories
private IFileSystem _fileSystem;
private SerializationService _serializationService;
- public MacroRepository(IUnitOfWork work) : base(work)
+ public MacroRepository(IUnitOfWork work)
+ : base(work)
{
EnsureDependencies();
}
- public MacroRepository(IUnitOfWork work, IRepositoryCacheProvider cache)
+ public MacroRepository(IUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
{
EnsureDependencies();
diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
index 370f6bcf4a..c01e76c203 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
@@ -19,13 +19,13 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly IMediaTypeRepository _mediaTypeRepository;
- public MediaRepository(IUnitOfWork work, IMediaTypeRepository mediaTypeRepository)
+ public MediaRepository(IDatabaseUnitOfWork work, IMediaTypeRepository mediaTypeRepository)
: base(work)
{
_mediaTypeRepository = mediaTypeRepository;
}
- public MediaRepository(IUnitOfWork work, IRepositoryCacheProvider cache, IMediaTypeRepository mediaTypeRepository)
+ public MediaRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IMediaTypeRepository mediaTypeRepository)
: base(work, cache)
{
_mediaTypeRepository = mediaTypeRepository;
diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs
index 98e1c159d2..50477a679e 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs
@@ -16,12 +16,12 @@ namespace Umbraco.Core.Persistence.Repositories
///
internal class MediaTypeRepository : ContentTypeBaseRepository, IMediaTypeRepository
{
- public MediaTypeRepository(IUnitOfWork work)
+ public MediaTypeRepository(IDatabaseUnitOfWork work)
: base(work)
{
}
- public MediaTypeRepository(IUnitOfWork work, IRepositoryCacheProvider cache)
+ public MediaTypeRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
{
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs
index a4a4526de0..6ccbe5d004 100644
--- a/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs
@@ -15,17 +15,27 @@ namespace Umbraco.Core.Persistence.Repositories
internal abstract class PetaPocoRepositoryBase : RepositoryBase
where TEntity : IAggregateRoot
{
- protected PetaPocoRepositoryBase(IUnitOfWork work) : base(work)
+ protected PetaPocoRepositoryBase(IDatabaseUnitOfWork work)
+ : base(work)
{
}
- protected PetaPocoRepositoryBase(IUnitOfWork work, IRepositoryCacheProvider cache) : base(work, cache)
+ protected PetaPocoRepositoryBase(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
+ : base(work, cache)
{
}
+ ///
+ /// Returns the database Unit of Work added to the repository
+ ///
+ protected internal new IDatabaseUnitOfWork UnitOfWork
+ {
+ get { return (IDatabaseUnitOfWork)base.UnitOfWork; }
+ }
+
protected Database Database
{
- get { return DatabaseContext.Current.Database; }
+ get { return UnitOfWork.Database; }
}
#region Abstract Methods
diff --git a/src/Umbraco.Core/Persistence/Repositories/RelationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/RelationRepository.cs
index 1dd7bf60dd..89f5510708 100644
--- a/src/Umbraco.Core/Persistence/Repositories/RelationRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/RelationRepository.cs
@@ -18,12 +18,13 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly IRelationTypeRepository _relationTypeRepository;
- public RelationRepository(IUnitOfWork work, IRelationTypeRepository relationTypeRepository) : base(work)
+ public RelationRepository(IDatabaseUnitOfWork work, IRelationTypeRepository relationTypeRepository)
+ : base(work)
{
_relationTypeRepository = relationTypeRepository;
}
- public RelationRepository(IUnitOfWork work, IRepositoryCacheProvider cache, IRelationTypeRepository relationTypeRepository)
+ public RelationRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IRelationTypeRepository relationTypeRepository)
: base(work, cache)
{
_relationTypeRepository = relationTypeRepository;
diff --git a/src/Umbraco.Core/Persistence/Repositories/RelationTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/RelationTypeRepository.cs
index d89219a41b..e30e992861 100644
--- a/src/Umbraco.Core/Persistence/Repositories/RelationTypeRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/RelationTypeRepository.cs
@@ -15,11 +15,12 @@ namespace Umbraco.Core.Persistence.Repositories
///
internal class RelationTypeRepository : PetaPocoRepositoryBase, IRelationTypeRepository
{
- public RelationTypeRepository(IUnitOfWork work) : base(work)
+ public RelationTypeRepository(IDatabaseUnitOfWork work)
+ : base(work)
{
}
- public RelationTypeRepository(IUnitOfWork work, IRepositoryCacheProvider cache)
+ public RelationTypeRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
{
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs
index 5206449af3..13282369ef 100644
--- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs
@@ -13,18 +13,18 @@ namespace Umbraco.Core.Persistence.Repositories
///
/// Type of entity for which the repository is used
/// Type of the Id used for this entity
- internal abstract class RepositoryBase : IRepositoryQueryable,
- IUnitOfWorkRepository where TEntity : IAggregateRoot
+ internal abstract class RepositoryBase : DisposableObject, IRepositoryQueryable, IUnitOfWorkRepository
+ where TEntity : IAggregateRoot
{
- private IUnitOfWork _work;
+ private readonly IUnitOfWork _work;
private readonly IRepositoryCacheProvider _cache;
- protected RepositoryBase(IUnitOfWork work)
+ protected RepositoryBase(IUnitOfWork work)
: this(work, RuntimeCacheProvider.Current)
{
}
- internal RepositoryBase(IUnitOfWork work, IRepositoryCacheProvider cache)
+ internal RepositoryBase(IUnitOfWork work, IRepositoryCacheProvider cache)
{
_work = work;
_cache = cache;
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories
///
/// Returns the Unit of Work added to the repository
///
- protected IUnitOfWork UnitOfWork
+ protected internal IUnitOfWork UnitOfWork
{
get { return _work; }
}
@@ -181,16 +181,7 @@ namespace Umbraco.Core.Persistence.Repositories
public int Count(IQuery query)
{
return PerformCount(query);
- }
-
- ///
- /// Sets the repository's Unit Of Work with the passed in
- ///
- ///
- public void SetUnitOfWork(IUnitOfWork work)
- {
- _work = work;
- }
+ }
#endregion
@@ -259,5 +250,16 @@ namespace Umbraco.Core.Persistence.Repositories
{
return id.EncodeAsGuid();
}
+
+ ///
+ /// Dispose disposable properties
+ ///
+ ///
+ /// Ensure the unit of work is disposed
+ ///
+ protected override void DisposeResources()
+ {
+ UnitOfWork.DisposeIfDisposable();
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs
index 65a5073f02..fb8307d940 100644
--- a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs
@@ -23,17 +23,20 @@ namespace Umbraco.Core.Persistence.Repositories
private IFileSystem _masterpagesFileSystem;
private IFileSystem _viewsFileSystem;
- public TemplateRepository(IUnitOfWork work) : base(work)
+ public TemplateRepository(IDatabaseUnitOfWork work)
+ : base(work)
{
EnsureDepedencies();
}
- public TemplateRepository(IUnitOfWork work, IRepositoryCacheProvider cache) : base(work, cache)
+ public TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
+ : base(work, cache)
{
EnsureDepedencies();
}
- internal TemplateRepository(IUnitOfWork work, IRepositoryCacheProvider cache, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem) : base(work, cache)
+ internal TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem)
+ : base(work, cache)
{
_masterpagesFileSystem = masterpageFileSystem;
_viewsFileSystem = viewFileSystem;
diff --git a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs
index ad3d7aefb9..bfe896e6b5 100644
--- a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs
@@ -17,13 +17,13 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly IUserTypeRepository _userTypeRepository;
- public UserRepository(IUnitOfWork work, IUserTypeRepository userTypeRepository)
+ public UserRepository(IDatabaseUnitOfWork work, IUserTypeRepository userTypeRepository)
: base(work)
{
_userTypeRepository = userTypeRepository;
}
- public UserRepository(IUnitOfWork work, IRepositoryCacheProvider cache, IUserTypeRepository userTypeRepository)
+ public UserRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IUserTypeRepository userTypeRepository)
: base(work, cache)
{
_userTypeRepository = userTypeRepository;
diff --git a/src/Umbraco.Core/Persistence/Repositories/UserTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserTypeRepository.cs
index 2e8cf45137..3618ef89b0 100644
--- a/src/Umbraco.Core/Persistence/Repositories/UserTypeRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/UserTypeRepository.cs
@@ -15,11 +15,13 @@ namespace Umbraco.Core.Persistence.Repositories
///
internal class UserTypeRepository : PetaPocoRepositoryBase, IUserTypeRepository
{
- public UserTypeRepository(IUnitOfWork work) : base(work)
+ public UserTypeRepository(IDatabaseUnitOfWork work)
+ : base(work)
{
}
- public UserTypeRepository(IUnitOfWork work, IRepositoryCacheProvider cache) : base(work, cache)
+ public UserTypeRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
+ : base(work, cache)
{
}
diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs
index 5862025fd4..085a5cd87b 100644
--- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs
+++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs
@@ -9,14 +9,14 @@ namespace Umbraco.Core.Persistence
///
public class RepositoryFactory
{
- internal virtual IUserTypeRepository CreateUserTypeRepository(IUnitOfWork uow)
+ internal virtual IUserTypeRepository CreateUserTypeRepository(IDatabaseUnitOfWork uow)
{
return new UserTypeRepository(
uow,
NullCacheProvider.Current);
}
- internal virtual IUserRepository CreateUserRepository(IUnitOfWork uow)
+ internal virtual IUserRepository CreateUserRepository(IDatabaseUnitOfWork uow)
{
return new UserRepository(
uow,
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence
CreateUserTypeRepository(uow));
}
- public virtual IContentRepository CreateContentRepository(IUnitOfWork uow)
+ public virtual IContentRepository CreateContentRepository(IDatabaseUnitOfWork uow)
{
return new ContentRepository(
uow,
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence
CreateTemplateRepository(uow));
}
- public virtual IContentTypeRepository CreateContentTypeRepository(IUnitOfWork uow)
+ public virtual IContentTypeRepository CreateContentTypeRepository(IDatabaseUnitOfWork uow)
{
return new ContentTypeRepository(
uow,
@@ -41,14 +41,14 @@ namespace Umbraco.Core.Persistence
new TemplateRepository(uow, NullCacheProvider.Current));
}
- public virtual IDataTypeDefinitionRepository CreateDataTypeDefinitionRepository(IUnitOfWork uow)
+ public virtual IDataTypeDefinitionRepository CreateDataTypeDefinitionRepository(IDatabaseUnitOfWork uow)
{
return new DataTypeDefinitionRepository(
uow,
NullCacheProvider.Current);
}
- public virtual IDictionaryRepository CreateDictionaryRepository(IUnitOfWork uow)
+ public virtual IDictionaryRepository CreateDictionaryRepository(IDatabaseUnitOfWork uow)
{
return new DictionaryRepository(
uow,
@@ -56,21 +56,21 @@ namespace Umbraco.Core.Persistence
CreateLanguageRepository(uow));
}
- public virtual ILanguageRepository CreateLanguageRepository(IUnitOfWork uow)
+ public virtual ILanguageRepository CreateLanguageRepository(IDatabaseUnitOfWork uow)
{
return new LanguageRepository(
uow,
InMemoryCacheProvider.Current);
}
- internal virtual IMacroRepository CreateMacroRepository(IUnitOfWork uow)
+ internal virtual IMacroRepository CreateMacroRepository(IUnitOfWork uow)
{
return new MacroRepository(
uow,
InMemoryCacheProvider.Current);
}
- public virtual IMediaRepository CreateMediaRepository(IUnitOfWork uow)
+ public virtual IMediaRepository CreateMediaRepository(IDatabaseUnitOfWork uow)
{
return new MediaRepository(
uow,
@@ -78,14 +78,14 @@ namespace Umbraco.Core.Persistence
CreateMediaTypeRepository(uow));
}
- public virtual IMediaTypeRepository CreateMediaTypeRepository(IUnitOfWork uow)
+ public virtual IMediaTypeRepository CreateMediaTypeRepository(IDatabaseUnitOfWork uow)
{
return new MediaTypeRepository(
uow,
InMemoryCacheProvider.Current);
}
- public virtual IRelationRepository CreateRelationRepository(IUnitOfWork uow)
+ public virtual IRelationRepository CreateRelationRepository(IDatabaseUnitOfWork uow)
{
return new RelationRepository(
uow,
@@ -93,7 +93,7 @@ namespace Umbraco.Core.Persistence
CreateRelationTypeRepository(uow));
}
- public virtual IRelationTypeRepository CreateRelationTypeRepository(IUnitOfWork uow)
+ public virtual IRelationTypeRepository CreateRelationTypeRepository(IDatabaseUnitOfWork uow)
{
return new RelationTypeRepository(
uow,
@@ -110,7 +110,7 @@ namespace Umbraco.Core.Persistence
return new StylesheetRepository(uow);
}
- public virtual ITemplateRepository CreateTemplateRepository(IUnitOfWork uow)
+ public virtual ITemplateRepository CreateTemplateRepository(IDatabaseUnitOfWork uow)
{
return new TemplateRepository(uow, NullCacheProvider.Current);
}
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/FileUnitOfWork.cs b/src/Umbraco.Core/Persistence/UnitOfWork/FileUnitOfWork.cs
index 5e441fe242..7c15df55af 100644
--- a/src/Umbraco.Core/Persistence/UnitOfWork/FileUnitOfWork.cs
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/FileUnitOfWork.cs
@@ -140,5 +140,6 @@ namespace Umbraco.Core.Persistence.UnitOfWork
}
#endregion
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/IDatabaseUnitOfWork.cs b/src/Umbraco.Core/Persistence/UnitOfWork/IDatabaseUnitOfWork.cs
new file mode 100644
index 0000000000..8653733677
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/IDatabaseUnitOfWork.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Umbraco.Core.Persistence.UnitOfWork
+{
+ ///
+ /// Defines a unit of work when working with a database object
+ ///
+ public interface IDatabaseUnitOfWork : IUnitOfWork, IDisposable
+ {
+ Database Database { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/IDatabaseUnitOfWorkProvider.cs b/src/Umbraco.Core/Persistence/UnitOfWork/IDatabaseUnitOfWorkProvider.cs
new file mode 100644
index 0000000000..c18c08d8bb
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/IDatabaseUnitOfWorkProvider.cs
@@ -0,0 +1,10 @@
+namespace Umbraco.Core.Persistence.UnitOfWork
+{
+ ///
+ /// Defines a Unit of Work Provider for working with an IDatabaseUnitOfWork
+ ///
+ public interface IDatabaseUnitOfWorkProvider
+ {
+ IDatabaseUnitOfWork GetUnitOfWork();
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/IUnitOfWork.cs b/src/Umbraco.Core/Persistence/UnitOfWork/IUnitOfWork.cs
index 809c2340e4..13d2bb8be9 100644
--- a/src/Umbraco.Core/Persistence/UnitOfWork/IUnitOfWork.cs
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/IUnitOfWork.cs
@@ -1,12 +1,13 @@
-using Umbraco.Core.Models.EntityBase;
+using System;
+using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Persistence.UnitOfWork
{
- ///
+ ///
/// Defines a Unit Of Work
///
public interface IUnitOfWork
- {
+ {
void RegisterAdded(IEntity entity, IUnitOfWorkRepository repository);
void RegisterChanged(IEntity entity, IUnitOfWorkRepository repository);
void RegisterRemoved(IEntity entity, IUnitOfWorkRepository repository);
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/IUnitOfWorkProvider.cs b/src/Umbraco.Core/Persistence/UnitOfWork/IUnitOfWorkProvider.cs
index 7b87d9a2ee..006bda0820 100644
--- a/src/Umbraco.Core/Persistence/UnitOfWork/IUnitOfWorkProvider.cs
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/IUnitOfWorkProvider.cs
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Persistence.UnitOfWork
{
- ///
+ ///
/// Defines a Unit of Work Provider
///
public interface IUnitOfWorkProvider
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWork.cs b/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWork.cs
index 6266053390..896ac82d0f 100644
--- a/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWork.cs
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWork.cs
@@ -8,17 +8,26 @@ namespace Umbraco.Core.Persistence.UnitOfWork
///
/// Represents the Unit of Work implementation for PetaPoco
///
- internal class PetaPocoUnitOfWork : IUnitOfWork
+ internal class PetaPocoUnitOfWork : DisposableObject, IDatabaseUnitOfWork
{
+
+ ///
+ /// Used for testing
+ ///
+ internal Guid InstanceId { get; private set; }
+
private Guid _key;
private readonly List _operations = new List();
- public PetaPocoUnitOfWork()
- {
- _key = Guid.NewGuid();
- }
- ///
+ public PetaPocoUnitOfWork(Database database)
+ {
+ Database = database;
+ _key = Guid.NewGuid();
+ InstanceId = Guid.NewGuid();
+ }
+
+ ///
/// Registers an instance to be added through this
///
/// The
@@ -74,7 +83,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork
///
public void Commit()
{
- using(Transaction transaction = DatabaseFactory.Current.Database.GetTransaction())
+ using(Transaction transaction = Database.GetTransaction())
{
foreach (var operation in _operations.OrderBy(o => o.ProcessDate))
{
@@ -104,6 +113,8 @@ namespace Umbraco.Core.Persistence.UnitOfWork
get { return _key; }
}
+ public Database Database { get; private set; }
+
#region Operation
///
@@ -137,5 +148,19 @@ namespace Umbraco.Core.Persistence.UnitOfWork
}
#endregion
+
+ ///
+ /// Ensures disposable objects are disposed
+ ///
+ ///
+ /// We will not dispose the database because this will get disposed of automatically when
+ /// in the HttpContext by the UmbracoModule because the DatabaseFactory stores the instance in HttpContext.Items
+ /// when in a web context.
+ /// When not in a web context, we may possibly be re-using the database context.
+ ///
+ protected override void DisposeResources()
+ {
+ _operations.Clear();
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWorkProvider.cs b/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWorkProvider.cs
index 647e020b1a..ee46f56745 100644
--- a/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWorkProvider.cs
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWorkProvider.cs
@@ -1,15 +1,21 @@
-namespace Umbraco.Core.Persistence.UnitOfWork
+using System;
+using System.Threading;
+using System.Web;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Core.Persistence.UnitOfWork
{
///
/// Represents a Unit of Work Provider for creating a
///
- internal class PetaPocoUnitOfWorkProvider : IUnitOfWorkProvider
+ internal class PetaPocoUnitOfWorkProvider : IDatabaseUnitOfWorkProvider
{
- #region Implementation of IUnitOfWorkProvider
+
+ #region Implementation of IUnitOfWorkProvider
- public IUnitOfWork GetUnitOfWork()
+ public IDatabaseUnitOfWork GetUnitOfWork()
{
- return new PetaPocoUnitOfWork();
+ return new PetaPocoUnitOfWork(DatabaseFactory.Current.Database);
}
#endregion
diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs
index 3104bec51f..04fe684939 100644
--- a/src/Umbraco.Core/Services/ContentService.cs
+++ b/src/Umbraco.Core/Services/ContentService.cs
@@ -18,28 +18,22 @@ namespace Umbraco.Core.Services
///
public class ContentService : IContentService
{
- private readonly IPublishingStrategy _publishingStrategy;
- private readonly IUserService _userService;
- private readonly IUnitOfWork _unitOfWork;
+ private readonly IDatabaseUnitOfWorkProvider _uowProvider;
+ private readonly IPublishingStrategy _publishingStrategy;
+ private readonly IUserService _userService;
private HttpContextBase _httpContext;
- private readonly IContentRepository _contentRepository;
- private readonly IContentTypeRepository _contentTypeRepository;
-
- public ContentService(IUnitOfWorkProvider provider, IPublishingStrategy publishingStrategy)
+
+ public ContentService(IDatabaseUnitOfWorkProvider provider, IPublishingStrategy publishingStrategy)
{
- _publishingStrategy = publishingStrategy;
- _unitOfWork = provider.GetUnitOfWork();
- _contentRepository = RepositoryResolver.Current.Factory.CreateContentRepository(_unitOfWork);
- _contentTypeRepository = RepositoryResolver.Current.Factory.CreateContentTypeRepository(_unitOfWork);
+ _uowProvider = provider;
+ _publishingStrategy = publishingStrategy;
}
- internal ContentService(IUnitOfWorkProvider provider, IPublishingStrategy publishingStrategy, IUserService userService)
+ internal ContentService(IDatabaseUnitOfWorkProvider provider, IPublishingStrategy publishingStrategy, IUserService userService)
{
_publishingStrategy = publishingStrategy;
_userService = userService;
- _unitOfWork = provider.GetUnitOfWork();
- _contentRepository = RepositoryResolver.Current.Factory.CreateContentRepository(_unitOfWork);
- _contentTypeRepository = RepositoryResolver.Current.Factory.CreateContentTypeRepository(_unitOfWork);
+ _uowProvider = provider;
}
//TODO Add GetLatestUnpublishedVersions(int id){}
@@ -54,7 +48,8 @@ namespace Umbraco.Core.Services
///
public IContent CreateContent(int parentId, string contentTypeAlias, int userId = -1)
{
- var repository = _contentTypeRepository;
+ var uow = _uowProvider.GetUnitOfWork();
+ var repository = RepositoryResolver.Current.Factory.CreateContentTypeRepository(uow);
var query = Query.Builder.Where(x => x.Alias == contentTypeAlias);
var contentTypes = repository.GetByQuery(query);
@@ -92,8 +87,11 @@ namespace Umbraco.Core.Services
///
public IContent GetById(int id)
{
- var repository = _contentRepository;
- return repository.Get(id);
+ using(var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ return repository.Get(id);
+ }
+
}
///
@@ -103,10 +101,12 @@ namespace Umbraco.Core.Services
///
public IContent GetById(Guid key)
{
- var repository = _contentRepository;
- var query = Query.Builder.Where(x => x.Key == key);
- var contents = repository.GetByQuery(query);
- return contents.SingleOrDefault();
+ using(var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.Key == key);
+ var contents = repository.GetByQuery(query);
+ return contents.SingleOrDefault();
+ }
}
@@ -117,12 +117,13 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetContentOfContentType(int id)
{
- var repository = _contentRepository;
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.ContentTypeId == id);
+ var contents = repository.GetByQuery(query);
- var query = Query.Builder.Where(x => x.ContentTypeId == id);
- var contents = repository.GetByQuery(query);
-
- return contents;
+ return contents;
+ }
}
///
@@ -132,12 +133,13 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetByLevel(int level)
{
- var repository = _contentRepository;
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.Level == level);
+ var contents = repository.GetByQuery(query);
- var query = Query.Builder.Where(x => x.Level == level);
- var contents = repository.GetByQuery(query);
-
- return contents;
+ return contents;
+ }
}
///
@@ -147,12 +149,13 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetChildren(int id)
{
- var repository = _contentRepository;
+ using(var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.ParentId == id);
+ var contents = repository.GetByQuery(query);
- var query = Query.Builder.Where(x => x.ParentId == id);
- var contents = repository.GetByQuery(query);
-
- return contents;
+ return contents;
+ }
}
///
@@ -162,9 +165,12 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetVersions(int id)
{
- var repository = _contentRepository;
- var versions = repository.GetAllVersions(id);
- return versions;
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var versions = repository.GetAllVersions(id);
+ return versions;
+ }
+
}
///
@@ -173,12 +179,13 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetRootContent()
{
- var repository = _contentRepository;
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.ParentId == -1);
+ var contents = repository.GetByQuery(query);
- var query = Query.Builder.Where(x => x.ParentId == -1);
- var contents = repository.GetByQuery(query);
-
- return contents;
+ return contents;
+ }
}
///
@@ -187,12 +194,13 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetContentForExpiration()
{
- var repository = _contentRepository;
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.Published == true && x.ExpireDate <= DateTime.UtcNow);
+ var contents = repository.GetByQuery(query);
- var query = Query.Builder.Where(x => x.Published == true && x.ExpireDate <= DateTime.UtcNow);
- var contents = repository.GetByQuery(query);
-
- return contents;
+ return contents;
+ }
}
///
@@ -201,12 +209,13 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetContentForRelease()
{
- var repository = _contentRepository;
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.Published == false && x.ReleaseDate <= DateTime.UtcNow);
+ var contents = repository.GetByQuery(query);
- var query = Query.Builder.Where(x => x.Published == false && x.ReleaseDate <= DateTime.UtcNow);
- var contents = repository.GetByQuery(query);
-
- return contents;
+ return contents;
+ }
}
///
@@ -215,12 +224,13 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetContentInRecycleBin()
{
- var repository = _contentRepository;
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.ParentId == -20);
+ var contents = repository.GetByQuery(query);
- var query = Query.Builder.Where(x => x.ParentId == -20);
- var contents = repository.GetByQuery(query);
-
- return contents;
+ return contents;
+ }
}
///
@@ -230,41 +240,43 @@ namespace Umbraco.Core.Services
/// True if publishing succeeded, otherwise False
public bool RePublishAll(int userId = -1)
{
- var repository = _contentRepository;
-
- var list = new List();
-
- //Consider creating a Path query instead of recursive method:
- //var query = Query.Builder.Where(x => x.Path.StartsWith("-1"));
-
- var rootContent = GetRootContent();
- foreach (var content in rootContent)
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
{
- if(content.IsValid())
- {
- list.Add(content);
- list.AddRange(GetChildrenDeep(content.Id));
- }
+ var list = new List();
+
+ //Consider creating a Path query instead of recursive method:
+ //var query = Query.Builder.Where(x => x.Path.StartsWith("-1"));
+
+ var rootContent = GetRootContent();
+ foreach (var content in rootContent)
+ {
+ if (content.IsValid())
+ {
+ list.Add(content);
+ list.AddRange(GetChildrenDeep(content.Id));
+ }
+ }
+
+ //Publish and then update the database with new status
+ var published = _publishingStrategy.PublishWithChildren(list, userId);
+ if (published)
+ {
+ //Only loop through content where the Published property has been updated
+ foreach (var item in list.Where(x => ((ICanBeDirty)x).IsPropertyDirty("Published")))
+ {
+ SetWriter(item, userId);
+ repository.AddOrUpdate(item);
+ }
+
+ uow.Commit();
+
+ //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
+ //global::umbraco.library.RefreshContent();
+ }
+
+ return published;
}
-
- //Publish and then update the database with new status
- var published = _publishingStrategy.PublishWithChildren(list, userId);
- if (published)
- {
- //Only loop through content where the Published property has been updated
- foreach (var item in list.Where(x => ((ICanBeDirty)x).IsPropertyDirty("Published")))
- {
- SetWriter(item, userId);
- repository.AddOrUpdate(item);
- }
-
- _unitOfWork.Commit();
-
- //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
- //global::umbraco.library.RefreshContent();
- }
-
- return published;
}
///
@@ -286,52 +298,54 @@ namespace Umbraco.Core.Services
/// True if publishing succeeded, otherwise False
public bool PublishWithChildren(IContent content, int userId = -1)
{
- var repository = _contentRepository;
-
- //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
- if (content.ParentId != -1 && content.ParentId != -20 && !GetById(content.ParentId).Published)
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
{
- LogHelper.Info(
- string.Format("Content '{0}' with Id '{1}' could not be published because its parent is not published.",
- content.Name, content.Id));
- return false;
- }
+ //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
+ if (content.ParentId != -1 && content.ParentId != -20 && !GetById(content.ParentId).Published)
+ {
+ LogHelper.Info(
+ string.Format("Content '{0}' with Id '{1}' could not be published because its parent is not published.",
+ content.Name, content.Id));
+ return false;
+ }
- //Content contains invalid property values and can therefore not be published - fire event?
- if (!content.IsValid())
- {
- LogHelper.Info(
- string.Format("Content '{0}' with Id '{1}' could not be published because of invalid properties.",
- content.Name, content.Id));
- return false;
- }
+ //Content contains invalid property values and can therefore not be published - fire event?
+ if (!content.IsValid())
+ {
+ LogHelper.Info(
+ string.Format("Content '{0}' with Id '{1}' could not be published because of invalid properties.",
+ content.Name, content.Id));
+ return false;
+ }
- //Consider creating a Path query instead of recursive method:
- //var query = Query.Builder.Where(x => x.Path.StartsWith(content.Path));
+ //Consider creating a Path query instead of recursive method:
+ //var query = Query.Builder.Where(x => x.Path.StartsWith(content.Path));
- var list = new List();
- list.Add(content);
- list.AddRange(GetChildrenDeep(content.Id));
+ var list = new List();
+ list.Add(content);
+ list.AddRange(GetChildrenDeep(content.Id));
- //Publish and then update the database with new status
- var published = _publishingStrategy.PublishWithChildren(list, userId);
- if (published)
- {
- //Only loop through content where the Published property has been updated
- foreach (var item in list.Where(x => ((ICanBeDirty)x).IsPropertyDirty("Published")))
- {
- SetWriter(item, userId);
- repository.AddOrUpdate(item);
- }
+ //Publish and then update the database with new status
+ var published = _publishingStrategy.PublishWithChildren(list, userId);
+ if (published)
+ {
+ //Only loop through content where the Published property has been updated
+ foreach (var item in list.Where(x => ((ICanBeDirty)x).IsPropertyDirty("Published")))
+ {
+ SetWriter(item, userId);
+ repository.AddOrUpdate(item);
+ }
- _unitOfWork.Commit();
+ uow.Commit();
- //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
- //TODO Need to investigate if it will also update the cache for children of the Content object
- //global::umbraco.library.UpdateDocumentCache(content.Id);
- }
+ //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
+ //TODO Need to investigate if it will also update the cache for children of the Content object
+ //global::umbraco.library.UpdateDocumentCache(content.Id);
+ }
- return published;
+ return published;
+ }
}
///
@@ -342,39 +356,41 @@ namespace Umbraco.Core.Services
/// True if unpublishing succeeded, otherwise False
public bool UnPublish(IContent content, int userId = -1)
{
- var repository = _contentRepository;
-
- //Look for children and unpublish them if any exists, otherwise just unpublish the passed in Content.
- var children = GetChildrenDeep(content.Id);
- var hasChildren = children.Any();
-
- if(hasChildren)
- children.Add(content);
-
- var unpublished = hasChildren
- ? _publishingStrategy.UnPublish(children, userId)
- : _publishingStrategy.UnPublish(content, userId);
-
- if (unpublished)
+ var uow = _uowProvider.GetUnitOfWork();
+ using(var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
{
- repository.AddOrUpdate(content);
+ //Look for children and unpublish them if any exists, otherwise just unpublish the passed in Content.
+ var children = GetChildrenDeep(content.Id);
+ var hasChildren = children.Any();
- if (hasChildren)
- {
- foreach (var child in children)
- {
- SetWriter(child, userId);
- repository.AddOrUpdate(child);
- }
- }
+ if (hasChildren)
+ children.Add(content);
- _unitOfWork.Commit();
+ var unpublished = hasChildren
+ ? _publishingStrategy.UnPublish(children, userId)
+ : _publishingStrategy.UnPublish(content, userId);
- //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content class.
- //global::umbraco.library.UnPublishSingleNode(content.Id);
+ if (unpublished)
+ {
+ repository.AddOrUpdate(content);
+
+ if (hasChildren)
+ {
+ foreach (var child in children)
+ {
+ SetWriter(child, userId);
+ repository.AddOrUpdate(child);
+ }
+ }
+
+ uow.Commit();
+
+ //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content class.
+ //global::umbraco.library.UnPublishSingleNode(content.Id);
+ }
+
+ return unpublished;
}
-
- return unpublished;
}
///
@@ -410,54 +426,58 @@ namespace Umbraco.Core.Services
/// Optional Id of the User issueing the publishing
/// True if publishing succeeded, otherwise False
public bool SaveAndPublish(IContent content, int userId = -1)
- {
- var e = new SaveEventArgs();
- if (Saving != null)
- Saving(content, e);
+ {
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
+ {
+ var e = new SaveEventArgs(uow);
+ if (Saving != null)
+ Saving(content, e);
- if (!e.Cancel)
- {
- var repository = _contentRepository;
+ if (!e.Cancel)
+ {
- //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
- if (content.ParentId != -1 && content.ParentId != -20 && GetById(content.ParentId).Published == false)
- {
- LogHelper.Info(
- string.Format(
- "Content '{0}' with Id '{1}' could not be published because its parent is not published.",
- content.Name, content.Id));
- return false;
- }
+ //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
+ if (content.ParentId != -1 && content.ParentId != -20 && GetById(content.ParentId).Published == false)
+ {
+ LogHelper.Info(
+ string.Format(
+ "Content '{0}' with Id '{1}' could not be published because its parent is not published.",
+ content.Name, content.Id));
+ return false;
+ }
- //Content contains invalid property values and can therefore not be published - fire event?
- if (!content.IsValid())
- {
- LogHelper.Info(
- string.Format(
- "Content '{0}' with Id '{1}' could not be published because of invalid properties.",
- content.Name, content.Id));
- return false;
- }
+ //Content contains invalid property values and can therefore not be published - fire event?
+ if (!content.IsValid())
+ {
+ LogHelper.Info(
+ string.Format(
+ "Content '{0}' with Id '{1}' could not be published because of invalid properties.",
+ content.Name, content.Id));
+ return false;
+ }
- //Publish and then update the database with new status
- bool published = _publishingStrategy.Publish(content, userId);
- if (published)
- {
- SetWriter(content, userId);
- repository.AddOrUpdate(content);
- _unitOfWork.Commit();
+ //Publish and then update the database with new status
+ bool published = _publishingStrategy.Publish(content, userId);
+ if (published)
+ {
+ SetWriter(content, userId);
+ repository.AddOrUpdate(content);
+ uow.Commit();
- //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
- //global::umbraco.library.UpdateDocumentCache(content.Id);
- }
+ //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
+ //global::umbraco.library.UpdateDocumentCache(content.Id);
+ }
- if (Saved != null)
- Saved(content, e);
+ if (Saved != null)
+ Saved(content, e);
- return published;
- }
+ return published;
+ }
- return false;
+
+ return false;
+ }
}
///
@@ -467,22 +487,25 @@ namespace Umbraco.Core.Services
/// Optional Id of the User saving the Content
public void Save(IContent content, int userId = -1)
{
- var e = new SaveEventArgs();
- if (Saving != null)
- Saving(content, e);
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
+ {
+ var e = new SaveEventArgs(uow);
+ if (Saving != null)
+ Saving(content, e);
- if (!e.Cancel)
- {
- var repository = _contentRepository;
+ if (!e.Cancel)
+ {
- SetWriter(content, userId);
- content.ChangePublishedState(false);
- repository.AddOrUpdate(content);
- _unitOfWork.Commit();
+ SetWriter(content, userId);
+ content.ChangePublishedState(false);
+ repository.AddOrUpdate(content);
+ uow.Commit();
- if (Saved != null)
- Saved(content, e);
- }
+ if (Saved != null)
+ Saved(content, e);
+ }
+ }
}
///
@@ -496,41 +519,44 @@ namespace Umbraco.Core.Services
/// Optional Id of the User saving the Content
public void Save(IEnumerable contents, int userId = -1)
{
- var repository = _contentRepository;
- var containsNew = contents.Any(x => x.HasIdentity == false);
-
- var e = new SaveEventArgs();
- if (Saving != null)
- Saving(contents, e);
-
- if (!e.Cancel)
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
{
- if (containsNew)
- {
- foreach (var content in contents)
- {
- SetWriter(content, userId);
- content.ChangePublishedState(false);
- repository.AddOrUpdate(content);
- _unitOfWork.Commit();
- }
- }
- else
- {
- foreach (var content in contents)
- {
- if (Saving != null)
- Saving(content, e);
+ var containsNew = contents.Any(x => x.HasIdentity == false);
- SetWriter(content, userId);
- repository.AddOrUpdate(content);
- }
- _unitOfWork.Commit();
- }
+ var e = new SaveEventArgs(uow);
+ if (Saving != null)
+ Saving(contents, e);
- if (Saved != null)
- Saved(contents, e);
- }
+ if (!e.Cancel)
+ {
+ if (containsNew)
+ {
+ foreach (var content in contents)
+ {
+ SetWriter(content, userId);
+ content.ChangePublishedState(false);
+ repository.AddOrUpdate(content);
+ uow.Commit();
+ }
+ }
+ else
+ {
+ foreach (var content in contents)
+ {
+ if (Saving != null)
+ Saving(content, e);
+
+ SetWriter(content, userId);
+ repository.AddOrUpdate(content);
+ }
+ uow.Commit();
+ }
+
+ if (Saved != null)
+ Saved(contents, e);
+ }
+ }
}
///
@@ -544,24 +570,26 @@ namespace Umbraco.Core.Services
/// Optional Id of the User saving the Content
public void Save(IEnumerable> contents, int userId = -1)
{
- var repository = _contentRepository;
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
+ {
+ var e = new SaveEventArgs(uow);
+ if (Saving != null)
+ Saving(contents, e);
- var e = new SaveEventArgs();
- if (Saving != null)
- Saving(contents, e);
-
- if (!e.Cancel)
- {
- foreach (var content in contents)
- {
- SetWriter(content.Value, userId);
- content.Value.ChangePublishedState(false);
- repository.AddOrUpdate(content.Value);
- _unitOfWork.Commit();
- }
- if (Saved != null)
- Saved(contents, e);
- }
+ if (!e.Cancel)
+ {
+ foreach (var content in contents)
+ {
+ SetWriter(content.Value, userId);
+ content.Value.ChangePublishedState(false);
+ repository.AddOrUpdate(content.Value);
+ uow.Commit();
+ }
+ if (Saved != null)
+ Saved(contents, e);
+ }
+ }
}
///
@@ -571,29 +599,31 @@ namespace Umbraco.Core.Services
/// Id of the
public void DeleteContentOfType(int contentTypeId)
{
- var repository = _contentRepository;
-
- //NOTE What about content that has the contenttype as part of its composition?
- var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId);
- var contents = repository.GetByQuery(query);
-
- var e = new DeleteEventArgs { Id = contentTypeId };
- if (Deleting != null)
- Deleting(contents, e);
-
- if (!e.Cancel)
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
{
- foreach (var content in contents)
- {
- ((Content) content).ChangeTrashedState(true);
- repository.AddOrUpdate(content);
- }
+ //NOTE What about content that has the contenttype as part of its composition?
+ var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId);
+ var contents = repository.GetByQuery(query);
- _unitOfWork.Commit();
+ var e = new DeleteEventArgs { Id = contentTypeId };
+ if (Deleting != null)
+ Deleting(contents, e);
- if (Deleted != null)
- Deleted(contents, e);
- }
+ if (!e.Cancel)
+ {
+ foreach (var content in contents)
+ {
+ ((Content)content).ChangeTrashedState(true);
+ repository.AddOrUpdate(content);
+ }
+
+ uow.Commit();
+
+ if (Deleted != null)
+ Deleted(contents, e);
+ }
+ }
}
///
@@ -614,13 +644,17 @@ namespace Umbraco.Core.Services
if (!e.Cancel)
{
- var repository = _contentRepository;
- SetWriter(content, userId);
- repository.Delete(content);
- _unitOfWork.Commit();
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
+ {
+ SetWriter(content, userId);
+ repository.Delete(content);
+ uow.Commit();
- if (Deleted != null)
- Deleted(content, e);
+ if (Deleted != null)
+ Deleted(content, e);
+ }
+
}
}
@@ -661,11 +695,14 @@ namespace Umbraco.Core.Services
if (!e.Cancel)
{
- var repository = _contentRepository;
- repository.Delete(id, versionDate);
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ repository.Delete(id, versionDate);
- if (Deleted != null)
- Deleted(versionDate, e);
+ if (Deleted != null)
+ Deleted(versionDate, e);
+ }
+
}
}
@@ -678,25 +715,26 @@ namespace Umbraco.Core.Services
/// Optional Id of the User deleting versions of a Content object
public void Delete(int id, Guid versionId, bool deletePriorVersions, int userId = -1)
{
- var repository = _contentRepository;
-
- if(deletePriorVersions)
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
{
- var content = repository.GetByVersion(id, versionId);
- Delete(id, content.UpdateDate, userId);
- }
+ if (deletePriorVersions)
+ {
+ var content = repository.GetByVersion(id, versionId);
+ Delete(id, content.UpdateDate, userId);
+ }
- var e = new DeleteEventArgs {Id = id};
- if (Deleting != null)
- Deleting(versionId, e);
+ var e = new DeleteEventArgs { Id = id };
+ if (Deleting != null)
+ Deleting(versionId, e);
- if (!e.Cancel)
- {
- repository.Delete(id, versionId);
+ if (!e.Cancel)
+ {
+ repository.Delete(id, versionId);
- if (Deleted != null)
- Deleted(versionId, e);
- }
+ if (Deleted != null)
+ Deleted(versionId, e);
+ }
+ }
}
///
@@ -709,11 +747,15 @@ namespace Umbraco.Core.Services
{
//TODO If content item has children those should also be moved to the recycle bin
//TODO Unpublish deleted content + children
- var repository = _contentRepository;
- SetWriter(content, userId);
- content.ChangeTrashedState(true);
- repository.AddOrUpdate(content);
- _unitOfWork.Commit();
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
+ {
+ SetWriter(content, userId);
+ content.ChangeTrashedState(true);
+ repository.AddOrUpdate(content);
+ uow.Commit();
+ }
+
}
///
@@ -767,16 +809,18 @@ namespace Umbraco.Core.Services
///
public void EmptyRecycleBin()
{
- var repository = _contentRepository;
-
- var query = Query.Builder.Where(x => x.ParentId == -20);
- var contents = repository.GetByQuery(query);
-
- foreach (var content in contents)
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
{
- repository.Delete(content);
- }
- _unitOfWork.Commit();
+ var query = Query.Builder.Where(x => x.ParentId == -20);
+ var contents = repository.GetByQuery(query);
+
+ foreach (var content in contents)
+ {
+ repository.Delete(content);
+ }
+ uow.Commit();
+ }
}
///
@@ -801,12 +845,14 @@ namespace Umbraco.Core.Services
copy.ParentId = parentId;
copy.Name = copy.Name + " (1)";
- var repository = _contentRepository;
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
+ {
+ SetWriter(content, userId);
- SetWriter(content, userId);
-
- repository.AddOrUpdate(copy);
- _unitOfWork.Commit();
+ repository.AddOrUpdate(copy);
+ uow.Commit();
+ }
}
if(Copied != null)
@@ -867,25 +913,28 @@ namespace Umbraco.Core.Services
{
var e = new RollbackEventArgs();
- var repository = _contentRepository;
- var content = repository.GetByVersion(id, versionId);
-
- if (Rollingback != null)
- Rollingback(content, e);
-
- if (!e.Cancel)
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = RepositoryResolver.Current.Factory.CreateContentRepository(uow))
{
- SetUser(content, userId);
- SetWriter(content, userId);
+ var content = repository.GetByVersion(id, versionId);
- repository.AddOrUpdate(content);
- _unitOfWork.Commit();
+ if (Rollingback != null)
+ Rollingback(content, e);
- if (Rolledback != null)
- Rolledback(content, e);
+ if (!e.Cancel)
+ {
+ SetUser(content, userId);
+ SetWriter(content, userId);
+
+ repository.AddOrUpdate(content);
+ uow.Commit();
+
+ if (Rolledback != null)
+ Rolledback(content, e);
+ }
+
+ return content;
}
-
- return content;
}
///
diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs
index 77c728d37b..efd63bb503 100644
--- a/src/Umbraco.Core/Services/ContentTypeService.cs
+++ b/src/Umbraco.Core/Services/ContentTypeService.cs
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Services
{
private readonly IContentService _contentService;
private readonly IMediaService _mediaService;
- private readonly IUnitOfWork _unitOfWork;
+ private readonly IDatabaseUnitOfWork _unitOfWork;
private readonly IContentTypeRepository _contentTypeRepository;
private readonly IMediaTypeRepository _mediaTypeRepository;
@@ -27,7 +27,7 @@ namespace Umbraco.Core.Services
: this(contentService, mediaService, new PetaPocoUnitOfWorkProvider())
{}
- public ContentTypeService(IContentService contentService, IMediaService mediaService, IUnitOfWorkProvider provider)
+ public ContentTypeService(IContentService contentService, IMediaService mediaService, IDatabaseUnitOfWorkProvider provider)
{
_contentService = contentService;
_mediaService = mediaService;
diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs
index cf9f68896e..119eb8411d 100644
--- a/src/Umbraco.Core/Services/DataTypeService.cs
+++ b/src/Umbraco.Core/Services/DataTypeService.cs
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Services
///
public class DataTypeService : IDataTypeService
{
- private readonly IUnitOfWork _unitOfWork;
+ private readonly IDatabaseUnitOfWork _unitOfWork;
private readonly IDataTypeDefinitionRepository _dataTypeService;
private readonly IContentTypeRepository _contentTypeRepository;
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Services
{
}
- public DataTypeService(IUnitOfWorkProvider provider)
+ public DataTypeService(IDatabaseUnitOfWorkProvider provider)
{
_unitOfWork = provider.GetUnitOfWork();
_dataTypeService = RepositoryResolver.Current.Factory.CreateDataTypeDefinitionRepository(_unitOfWork);
diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs
index 9695db5c11..131b987df9 100644
--- a/src/Umbraco.Core/Services/FileService.cs
+++ b/src/Umbraco.Core/Services/FileService.cs
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Services
public class FileService : IFileService
{
private readonly IUnitOfWork _fileUnitOfWork;
- private readonly IUnitOfWork _dataUnitOfWork;
+ private readonly IDatabaseUnitOfWork _dataUnitOfWork;
private readonly IStylesheetRepository _stylesheetRepository;
private readonly IScriptRepository _scriptRepository;
private readonly ITemplateRepository _templateRepository;
@@ -21,7 +21,7 @@ namespace Umbraco.Core.Services
{
}
- public FileService(IUnitOfWorkProvider fileProvider, IUnitOfWorkProvider dataProvider)
+ public FileService(IUnitOfWorkProvider fileProvider, IDatabaseUnitOfWorkProvider dataProvider)
{
_fileUnitOfWork = fileProvider.GetUnitOfWork();
_dataUnitOfWork = dataProvider.GetUnitOfWork();
diff --git a/src/Umbraco.Core/Services/LocalizationService.cs b/src/Umbraco.Core/Services/LocalizationService.cs
index df7770c138..6c1edee8f9 100644
--- a/src/Umbraco.Core/Services/LocalizationService.cs
+++ b/src/Umbraco.Core/Services/LocalizationService.cs
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Services
public class LocalizationService : ILocalizationService
{
private static readonly Guid RootParentId = new Guid("41c7638d-f529-4bff-853e-59a0c2fb1bde");
- private readonly IUnitOfWork _unitOfWork;
+ private readonly IDatabaseUnitOfWork _unitOfWork;
private readonly IDictionaryRepository _dictionaryRepository;
private readonly ILanguageRepository _languageRepository;
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Services
{
}
- public LocalizationService(IUnitOfWorkProvider provider)
+ public LocalizationService(IDatabaseUnitOfWorkProvider provider)
{
_unitOfWork = provider.GetUnitOfWork();
_dictionaryRepository = RepositoryResolver.Current.Factory.CreateDictionaryRepository(_unitOfWork);
diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs
index b4d13cd947..a8333e1691 100644
--- a/src/Umbraco.Core/Services/MediaService.cs
+++ b/src/Umbraco.Core/Services/MediaService.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
@@ -12,14 +13,14 @@ namespace Umbraco.Core.Services
///
public class MediaService : IMediaService
{
- private readonly IUnitOfWork _unitOfWork;
+ private readonly IDatabaseUnitOfWork _unitOfWork;
private readonly IMediaRepository _mediaRepository;
public MediaService() : this(new PetaPocoUnitOfWorkProvider())
{
}
- public MediaService(IUnitOfWorkProvider provider)
+ public MediaService(IDatabaseUnitOfWorkProvider provider)
{
_unitOfWork = provider.GetUnitOfWork();
_mediaRepository = RepositoryResolver.Current.Factory.CreateMediaRepository(_unitOfWork);
@@ -202,8 +203,19 @@ namespace Umbraco.Core.Services
public void Save(IMedia media, int userId)
{
var repository = _mediaRepository;
- repository.AddOrUpdate(media);
- _unitOfWork.Commit();
+
+ var e = new SaveEventArgs(_unitOfWork);
+ if (Saving != null)
+ Saving(media, e);
+
+ if (!e.Cancel)
+ {
+ repository.AddOrUpdate(media);
+ _unitOfWork.Commit();
+
+ if (Saved != null)
+ Saved(media, e);
+ }
}
///
@@ -220,5 +232,15 @@ namespace Umbraco.Core.Services
}
_unitOfWork.Commit();
}
+
+ ///
+ /// Occurs before Save
+ ///
+ public static event EventHandler Saving;
+
+ ///
+ /// Occurs after Save
+ ///
+ public static event EventHandler Saved;
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs
index 6e44a4c405..1cf810d0f9 100644
--- a/src/Umbraco.Core/Services/ServiceContext.cs
+++ b/src/Umbraco.Core/Services/ServiceContext.cs
@@ -31,18 +31,29 @@ namespace Umbraco.Core.Services
private ServiceContext()
{
- BuildServiceCache();
+ BuildServiceCache(new PetaPocoUnitOfWorkProvider(), new FileUnitOfWorkProvider(), new PublishingStrategy());
}
+
+ ///
+ /// Internal constructor used for unit tests
+ ///
+ ///
+ ///
+ ///
+ internal ServiceContext(IDatabaseUnitOfWorkProvider dbUnitOfWorkProvider, IUnitOfWorkProvider fileUnitOfWorkProvider, IPublishingStrategy publishingStrategy)
+ {
+ BuildServiceCache(dbUnitOfWorkProvider, fileUnitOfWorkProvider, publishingStrategy);
+ }
+
#endregion
///
/// Builds the various services
///
- private void BuildServiceCache()
+ private void BuildServiceCache(IDatabaseUnitOfWorkProvider dbUnitOfWorkProvider, IUnitOfWorkProvider fileUnitOfWorkProvider, IPublishingStrategy publishingStrategy)
{
- var provider = new PetaPocoUnitOfWorkProvider();
- var fileProvider = new FileUnitOfWorkProvider();
- var publishingStrategy = new PublishingStrategy();
+ var provider = dbUnitOfWorkProvider;
+ var fileProvider = fileUnitOfWorkProvider;
if(_userService == null)
_userService = new UserService(provider);
diff --git a/src/Umbraco.Core/Services/UserService.cs b/src/Umbraco.Core/Services/UserService.cs
index 3281800830..16e94d3af2 100644
--- a/src/Umbraco.Core/Services/UserService.cs
+++ b/src/Umbraco.Core/Services/UserService.cs
@@ -12,10 +12,10 @@ namespace Umbraco.Core.Services
///
internal class UserService : IUserService
{
- private readonly IUnitOfWork _unitOfWork;
+ private readonly IDatabaseUnitOfWork _unitOfWork;
private readonly IUserRepository _userRepository;
- public UserService(IUnitOfWorkProvider provider)
+ public UserService(IDatabaseUnitOfWorkProvider provider)
{
_unitOfWork = provider.GetUnitOfWork();
_userRepository = RepositoryResolver.Current.Factory.CreateUserRepository(_unitOfWork);
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 33b1f5aa46..a228f0fec5 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -400,6 +400,8 @@
+
+
diff --git a/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs b/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs
index 659243a258..3d6c3e6a9a 100644
--- a/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs
+++ b/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs
@@ -228,9 +228,6 @@ namespace Umbraco.Tests.CodeFirst
[TearDown]
public override void TearDown()
{
-
- DatabaseContext.Database.Dispose();
-
base.TearDown();
//reset the app context
diff --git a/src/Umbraco.Tests/Models/ContentXmlTest.cs b/src/Umbraco.Tests/Models/ContentXmlTest.cs
index 0512a94116..343dc0be9b 100644
--- a/src/Umbraco.Tests/Models/ContentXmlTest.cs
+++ b/src/Umbraco.Tests/Models/ContentXmlTest.cs
@@ -38,8 +38,6 @@ namespace Umbraco.Tests.Models
[TearDown]
public override void TearDown()
{
- DatabaseContext.Database.Dispose();
-
//reset the app context
DataTypesResolver.Reset();
diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
index 521d4d94b9..906a1909ff 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
@@ -13,7 +13,7 @@ using Umbraco.Tests.TestHelpers.Entities;
namespace Umbraco.Tests.Persistence.Repositories
{
- [TestFixture]
+ [TestFixture]
public class ContentRepositoryTest : BaseDatabaseFactoryTest
{
[SetUp]
diff --git a/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs b/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs
index 48e5acb4ac..80c05585c1 100644
--- a/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs
+++ b/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs
@@ -29,14 +29,14 @@ namespace Umbraco.Tests.Persistence
//[TestCase(typeof(IUserTypeRepository))]
//[TestCase(typeof(IUserRepository))]
+ //[TestCase(typeof(IMacroRepository))]
[TestCase(typeof(IContentRepository))]
[TestCase(typeof(IMediaRepository))]
[TestCase(typeof(IMediaTypeRepository))]
[TestCase(typeof(IContentTypeRepository))]
[TestCase(typeof(IDataTypeDefinitionRepository))]
[TestCase(typeof(IDictionaryRepository))]
- [TestCase(typeof(ILanguageRepository))]
- //[TestCase(typeof(IMacroRepository))]
+ [TestCase(typeof(ILanguageRepository))]
[TestCase(typeof(IRelationRepository))]
[TestCase(typeof(IRelationTypeRepository))]
[TestCase(typeof(IScriptRepository))]
@@ -46,29 +46,16 @@ namespace Umbraco.Tests.Persistence
{
var method = typeof(RepositoryResolver).GetMethod("ResolveByType", BindingFlags.NonPublic | BindingFlags.Instance);
var gMethod = method.MakeGenericMethod(repoType);
- var repo = gMethod.Invoke(RepositoryResolver.Current, new object[] { new PetaPocoUnitOfWork() });
+ var repo = gMethod.Invoke(RepositoryResolver.Current, new object[] { new PetaPocoUnitOfWork(DatabaseFactory.Current.Database) });
Assert.IsNotNull(repo);
Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(repoType, repo.GetType()));
}
- //[Test]
- //public void Can_Resolve_All_Repositories()
- //{
- // // Arrange
- // var uow = new PetaPocoUnitOfWork();
-
- // // Act
- // RepositoryResolver.RegisterRepositories();
-
- // // Assert
- // Assert.That(RepositoryResolver.RegisteredRepositories(), Is.EqualTo(15));
- //}
-
- [Test]
+ [Test]
public void Can_Verify_UOW_In_Repository()
{
// Arrange
- var uow = new PetaPocoUnitOfWork();
+ var uow = new PetaPocoUnitOfWork(DatabaseFactory.Current.Database);
// Act
var repository = RepositoryResolver.Current.ResolveByType(uow);
@@ -87,8 +74,8 @@ namespace Umbraco.Tests.Persistence
Assert.That(isSubclassOf, Is.False);
Assert.That(isAssignableFrom, Is.True);
-
- var uow = new PetaPocoUnitOfWork();
+
+ var uow = new PetaPocoUnitOfWork(DatabaseFactory.Current.Database);
var repository = RepositoryResolver.Current.ResolveByType(uow);
bool subclassOf = repository.GetType().IsSubclassOf(typeof (IRepository));
diff --git a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs b/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs
index 9e6ea58ed8..17b9ad9130 100644
--- a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs
+++ b/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs
@@ -46,8 +46,8 @@ namespace Umbraco.Tests.Publishing
[TearDown]
public override void TearDown()
{
- DatabaseContext.Database.Dispose();
-
+ base.TearDown();
+
//TestHelper.ClearDatabase();
//reset the app context
diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs
index f5fb884ef3..9096df8ad9 100644
--- a/src/Umbraco.Tests/Services/ContentServiceTests.cs
+++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs
@@ -14,7 +14,7 @@ using Umbraco.Tests.TestHelpers.Entities;
namespace Umbraco.Tests.Services
{
- ///
+ ///
/// Tests covering all methods in the ContentService class.
/// This is more of an integration test as it involves multiple layers
/// as well as configuration.
@@ -668,7 +668,7 @@ namespace Umbraco.Tests.Services
[Test]
public void Can_Save_Lazy_Content()
{
- var unitOfWork = new PetaPocoUnitOfWork();
+ var unitOfWork = new PetaPocoUnitOfWork(DatabaseFactory.Current.Database);
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
var root = ServiceContext.ContentService.GetById(1046);
diff --git a/src/Umbraco.Tests/Services/ThreadSafetyServiceTest.cs b/src/Umbraco.Tests/Services/ThreadSafetyServiceTest.cs
new file mode 100644
index 0000000000..1be8d4afbe
--- /dev/null
+++ b/src/Umbraco.Tests/Services/ThreadSafetyServiceTest.cs
@@ -0,0 +1,257 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using NUnit.Framework;
+using Umbraco.Core;
+using Umbraco.Core.Models;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.UnitOfWork;
+using Umbraco.Core.Publishing;
+using Umbraco.Core.Services;
+using Umbraco.Tests.TestHelpers;
+using Umbraco.Tests.TestHelpers.Entities;
+
+namespace Umbraco.Tests.Services
+{
+ [TestFixture]
+ public class ThreadSafetyServiceTest : BaseDatabaseFactoryTest
+ {
+ private PerThreadPetaPocoUnitOfWorkProvider _uowProvider;
+
+ [SetUp]
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ //here we are going to override the ServiceContext because normally with our test cases we use a
+ //global Database object but this is NOT how it should work in the web world or in any multi threaded scenario.
+ //we need a new Database object for each thread.
+ _uowProvider = new PerThreadPetaPocoUnitOfWorkProvider();
+ ServiceContext = new ServiceContext(_uowProvider, new FileUnitOfWorkProvider(), new PublishingStrategy());
+
+ CreateTestData();
+ }
+
+ [TearDown]
+ public override void TearDown()
+ {
+ _error = null;
+ _lastUowIdWithThread = null;
+
+ //dispose!
+ _uowProvider.Dispose();
+
+ base.TearDown();
+
+ ServiceContext = null;
+ }
+
+ ///
+ /// Used to track exceptions during multi-threaded tests, volatile so that it is not locked in CPU registers.
+ ///
+ private volatile Exception _error = null;
+
+ private int _maxThreadCount = 20;
+ private object _locker = new object();
+ private Tuple _lastUowIdWithThread = null;
+
+ [Test]
+ public void Ensure_All_Threads_Reference_Different_Units_Of_Work_Content_Service()
+ {
+ //we will mimick the ServiceContext in that each repository in a service (i.e. ContentService) is a singleton
+ var contentService = (ContentService)ServiceContext.ContentService;
+
+ var threads = new List();
+
+ Debug.WriteLine("Starting test...");
+
+ //bind to event to determine what is going on during the saving process
+ ContentService.Saving += HandleSaving;
+
+ for (var i = 0; i < _maxThreadCount; i++)
+ {
+ var t = new Thread(() =>
+ {
+ try
+ {
+ Debug.WriteLine("Created content on thread: " + Thread.CurrentThread.ManagedThreadId);
+
+ //create 2 content items
+
+ var content1 = contentService.CreateContent(-1, "umbTextpage", 0);
+ content1.Name = "test" + Guid.NewGuid();
+ Debug.WriteLine("Saving content1 on thread: " + Thread.CurrentThread.ManagedThreadId);
+ contentService.Save(content1);
+
+ Thread.Sleep(100); //quick pause for maximum overlap!
+
+ var content2 = contentService.CreateContent(-1, "umbTextpage", 0);
+ content2.Name = "test" + Guid.NewGuid();
+ Debug.WriteLine("Saving content2 on thread: " + Thread.CurrentThread.ManagedThreadId);
+ contentService.Save(content2);
+ }
+ catch(Exception e)
+ {
+ _error = e;
+ }
+ });
+ threads.Add(t);
+ }
+
+ //start all threads
+ threads.ForEach(x => x.Start());
+
+ //wait for all to complete
+ threads.ForEach(x => x.Join());
+
+ //kill them all
+ threads.ForEach(x => x.Abort());
+
+ if (_error == null)
+ {
+ //now look up all items, there should be 40!
+ var items = contentService.GetRootContent();
+ Assert.AreEqual(40, items.Count());
+ }
+ else
+ {
+ Assert.Fail("ERROR! " + _error);
+ }
+
+ }
+
+ [Test]
+ public void Ensure_All_Threads_Reference_Different_Units_Of_Work_Media_Service()
+ {
+ //we will mimick the ServiceContext in that each repository in a service (i.e. ContentService) is a singleton
+ var mediaService = (MediaService)ServiceContext.MediaService;
+
+ var threads = new List();
+
+ Debug.WriteLine("Starting test...");
+
+ //bind to event to determine what is going on during the saving process
+ ContentService.Saving += HandleSaving;
+
+ for (var i = 0; i < _maxThreadCount; i++)
+ {
+ var t = new Thread(() =>
+ {
+ try
+ {
+ var folderMediaType = ServiceContext.ContentTypeService.GetMediaType(1031);
+
+ Debug.WriteLine("Created content on thread: " + Thread.CurrentThread.ManagedThreadId);
+
+ //create 2 content items
+
+ var folder1 = MockedMedia.CreateMediaFolder(folderMediaType, -1);
+ folder1.Name = "test" + Guid.NewGuid();
+ Debug.WriteLine("Saving folder1 on thread: " + Thread.CurrentThread.ManagedThreadId);
+ mediaService.Save(folder1, 0);
+
+ Thread.Sleep(100); //quick pause for maximum overlap!
+
+ var folder2 = MockedMedia.CreateMediaFolder(folderMediaType, -1);
+ folder2.Name = "test" + Guid.NewGuid();
+ Debug.WriteLine("Saving folder2 on thread: " + Thread.CurrentThread.ManagedThreadId);
+ mediaService.Save(folder2, 0);
+ }
+ catch (Exception e)
+ {
+ _error = e;
+ }
+ });
+ threads.Add(t);
+ }
+
+ //start all threads
+ threads.ForEach(x => x.Start());
+
+ //wait for all to complete
+ threads.ForEach(x => x.Join());
+
+ //kill them all
+ threads.ForEach(x => x.Abort());
+
+ if (_error == null)
+ {
+ //now look up all items, there should be 40!
+ var items = mediaService.GetRootMedia();
+ Assert.AreEqual(40, items.Count());
+ }
+ else
+ {
+ Assert.Fail("ERROR! " + _error);
+ }
+
+ }
+
+ private void HandleSaving(object sender, SaveEventArgs args)
+ {
+ if (_error == null)
+ {
+ lock (_locker)
+ {
+ //get the instance id of the unit of work
+ var uowId = ((PetaPocoUnitOfWork)args.UnitOfWork).InstanceId;
+ if (_lastUowIdWithThread == null)
+ {
+ Debug.WriteLine("Initial UOW found = " + uowId + " with thread id " + Thread.CurrentThread.ManagedThreadId);
+
+ _lastUowIdWithThread = new Tuple(
+ Thread.CurrentThread.ManagedThreadId, uowId);
+ }
+ else
+ {
+ Debug.WriteLine("Next thread running. UOW found = " + uowId + " with thread id " + Thread.CurrentThread.ManagedThreadId);
+
+ var newTuple = new Tuple(
+ Thread.CurrentThread.ManagedThreadId, uowId);
+
+ //check if the uowId is the same as the last and if the thread Id's are different then we have a problem
+ if (newTuple.Item2 == _lastUowIdWithThread.Item2
+ && newTuple.Item1 != _lastUowIdWithThread.Item1)
+ {
+ _error = new Exception("The threads: " + newTuple.Item1 + " and " + _lastUowIdWithThread.Item1 + " are both referencing the Unit of work: " + _lastUowIdWithThread.Item2);
+ }
+ }
+ }
+ }
+ }
+
+ public void CreateTestData()
+ {
+ //Create and Save ContentType "umbTextpage" -> 1045
+ ContentType contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage");
+ contentType.Key = new Guid("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522");
+ ServiceContext.ContentTypeService.Save(contentType);
+ }
+
+ ///
+ /// Creates a Database object per thread, this mimics the web context which is per HttpContext
+ ///
+ internal class PerThreadPetaPocoUnitOfWorkProvider : DisposableObject, IDatabaseUnitOfWorkProvider
+ {
+ private readonly ConcurrentDictionary _databases = new ConcurrentDictionary();
+
+ public IDatabaseUnitOfWork GetUnitOfWork()
+ {
+ //Create or get a database instance for this thread.
+ var db = _databases.GetOrAdd(Thread.CurrentThread.ManagedThreadId, i => new Database(Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName));
+
+ return new PetaPocoUnitOfWork(db);
+ }
+
+ protected override void DisposeResources()
+ {
+ //dispose the databases
+ _databases.ForEach(x => x.Value.Dispose());
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
index a613ab097a..9926e7d92a 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
@@ -10,6 +10,8 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.UnitOfWork;
+using Umbraco.Core.Publishing;
using Umbraco.Core.Services;
using Umbraco.Tests.Stubs;
using Umbraco.Web;
@@ -18,6 +20,7 @@ using umbraco.BusinessLogic;
namespace Umbraco.Tests.TestHelpers
{
+
///
/// Use this abstract class for tests that requires a Sql Ce database populated with the umbraco db schema.
/// The PetaPoco Database class should be used through the singleton.
@@ -57,7 +60,7 @@ namespace Umbraco.Tests.TestHelpers
Resolution.Freeze();
ApplicationContext = new ApplicationContext() { IsReady = true };
DatabaseContext = DatabaseContext.Current;
- ServiceContext = ServiceContext.Current;
+ ServiceContext = new ServiceContext(new PetaPocoUnitOfWorkProvider(), new FileUnitOfWorkProvider(), new PublishingStrategy());
//Configure the Database and Sql Syntax based on connection string set in config
DatabaseContext.Initialize();
@@ -69,6 +72,8 @@ namespace Umbraco.Tests.TestHelpers
[TearDown]
public virtual void TearDown()
{
+ DatabaseContext.Database.Dispose();
+
TestHelper.CleanContentDirectories();
//reset the app context
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 7ae3071121..09ed380ec0 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -235,6 +235,7 @@
+
diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs
index 29457c2ce7..90ded62fd2 100644
--- a/src/Umbraco.Web/UmbracoModule.cs
+++ b/src/Umbraco.Web/UmbracoModule.cs
@@ -421,13 +421,15 @@ namespace Umbraco.Web
app.EndRequest += (sender, args) =>
{
- var httpContext = ((HttpApplication)sender).Context;
+ var httpContext = ((HttpApplication)sender).Context;
if (UmbracoContext.Current != null && UmbracoContext.Current.IsFrontEndUmbracoRequest)
{
//write the trace output for diagnostics at the end of the request
httpContext.Trace.Write("UmbracoModule", "Umbraco request completed");
LogHelper.Debug("Total milliseconds for umbraco request to process: " + DateTime.Now.Subtract(UmbracoContext.Current.ObjectCreated).TotalMilliseconds);
- }
+ }
+
+ DisposeHttpContextItems(httpContext);
};
}
@@ -438,5 +440,16 @@ namespace Umbraco.Web
#endregion
+ ///
+ /// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request
+ ///
+ ///
+ private static void DisposeHttpContextItems(HttpContext http)
+ {
+ foreach(var i in http.Items)
+ {
+ i.DisposeIfDisposable();
+ }
+ }
}
}