diff --git a/src/SQLCE4Umbraco/SqlCeContextGuardian.cs b/src/SQLCE4Umbraco/SqlCeContextGuardian.cs
index eb47a15bfe..8206ac6c53 100644
--- a/src/SQLCE4Umbraco/SqlCeContextGuardian.cs
+++ b/src/SQLCE4Umbraco/SqlCeContextGuardian.cs
@@ -11,7 +11,7 @@ namespace SQLCE4Umbraco
public static class SqlCeContextGuardian
{
private static SqlCeConnection _constantOpenConnection;
- private static object objLock = new object();
+ private static readonly object Lock = new object();
// Awesome SQL CE 4 speed improvement by Erik Ejskov Jensen - SQL CE 4 MVP
// It's not an issue with SQL CE 4 that we never close the connection
@@ -29,7 +29,7 @@ namespace SQLCE4Umbraco
connectionStringBuilder.Remove("datalayer");
// SQL CE 4 performs better when there's always a connection open in the background
- ensureOpenBackgroundConnection(connectionStringBuilder.ConnectionString);
+ EnsureOpenBackgroundConnection(connectionStringBuilder.ConnectionString);
SqlCeConnection conn = new SqlCeConnection(connectionStringBuilder.ConnectionString);
conn.Open();
@@ -38,9 +38,18 @@ namespace SQLCE4Umbraco
}
- private static void ensureOpenBackgroundConnection(string connectionString)
+ ///
+ /// Sometimes we need to ensure this is closed especially in unit tests
+ ///
+ internal static void CloseBackgroundConnection()
+ {
+ if (_constantOpenConnection != null)
+ _constantOpenConnection.Close();
+ }
+
+ private static void EnsureOpenBackgroundConnection(string connectionString)
{
- lock (objLock)
+ lock (Lock)
{
if (_constantOpenConnection == null)
{
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWork.cs b/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWork.cs
index 5d1fa309b7..6f9f5fc220 100644
--- a/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWork.cs
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/PetaPocoUnitOfWork.cs
@@ -18,9 +18,6 @@ namespace Umbraco.Core.Persistence.UnitOfWork
private Guid _key;
private readonly List _operations = new List();
- private readonly Transaction _transaction;
- private bool _committed = false;
-
///
/// Creates a new unit of work instance
@@ -34,7 +31,6 @@ namespace Umbraco.Core.Persistence.UnitOfWork
Database = database;
_key = Guid.NewGuid();
InstanceId = Guid.NewGuid();
- _transaction = Database.GetTransaction();
}
///
@@ -91,34 +87,37 @@ namespace Umbraco.Core.Persistence.UnitOfWork
///
/// Commits all batched changes within the scope of a PetaPoco transaction
///
+ ///
+ /// Unlike a typical unit of work, this UOW will let you commit more than once since a new transaction is creaed per
+ /// Commit() call instead of having one Transaction per UOW.
+ ///
public void Commit()
{
- if (_committed)
+
+ using (var transaction = Database.GetTransaction())
{
- throw new InvalidOperationException("Cannot has already been called for this unit of work");
- }
-
- foreach (var operation in _operations.OrderBy(o => o.ProcessDate))
- {
- switch (operation.Type)
+ foreach (var operation in _operations.OrderBy(o => o.ProcessDate))
{
- case TransactionType.Insert:
- operation.Repository.PersistNewItem(operation.Entity);
- break;
- case TransactionType.Delete:
- operation.Repository.PersistDeletedItem(operation.Entity);
- break;
- case TransactionType.Update:
- operation.Repository.PersistUpdatedItem(operation.Entity);
- break;
+ switch (operation.Type)
+ {
+ case TransactionType.Insert:
+ operation.Repository.PersistNewItem(operation.Entity);
+ break;
+ case TransactionType.Delete:
+ operation.Repository.PersistDeletedItem(operation.Entity);
+ break;
+ case TransactionType.Update:
+ operation.Repository.PersistUpdatedItem(operation.Entity);
+ break;
+ }
}
+ transaction.Complete();
}
- _transaction.Complete();
+
// Clear everything
_operations.Clear();
_key = Guid.NewGuid();
- _committed = true;
}
public object Key
@@ -171,9 +170,6 @@ namespace Umbraco.Core.Persistence.UnitOfWork
protected override void DisposeResources()
{
_operations.Clear();
- _transaction.Dispose();
- //ensure the local object will be gargabe collected
- Database = null;
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PublishedContentExtensions.cs b/src/Umbraco.Core/PublishedContentExtensions.cs
index c039cf881c..c4ccf3af1c 100644
--- a/src/Umbraco.Core/PublishedContentExtensions.cs
+++ b/src/Umbraco.Core/PublishedContentExtensions.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.Net.Mime;
using System.Web;
+using Umbraco.Core.Dynamics;
using Umbraco.Core.Models;
using umbraco.interfaces;
@@ -83,6 +84,13 @@ namespace Umbraco.Core
///
public static string GetRecursiveValue(this IPublishedContent publishedContent, string fieldname)
{
+ //check for the cached value in the objects properties first
+ var cachedVal = publishedContent["__recursive__" + fieldname];
+ if (cachedVal != null)
+ {
+ return cachedVal.ToString();
+ }
+
var contentValue = "";
var currentContent = publishedContent;
@@ -102,6 +110,10 @@ namespace Umbraco.Core
contentValue = val.ToString(); //we've found a recursive val
}
}
+
+ //cache this lookup in a new custom (hidden) property
+ publishedContent.Properties.Add(new PropertyResult("__recursive__" + fieldname, contentValue, Guid.Empty, PropertyResultType.CustomProperty));
+
return contentValue;
}
diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs
index 4e375733de..4f5d0d696e 100644
--- a/src/Umbraco.Core/Services/ServiceContext.cs
+++ b/src/Umbraco.Core/Services/ServiceContext.cs
@@ -1,3 +1,4 @@
+using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Publishing;
@@ -11,14 +12,14 @@ namespace Umbraco.Core.Services
///
public class ServiceContext
{
- private ContentService _contentService;
- private UserService _userService;
- private MediaService _mediaService;
- private MacroService _macroService;
- private ContentTypeService _contentTypeService;
- private DataTypeService _dataTypeService;
- private FileService _fileService;
- private LocalizationService _localizationService;
+ private Lazy _contentService;
+ private Lazy _userService;
+ private Lazy _mediaService;
+ private Lazy _macroService;
+ private Lazy _contentTypeService;
+ private Lazy _dataTypeService;
+ private Lazy _fileService;
+ private Lazy _localizationService;
///
/// Constructor
@@ -28,7 +29,10 @@ namespace Umbraco.Core.Services
///
internal ServiceContext(IDatabaseUnitOfWorkProvider dbUnitOfWorkProvider, IUnitOfWorkProvider fileUnitOfWorkProvider, IPublishingStrategy publishingStrategy)
{
- BuildServiceCache(dbUnitOfWorkProvider, fileUnitOfWorkProvider, publishingStrategy, RepositoryResolver.Current.Factory);
+ BuildServiceCache(dbUnitOfWorkProvider, fileUnitOfWorkProvider, publishingStrategy,
+ //this needs to be lazy because when we create the service context it's generally before the
+ //resolvers have been initialized!
+ new Lazy(() => RepositoryResolver.Current.Factory));
}
///
@@ -38,34 +42,34 @@ namespace Umbraco.Core.Services
IDatabaseUnitOfWorkProvider dbUnitOfWorkProvider,
IUnitOfWorkProvider fileUnitOfWorkProvider,
IPublishingStrategy publishingStrategy,
- RepositoryFactory repositoryFactory)
+ Lazy repositoryFactory)
{
var provider = dbUnitOfWorkProvider;
- var fileProvider = fileUnitOfWorkProvider;
+ var fileProvider = fileUnitOfWorkProvider;
- if(_userService == null)
- _userService = new UserService(provider, repositoryFactory);
+ if (_userService == null)
+ _userService = new Lazy(() => new UserService(provider, repositoryFactory.Value));
if (_contentService == null)
- _contentService = new ContentService(provider, repositoryFactory, publishingStrategy, _userService);
+ _contentService = new Lazy(() => new ContentService(provider, repositoryFactory.Value, publishingStrategy, _userService.Value));
if(_mediaService == null)
- _mediaService = new MediaService(provider, repositoryFactory);
+ _mediaService = new Lazy(() => new MediaService(provider, repositoryFactory.Value));
if(_macroService == null)
- _macroService = new MacroService(fileProvider, repositoryFactory);
+ _macroService = new Lazy(() => new MacroService(fileProvider, repositoryFactory.Value));
if(_contentTypeService == null)
- _contentTypeService = new ContentTypeService(provider, repositoryFactory, _contentService, _mediaService);
+ _contentTypeService = new Lazy(() => new ContentTypeService(provider, repositoryFactory.Value, _contentService.Value, _mediaService.Value));
if(_dataTypeService == null)
- _dataTypeService = new DataTypeService(provider, repositoryFactory);
+ _dataTypeService = new Lazy(() => new DataTypeService(provider, repositoryFactory.Value));
if(_fileService == null)
- _fileService = new FileService(fileProvider, provider, repositoryFactory);
+ _fileService = new Lazy(() => new FileService(fileProvider, provider, repositoryFactory.Value));
if(_localizationService == null)
- _localizationService = new LocalizationService(provider, repositoryFactory);
+ _localizationService = new Lazy(() => new LocalizationService(provider, repositoryFactory.Value));
}
///
@@ -73,7 +77,7 @@ namespace Umbraco.Core.Services
///
public IContentService ContentService
{
- get { return _contentService; }
+ get { return _contentService.Value; }
}
///
@@ -81,7 +85,7 @@ namespace Umbraco.Core.Services
///
public IContentTypeService ContentTypeService
{
- get { return _contentTypeService; }
+ get { return _contentTypeService.Value; }
}
///
@@ -89,7 +93,7 @@ namespace Umbraco.Core.Services
///
public IDataTypeService DataTypeService
{
- get { return _dataTypeService; }
+ get { return _dataTypeService.Value; }
}
///
@@ -97,7 +101,7 @@ namespace Umbraco.Core.Services
///
public IFileService FileService
{
- get { return _fileService; }
+ get { return _fileService.Value; }
}
///
@@ -105,7 +109,7 @@ namespace Umbraco.Core.Services
///
public ILocalizationService LocalizationService
{
- get { return _localizationService; }
+ get { return _localizationService.Value; }
}
///
@@ -113,7 +117,7 @@ namespace Umbraco.Core.Services
///
public IMediaService MediaService
{
- get { return _mediaService; }
+ get { return _mediaService.Value; }
}
///
@@ -121,7 +125,7 @@ namespace Umbraco.Core.Services
///
internal IMacroService MacroService
{
- get { return _macroService; }
+ get { return _macroService.Value; }
}
///
@@ -129,7 +133,7 @@ namespace Umbraco.Core.Services
///
internal IUserService UserService
{
- get { return _userService; }
+ get { return _userService.Value; }
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs
index d04cd84b26..d474752823 100644
--- a/src/Umbraco.Tests/Services/ContentServiceTests.cs
+++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using NUnit.Framework;
+using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
@@ -11,6 +12,8 @@ using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
+using umbraco.editorControls.tinyMCE3;
+using umbraco.interfaces;
namespace Umbraco.Tests.Services
{
@@ -26,17 +29,17 @@ namespace Umbraco.Tests.Services
public override void Initialize()
{
//this ensures its reset
- //PluginManager.Current = new PluginManager();
+ PluginManager.Current = new PluginManager();
//for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
- /*PluginManager.Current.AssembliesToScan = new[]
+ PluginManager.Current.AssembliesToScan = new[]
{
typeof(IDataType).Assembly,
typeof(tinyMCE3dataType).Assembly
};
DataTypesResolver.Current = new DataTypesResolver(
- PluginManager.Current.ResolveDataTypes());*/
+ PluginManager.Current.ResolveDataTypes());
base.Initialize();
@@ -47,8 +50,8 @@ namespace Umbraco.Tests.Services
public override void TearDown()
{
//reset the app context
- //DataTypesResolver.Reset();
- //PluginManager.Current = null;
+ DataTypesResolver.Reset();
+ PluginManager.Current = null;
base.TearDown();
}
diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
index 4644977b5a..f21b02e14a 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.Web.Routing;
using System.Xml;
using NUnit.Framework;
+using SQLCE4Umbraco;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.ObjectResolution;
@@ -74,23 +75,25 @@ namespace Umbraco.Tests.TestHelpers
public virtual void TearDown()
{
DatabaseContext.Database.Dispose();
+ //reset the app context
+ ApplicationContext.ApplicationCache.ClearAllCache();
+
+ //legacy API database connection close
+ SqlCeContextGuardian.CloseBackgroundConnection();
+
+ ApplicationContext.Current = null;
+ Resolution.IsFrozen = false;
+ RepositoryResolver.Reset();
TestHelper.CleanContentDirectories();
-
- //reset the app context
- ApplicationContext.ApplicationCache.ClearAllCache();
- ApplicationContext.Current = null;
- Resolution.IsFrozen = false;
-
- RepositoryResolver.Reset();
-
+
string path = TestHelper.CurrentAssemblyDirectory;
AppDomain.CurrentDomain.SetData("DataDirectory", null);
string filePath = string.Concat(path, "\\UmbracoPetaPocoTests.sdf");
if (File.Exists(filePath))
{
- //File.Delete(filePath);
+ File.Delete(filePath);
}
}