diff --git a/src/Umbraco.Core/Persistence/Caching/IRepositoryCacheProvider.cs b/src/Umbraco.Core/Persistence/Caching/IRepositoryCacheProvider.cs
new file mode 100644
index 0000000000..d65a819871
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Caching/IRepositoryCacheProvider.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using Umbraco.Core.Models.EntityBase;
+
+namespace Umbraco.Core.Persistence.Caching
+{
+ ///
+ /// Defines the implementation of a Cache Provider intented to back a repository
+ ///
+ internal interface IRepositoryCacheProvider
+ {
+ ///
+ /// Gets an Entity from the cache by Type and Id
+ ///
+ ///
+ ///
+ ///
+ IEntity GetById(Type type, Guid id);
+
+ ///
+ /// Gets an Entity from the cache by Type and Ids
+ ///
+ ///
+ ///
+ ///
+ IEnumerable GetByIds(Type type, List ids);
+
+ ///
+ /// Gets all Entities of specified type
+ ///
+ ///
+ ///
+ IEnumerable GetAllByType(Type type);
+
+ ///
+ /// Saves the Entity
+ ///
+ ///
+ ///
+ void Save(Type type, IEntity entity);
+
+ ///
+ /// Deletes the Entity from the cache
+ ///
+ ///
+ ///
+ void Delete(Type type, IEntity entity);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Caching/InMemoryCacheProvider.cs b/src/Umbraco.Core/Persistence/Caching/InMemoryCacheProvider.cs
new file mode 100644
index 0000000000..b6f763fb36
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Caching/InMemoryCacheProvider.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using Umbraco.Core.Models.EntityBase;
+
+namespace Umbraco.Core.Persistence.Caching
+{
+ ///
+ /// The InMemory registry looks up objects in an in-memory dictionary for fast retrival
+ ///
+ internal class InMemoryCacheProvider : IRepositoryCacheProvider
+ {
+ #region Singleton
+ private static volatile InMemoryCacheProvider _instance;
+ private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
+
+ private InMemoryCacheProvider() { }
+
+ public static InMemoryCacheProvider Current
+ {
+ get
+ {
+ using (new WriteLock(Lock))
+ {
+ if (_instance == null) _instance = new InMemoryCacheProvider();
+ }
+
+ return _instance;
+ }
+ }
+ #endregion
+
+ private readonly ConcurrentDictionary _cache = new ConcurrentDictionary();
+
+ ///
+ /// Retrives an object of the specified type by its Id
+ ///
+ /// The type of the object to retrive, which implements
+ /// The Guid Id of the Object to retrive
+ ///
+ public IEntity GetById(Type type, Guid id)
+ {
+ var compositeKey = GetCompositeId(type, id);
+ var containsKey = _cache.ContainsKey(compositeKey);
+ if (containsKey)
+ {
+ return _cache[compositeKey];
+ }
+
+ return null;
+ }
+
+ ///
+ /// Retrives objects of the specified type by their Ids
+ ///
+ /// The type of the objects to retrive, which implements
+ /// The Guid Ids of the Objects to retrive
+ ///
+ public IEnumerable GetByIds(Type type, List ids)
+ {
+ var list = (from id in ids
+ select GetCompositeId(type, id)
+ into key
+ let containsKey = _cache.ContainsKey(key)
+ where containsKey
+ select _cache[key]).ToList();
+ return list;
+ }
+
+ ///
+ /// Retrives all objects of the specified type
+ ///
+ /// The type of the objects to retrive, which implements
+ ///
+ public IEnumerable GetAllByType(Type type)
+ {
+ var list = _cache.Keys.Where(key => key.Contains(type.Name)).Select(key => _cache[key]).ToList();
+ return list;
+ }
+
+ ///
+ /// Saves an object in the registry cache
+ ///
+ ///
+ ///
+ public void Save(Type type, IEntity entity)
+ {
+ _cache.AddOrUpdate(GetCompositeId(type, entity.Key), entity, (x, y) => entity);
+ }
+
+ ///
+ /// Deletes an object from the registry cache
+ ///
+ ///
+ ///
+ public void Delete(Type type, IEntity entity)
+ {
+ IEntity entity1;
+ bool result = _cache.TryRemove(GetCompositeId(type, entity.Key), out entity1);
+ }
+
+ public void Clear()
+ {
+ _cache.Clear();
+ }
+
+ private string GetCompositeId(Type type, Guid id)
+ {
+ return string.Format("{0}-{1}", type.Name, id.ToString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs b/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs
new file mode 100644
index 0000000000..35a735953d
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Runtime.Caching;
+using System.Threading;
+using Umbraco.Core.Models.EntityBase;
+
+namespace Umbraco.Core.Persistence.Caching
+{
+ ///
+ /// The Runtime Cache provider looks up objects in the Runtime cache for fast retrival
+ ///
+ internal sealed class RuntimeCacheProvider : IRepositoryCacheProvider
+ {
+ #region Singleton
+ private static volatile RuntimeCacheProvider _instance;
+ private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
+
+ private RuntimeCacheProvider() { }
+
+ public static RuntimeCacheProvider Current
+ {
+ get
+ {
+ using (new WriteLock(Lock))
+ {
+ if (_instance == null) _instance = new RuntimeCacheProvider();
+ }
+
+ return _instance;
+ }
+ }
+ #endregion
+
+ private ObjectCache _memoryCache = new MemoryCache("in-memory");
+ private ConcurrentDictionary _keyTracker = new ConcurrentDictionary();
+
+ public IEntity GetById(Type type, Guid id)
+ {
+ var key = GetCompositeId(type, id);
+ var item = _memoryCache.Get(key);
+ return item as IEntity;
+ }
+
+ public IEnumerable GetByIds(Type type, List ids)
+ {
+ foreach (var guid in ids)
+ {
+ yield return _memoryCache.Get(GetCompositeId(type, guid)) as IEntity;
+ }
+ }
+
+ public IEnumerable GetAllByType(Type type)
+ {
+ foreach (var key in _keyTracker.Keys)
+ {
+ if (key.StartsWith(type.Name))
+ {
+ yield return _memoryCache.Get(key) as IEntity;
+ }
+ }
+ }
+
+ public void Save(Type type, IEntity entity)
+ {
+ var key = GetCompositeId(type, entity.Key);
+ var exists = _memoryCache.GetCacheItem(key) != null;
+
+ _keyTracker.TryAdd(key, key);
+ if (exists)
+ {
+ _memoryCache.Set(key, entity, new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(5) });
+ return;
+ }
+
+ _memoryCache.Add(key, entity, new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(5) });
+ }
+
+ public void Delete(Type type, IEntity entity)
+ {
+ string throwaway = null;
+ var key = GetCompositeId(type, entity.Key);
+ var keyBeSure = _keyTracker.TryGetValue(key, out throwaway);
+ object itemRemoved = _memoryCache.Remove(key);
+ _keyTracker.TryRemove(key, out throwaway);
+ }
+
+ private string GetCompositeId(Type type, Guid id)
+ {
+ return string.Format("{0}-{1}", type.Name, id.ToString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs
new file mode 100644
index 0000000000..f336f8330c
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Umbraco.Core.Models;
+using Umbraco.Core.Models.Rdbms;
+
+namespace Umbraco.Core.Persistence.Factories
+{
+ internal class ContentFactory
+ {
+ internal static Content CreateContent(int key, IContentType contentType, DocumentDto documentDto, IEnumerable propertyDataDtos)
+ {
+ var properties = new List();
+ foreach (var dto in propertyDataDtos)
+ {
+ var propertyType =
+ contentType.CompositionPropertyTypes.FirstOrDefault(x => x.Id == dto.PropertyTypeId);
+ properties.Add(propertyType.CreatePropertyFromRawValue(dto.GetValue));
+ }
+
+ return new Content(documentDto.ContentVersionDto.ContentDto.NodeDto.ParentId, contentType)
+ {
+ Id = key,
+ Key = documentDto.ContentVersionDto.ContentDto.NodeDto.UniqueId.HasValue ? documentDto.ContentVersionDto.ContentDto.NodeDto.UniqueId.Value : key.ToGuid(),
+ Name = documentDto.ContentVersionDto.ContentDto.NodeDto.Text,
+ Path = documentDto.ContentVersionDto.ContentDto.NodeDto.Path,
+ UserId = documentDto.ContentVersionDto.ContentDto.NodeDto.UserId.HasValue ? documentDto.ContentVersionDto.ContentDto.NodeDto.UserId.Value : documentDto.UserId,
+ Level = documentDto.ContentVersionDto.ContentDto.NodeDto.Level,
+ ParentId = documentDto.ContentVersionDto.ContentDto.NodeDto.ParentId,
+ SortOrder = documentDto.ContentVersionDto.ContentDto.NodeDto.SortOrder,
+ Trashed = documentDto.ContentVersionDto.ContentDto.NodeDto.Trashed,
+ Published = documentDto.Published,
+ CreatedDate = documentDto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
+ ModifiedDate = documentDto.ContentVersionDto.VersionDate,
+ ExpireDate = documentDto.ExpiresDate,
+ ReleaseDate = documentDto.ReleaseDate,
+ Version = documentDto.ContentVersionDto.VersionId,
+ Properties = new PropertyCollection(properties)
+ };
+ }
+
+ internal static NodeDto CreateNodeDto(IContent entity, string nodeObjectType)
+ {
+ var nodeDto = new NodeDto
+ {
+ CreateDate = entity.CreatedDate,
+ NodeId = entity.Id,
+ Level = short.Parse(entity.Level.ToString(CultureInfo.InvariantCulture)),
+ NodeObjectType = new Guid(nodeObjectType),
+ ParentId = entity.ParentId,
+ Path = entity.Path,
+ SortOrder = entity.SortOrder,
+ Text = entity.Name,
+ Trashed = entity.Trashed,
+ UniqueId = entity.Key,
+ UserId = entity.UserId
+ };
+
+ return nodeDto;
+ }
+
+ internal static NodeDto CreateNodeDto(IContent entity, string nodeObjectType, string path, int level, int sortOrder)
+ {
+ var nodeDto = new NodeDto
+ {
+ CreateDate = entity.CreatedDate,
+ NodeId = entity.Id,
+ Level = short.Parse(level.ToString(CultureInfo.InvariantCulture)),
+ NodeObjectType = new Guid(nodeObjectType),
+ ParentId = entity.ParentId,
+ Path = path,
+ SortOrder = sortOrder,
+ Text = entity.Name,
+ Trashed = entity.Trashed,
+ UniqueId = entity.Key,
+ UserId = entity.UserId
+ };
+
+ return nodeDto;
+ }
+
+ internal static ContentDto CreateContentDto(IContent entity, int primaryKey = 0)
+ {
+ var contentDto = new ContentDto
+ {
+ NodeId = entity.Id,
+ ContentType = entity.ContentTypeId
+ };
+
+ if (primaryKey > 0)
+ {
+ contentDto.PrimaryKey = primaryKey;
+ }
+
+ return contentDto;
+ }
+
+ internal static ContentVersionDto CreateContentVersionDto(IContent entity)
+ {
+ var contentVersionDto = new ContentVersionDto
+ {
+ NodeId = entity.Id,
+ VersionDate = entity.ModifiedDate,
+ VersionId = entity.Version
+ };
+ return contentVersionDto;
+ }
+
+ internal static DocumentDto CreateDocumentDto(IContent entity)
+ {
+ //NOTE Currently doesn't add Alias and templateId (legacy stuff that eventually will go away)
+ var documentDto = new DocumentDto
+ {
+ ExpiresDate = entity.ExpireDate,
+ Newest = true,
+ NodeId = entity.Id,
+ Published = entity.Published,
+ ReleaseDate = entity.ReleaseDate,
+ Text = entity.Name,
+ UpdateDate = entity.ModifiedDate,
+ UserId = entity.UserId,
+ VersionId = entity.Version
+ };
+ return documentDto;
+ }
+
+ internal static List CreateProperties(int id, Guid version, IEnumerable properties)
+ {
+ var propertyDataDtos = new List();
+ /*var serviceStackSerializer = new ServiceStackXmlSerializer();
+ var service = new SerializationService(serviceStackSerializer);*/
+
+ foreach (var property in properties)
+ {
+ var dto = new PropertyDataDto { NodeId = id, PropertyTypeId = property.PropertyTypeId, VersionId = version };
+ /*if (property.Value is IEditorModel)
+ {
+ var result = service.ToStream(property.Value);
+ dto.Text = result.ResultStream.ToJsonString();
+ }*/
+ if (property.Value is int)
+ {
+ dto.Integer = int.Parse(property.Value.ToString());
+ }
+ else if (property.Value is DateTime)
+ {
+ dto.Date = DateTime.Parse(property.Value.ToString());
+ }
+ else if (property.Value is string)
+ {
+ dto.Text = property.Value.ToString();
+ }
+ else if (property.Value != null)
+ {
+ dto.VarChar = property.Value.ToString();//TODO Check how/when NVarChar is actually set/used
+ }
+
+ propertyDataDtos.Add(dto);
+ }
+ return propertyDataDtos;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Mappers/ModelDtoMapper.cs b/src/Umbraco.Core/Persistence/Mappers/ModelDtoMapper.cs
new file mode 100644
index 0000000000..d2ac50c91e
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Mappers/ModelDtoMapper.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Reflection;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Core.Persistence.Mappers
+{
+ internal class ModelDtoMapper : IMapper
+ {
+ public void GetTableInfo(Type t, TableInfo ti)
+ { }
+
+ public bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn)
+ {
+ if (pi.DeclaringType == typeof(Content) || pi.DeclaringType == typeof(IContent))
+ {
+ switch (pi.Name)
+ {
+ case "Trashed":
+ columnName = "[umbracoNode].[trashed]";
+ return true;
+ case "ParentId":
+ columnName = "[umbracoNode].[parentID]";
+ return true;
+ case "UserId":
+ columnName = "[umbracoNode].[nodeUser]";
+ return true;
+ case "Level":
+ columnName = "[umbracoNode].[level]";
+ return true;
+ case "Path":
+ columnName = "[umbracoNode].[path]";
+ return true;
+ case "SortOrder":
+ columnName = "[umbracoNode].[sortOrder]";
+ return true;
+ case "NodeId":
+ columnName = "[umbracoNode].[id]";
+ return true;
+ case "Published":
+ columnName = "[cmsDocument].[published]";
+ return true;
+ case "Key":
+ columnName = "[umbracoNode].[uniqueID]";
+ return true;
+ case "CreatedDate":
+ columnName = "[umbracoNode].[createDate]";
+ return true;
+ case "Name":
+ columnName = "[umbracoNode].[text]";
+ return true;
+ }
+ }
+
+ if (pi.DeclaringType == typeof(ContentType) || pi.DeclaringType == typeof(IContentType))
+ {
+ switch (pi.Name)
+ {
+ case "Alias":
+ columnName = "[cmsContentType].[alias]";
+ return true;
+ case "Icon":
+ columnName = "[cmsContentType].[icon]";
+ return true;
+ case "Thumbnail":
+ columnName = "[cmsContentType].[thumbnail]";
+ return true;
+ case "Description":
+ columnName = "[cmsContentType].[description]";
+ return true;
+ }
+ }
+
+ return true;
+ }
+
+ public Func