Merge remote-tracking branch 'origin/7.1.2' into 7.1.2

This commit is contained in:
Stephan
2014-04-19 14:21:24 +02:00
81 changed files with 4052 additions and 739 deletions

View File

@@ -53,5 +53,6 @@ namespace Umbraco.Core.Cache
public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty";
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
public const string DataTypePreValuesCacheKey = "UmbracoPreVal";
}
}

View File

@@ -41,6 +41,12 @@ namespace Umbraco.Core.Cache
return result.Select(x => x.TryConvertTo<T>().Result);
}
public static IEnumerable<T> GetCacheItemsByKeyExpression<T>(this ICacheProvider provider, string regexString)
{
var result = provider.GetCacheItemsByKeyExpression(regexString);
return result.Select(x => x.TryConvertTo<T>().Result);
}
public static T GetCacheItem<T>(this ICacheProvider provider, string cacheKey)
{
var result = provider.GetCacheItem(cacheKey);

View File

@@ -171,6 +171,26 @@ namespace Umbraco.Core.Cache
select c.Value).ToList();
}
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
{
var found = new List<object>();
foreach (var item in DictionaryCache)
{
var c = new DictionaryItemWrapper(item);
var s = c.Key as string;
if (s != null)
{
var withoutPrefix = s.TrimStart(string.Format("{0}-", CacheItemPrefix));
if (Regex.IsMatch(withoutPrefix, regexString))
{
found.Add(c.Value);
}
}
}
return found;
}
/// <summary>
/// Returns a cache item by key, does not update the cache if it isn't there.
/// </summary>

View File

@@ -16,7 +16,15 @@ namespace Umbraco.Core.Cache
void ClearCacheByKeySearch(string keyStartsWith);
void ClearCacheByKeyExpression(string regexString);
IEnumerable<object> GetCacheItemsByKeySearch(string keyStartsWith);
IEnumerable<object> GetCacheItemsByKeyExpression(string regexString);
/// <summary>
/// Returns an item with a given key
/// </summary>
/// <param name="cacheKey"></param>
/// <returns></returns>
object GetCacheItem(string cacheKey);
object GetCacheItem(string cacheKey, Func<object> getCacheItem);
}
}

View File

@@ -43,6 +43,11 @@ namespace Umbraco.Core.Cache
return Enumerable.Empty<object>();
}
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
{
return Enumerable.Empty<object>();
}
public virtual object GetCacheItem(string cacheKey)
{
return default(object);

View File

@@ -114,6 +114,13 @@ namespace Umbraco.Core.Cache
select c.Value).ToList();
}
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
{
return (from c in MemoryCache
where Regex.IsMatch(c.Key, regexString)
select c.Value).ToList();
}
public virtual object GetCacheItem(string cacheKey)
{
var result = MemoryCache.Get(cacheKey);

View File

@@ -59,6 +59,13 @@ namespace Umbraco.Core.Cache
select c.Value).ToList();
}
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
{
return (from KeyValuePair<string, object> c in StaticCache
where Regex.IsMatch(c.Key, regexString)
select c.Value).ToList();
}
public virtual object GetCacheItem(string cacheKey)
{
var result = StaticCache[cacheKey];

View File

@@ -149,7 +149,14 @@ namespace Umbraco.Core
/// <param name="connectionString"></param>
public void ConfigureDatabaseConnection(string connectionString)
{
SaveConnectionString(connectionString, string.Empty);
var provider = DbConnectionExtensions.DetectProviderFromConnectionString(connectionString);
var databaseProvider = provider.ToString();
var providerName = "System.Data.SqlClient";
if (databaseProvider.ToLower().Contains("mysql"))
{
providerName = "MySql.Data.MySqlClient";
}
SaveConnectionString(connectionString, providerName);
Initialize(string.Empty);
}
@@ -169,7 +176,7 @@ namespace Umbraco.Core
SaveConnectionString(connectionString, providerName);
Initialize(providerName);
}
public string GetDatabaseConnectionString(string server, string databaseName, string user, string password, string databaseProvider, out string providerName)
{
providerName = "System.Data.SqlClient";

View File

@@ -36,42 +36,22 @@ namespace Umbraco.Core.Dynamics
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
if (!string.IsNullOrEmpty(haystack) || needles.Any())
{
return needles.Any(haystack.Contains);
}
return false;
return StringExtensions.ContainsAny(haystack, needles);
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, params string[] needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
if (!string.IsNullOrEmpty(haystack) || needles.Length > 0)
{
return needles.Any(haystack.Contains);
}
return false;
return StringExtensions.ContainsAny(haystack, needles);
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, StringComparison comparison, IEnumerable<string> needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
if (!string.IsNullOrEmpty(haystack) || needles.Any())
{
return needles.Any(value => haystack.IndexOf(value, comparison) >= 0);
}
return false;
return StringExtensions.ContainsAny(haystack, needles, comparison);
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, StringComparison comparison, params string[] needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
if (!string.IsNullOrEmpty(haystack) || needles.Length > 0)
{
return needles.Any(value => haystack.IndexOf(value, comparison) >= 0);
}
return false;
return StringExtensions.ContainsAny(haystack, needles, comparison);
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsInsensitive(this string haystack, string needle)

View File

@@ -232,6 +232,7 @@ namespace Umbraco.Core.Models
/// <remarks>
/// This Property is kept internal until localization is introduced.
/// </remarks>
[DataMember]
internal string NodeName
{
get { return _nodeName; }
@@ -248,6 +249,7 @@ namespace Umbraco.Core.Models
/// <summary>
/// Used internally to track if permissions have been changed during the saving process for this entity
/// </summary>
[IgnoreDataMember]
internal bool PermissionsChanged
{
get { return _permissionsChanged; }
@@ -314,6 +316,7 @@ namespace Umbraco.Core.Models
PublishedState = state;
}
[DataMember]
internal PublishedState PublishedState { get; set; }
/// <summary>
@@ -333,26 +336,6 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Creates a clone of the current entity
/// </summary>
/// <returns></returns>
public IContent Clone()
{
var clone = (Content)this.MemberwiseClone();
clone.Key = Guid.Empty;
clone.Version = Guid.NewGuid();
clone.ResetIdentity();
foreach (var property in clone.Properties)
{
property.ResetIdentity();
property.Version = clone.Version;
}
return clone;
}
/// <summary>
/// Indicates whether a specific property on the current <see cref="IContent"/> entity is dirty.
/// </summary>
@@ -432,5 +415,37 @@ namespace Umbraco.Core.Models
base.UpdatingEntity();
Version = Guid.NewGuid();
}
/// <summary>
/// Creates a deep clone of the current entity with its identity and it's property identities reset
/// </summary>
/// <returns></returns>
public IContent Clone()
{
var clone = (Content)DeepClone();
clone.Key = Guid.Empty;
clone.Version = Guid.NewGuid();
clone.ResetIdentity();
foreach (var property in clone.Properties)
{
property.ResetIdentity();
property.Version = clone.Version;
}
return clone;
}
public override object DeepClone()
{
var clone = (Content)base.DeepClone();
//need to manually clone this since it's not settable
clone._contentType = (IContentType)ContentType.DeepClone();
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -15,10 +15,13 @@ namespace Umbraco.Core.Models
/// <summary>
/// Represents an abstract class for base Content properties and methods
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
[DebuggerDisplay("Id: {Id}, Name: {Name}, ContentType: {ContentTypeBase.Alias}")]
public abstract class ContentBase : Entity, IContentBase
{
protected IContentTypeComposition ContentTypeBase;
private Lazy<int> _parentId;
private string _name;//NOTE Once localization is introduced this will be the localized Name of the Content/Media.
private int _sortOrder;
@@ -257,6 +260,7 @@ namespace Umbraco.Core.Models
}
private readonly IDictionary<string, object> _additionalData;
/// <summary>
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
/// </summary>
@@ -445,6 +449,7 @@ namespace Umbraco.Core.Models
/// <summary>
/// Returns a collection of the result of the last validation process, this collection contains all invalid properties.
/// </summary>
[IgnoreDataMember]
internal IEnumerable<Property> LastInvalidProperties
{
get { return _lastInvalidProperties; }
@@ -466,5 +471,6 @@ namespace Umbraco.Core.Models
prop.ResetDirtyProperties(rememberPreviouslyChangedProperties);
}
}
}
}

View File

@@ -122,6 +122,28 @@ namespace Umbraco.Core.Models
}
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
/// <remarks>Created date is set and a Unique key is assigned</remarks>
internal override void AddingEntity()
{
base.AddingEntity();
if(Key == Guid.Empty)
Key = Guid.NewGuid();
}
/// <summary>
/// Method to call when Entity is being updated
/// </summary>
/// <remarks>Modified Date is set and a new Version guid is set</remarks>
internal override void UpdatingEntity()
{
base.UpdatingEntity();
}
/// <summary>
/// //TODO: REmove this as it's mostly just a shallow clone and not thread safe
/// Creates a clone of the current entity
/// </summary>
/// <returns></returns>
@@ -153,25 +175,5 @@ namespace Umbraco.Core.Models
return clone;
}
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
/// <remarks>Created date is set and a Unique key is assigned</remarks>
internal override void AddingEntity()
{
base.AddingEntity();
if(Key == Guid.Empty)
Key = Guid.NewGuid();
}
/// <summary>
/// Method to call when Entity is being updated
/// </summary>
/// <remarks>Modified Date is set and a new Version guid is set</remarks>
internal override void UpdatingEntity()
{
base.UpdatingEntity();
}
}
}

View File

@@ -319,7 +319,7 @@ namespace Umbraco.Core.Models
}
}
private readonly IDictionary<string, object> _additionalData;
private IDictionary<string, object> _additionalData;
/// <summary>
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
/// </summary>

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition
{
private readonly List<IContentTypeComposition> _contentTypeComposition = new List<IContentTypeComposition>();
private List<IContentTypeComposition> _contentTypeComposition = new List<IContentTypeComposition>();
internal List<int> RemovedContentTypeKeyTracker = new List<int>();
protected ContentTypeCompositionBase(int parentId) : base(parentId)
@@ -217,5 +217,17 @@ namespace Umbraco.Core.Models
.Select(x => x.Id)
.Union(ContentTypeComposition.SelectMany(x => x.CompositionIds()));
}
public override object DeepClone()
{
var clone = (ContentTypeCompositionBase)base.DeepClone();
//need to manually assign since this is an internal field and will not be automatically mapped
clone.RemovedContentTypeKeyTracker = new List<int>();
clone._contentTypeComposition = ContentTypeComposition.Select(x => (IContentTypeComposition)x.DeepClone()).ToList();
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -6,7 +6,7 @@ namespace Umbraco.Core.Models
/// <summary>
/// Represents a POCO for setting sort order on a ContentType reference
/// </summary>
public class ContentTypeSort : IValueObject
public class ContentTypeSort : IValueObject, IDeepCloneable
{
public ContentTypeSort()
{
@@ -33,5 +33,36 @@ namespace Umbraco.Core.Models
/// Gets or sets the Alias of the ContentType
/// </summary>
public string Alias { get; set; }
public object DeepClone()
{
var clone = (ContentTypeSort)MemberwiseClone();
var id = Id.Value;
clone.Id = new Lazy<int>(() => id);
return clone;
}
protected bool Equals(ContentTypeSort other)
{
return Id.Value.Equals(other.Id.Value) && string.Equals(Alias, other.Alias);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ContentTypeSort) obj);
}
public override int GetHashCode()
{
unchecked
{
return (Id.GetHashCode()*397) ^ Alias.GetHashCode();
}
}
}
}

View File

@@ -0,0 +1,144 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models
{
public static class DeepCloneHelper
{
/// <summary>
/// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output')
/// </summary>
/// <param name="input"></param>
/// <param name="output"></param>
/// <returns></returns>
public static void DeepCloneRefProperties(IDeepCloneable input, IDeepCloneable output)
{
var inputType = input.GetType();
var outputType = output.GetType();
if (inputType != outputType)
{
throw new InvalidOperationException("Both the input and output types must be the same");
}
var refProperties = inputType.GetProperties()
.Where(x =>
//reference type but not string
x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
//settable
&& x.CanWrite
//non-indexed
&& x.GetIndexParameters().Any() == false);
foreach (var propertyInfo in refProperties)
{
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
{
//this ref property is also deep cloneable so clone it
var result = (IDeepCloneable)propertyInfo.GetValue(input, null);
if (result != null)
{
//set the cloned value to the property
propertyInfo.SetValue(output, result.DeepClone(), null);
}
}
else if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
{
IList newList;
if (propertyInfo.PropertyType.IsGenericType
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
newList = (IList)Activator.CreateInstance(genericType);
}
else if (propertyInfo.PropertyType.IsArray
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
{
//if its an array, we'll create a list to work with first and then convert to array later
//otherwise if its just a regular derivitave of IEnumerable, we can use a list too
newList = new List<object>();
}
else
{
//its a custom IEnumerable, we'll try to create it
try
{
var custom = Activator.CreateInstance(propertyInfo.PropertyType);
//if it's an IList we can work with it, otherwise we cannot
newList = custom as IList;
if (newList == null)
{
continue;
}
}
catch (Exception)
{
//could not create this type so we'll skip it
continue;
}
}
var enumerable = (IEnumerable)propertyInfo.GetValue(input, null);
if (enumerable == null) continue;
var isUsableType = true;
//now clone each item
foreach (var o in enumerable)
{
//first check if the item is deep cloneable and copy that way
var dc = o as IDeepCloneable;
if (dc != null)
{
newList.Add(dc.DeepClone());
}
else if (o is string || o.GetType().IsValueType)
{
//check if the item is a value type or a string, then we can just use it
newList.Add(o);
}
else
{
//this will occur if the item is not a string or value type or IDeepCloneable, in this case we cannot
// clone each element, we'll need to skip this property, people will have to manually clone this list
isUsableType = false;
break;
}
}
//if this was not usable, skip this property
if (isUsableType == false)
{
continue;
}
if (propertyInfo.PropertyType.IsArray)
{
//need to convert to array
var arr = (object[])Activator.CreateInstance(propertyInfo.PropertyType, newList.Count);
for (int i = 0; i < newList.Count; i++)
{
arr[i] = newList[i];
}
//set the cloned collection
propertyInfo.SetValue(output, arr, null);
}
else
{
//set the cloned collection
propertyInfo.SetValue(output, newList, null);
}
}
}
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
@@ -96,5 +97,6 @@ namespace Umbraco.Core.Models
if(ParentId == Guid.Empty)
_parentId = new Guid("41c7638d-f529-4bff-853e-59a0c2fb1bde");
}
}
}

View File

@@ -65,5 +65,6 @@ namespace Umbraco.Core.Models
}, _value, ValueSelector);
}
}
}
}

View File

@@ -1,7 +1,10 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace Umbraco.Core.Models.EntityBase
{
@@ -93,7 +96,7 @@ namespace Umbraco.Core.Models.EntityBase
}
/// <summary>
/// /// Gets or sets the WasCancelled flag, which is used to track
/// Gets or sets the WasCancelled flag, which is used to track
/// whether some action against an entity was cancelled through some event.
/// This only exists so we have a way to check if an event was cancelled through
/// the new api, which also needs to take effect in the legacy api.
@@ -155,6 +158,7 @@ namespace Umbraco.Core.Models.EntityBase
/// <summary>
/// Indicates whether the current entity has an identity, eg. Id.
/// </summary>
[DataMember]
public virtual bool HasIdentity
{
get
@@ -226,5 +230,62 @@ namespace Umbraco.Core.Models.EntityBase
_hash = !HasIdentity ? new int?(base.GetHashCode()) : new int?(Id.GetHashCode() * 397 ^ GetType().GetHashCode());
return _hash.Value;
}
public virtual object DeepClone()
{
//Memberwise clone on Entity will work since it doesn't have any deep elements
// for any sub class this will work for standard properties as well that aren't complex object's themselves.
var clone = (Entity)MemberwiseClone();
//Automatically deep clone ref properties that are IDeepCloneable
DeepCloneHelper.DeepCloneRefProperties(this, clone);
clone.ResetDirtyProperties(false);
return clone;
//Using data contract serializer - has issues
//var s = Serialize(this);
//var d = Deserialize(s, this.GetType());
//return d;
//Using binary serializer - has issues
//using (var memoryStream = new MemoryStream(10))
//{
//IFormatter formatter = new BinaryFormatter();
//formatter.Serialize(memoryStream, this);
//memoryStream.Seek(0, SeekOrigin.Begin);
//return formatter.Deserialize(memoryStream);
//}
}
// serialize/deserialize with data contracts:
//public static string Serialize(object obj)
//{
// using (var memoryStream = new MemoryStream())
// using (var reader = new StreamReader(memoryStream))
// {
// var serializer = new DataContractSerializer(obj.GetType());
// serializer.WriteObject(memoryStream, obj);
// memoryStream.Position = 0;
// return reader.ReadToEnd();
// }
//}
//public static object Deserialize(string xml, Type toType)
//{
// using (Stream stream = new MemoryStream())
// {
// using (var writer = new StreamWriter(stream, Encoding.UTF8))
// {
// writer.Write(xml);
// //byte[] data = Encoding.UTF8.GetBytes(xml);
// //stream.Write(data, 0, data.Length);
// stream.Position = 0;
// var deserializer = new DataContractSerializer(toType);
// return deserializer.ReadObject(stream);
// }
// }
//}
}
}

View File

@@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.EntityBase
/// </summary>
/// <remarks>The current database schema doesn't provide a modified date
/// for all entities, so this will have to be changed at a later stage.</remarks>
public interface IEntity
public interface IEntity : IDeepCloneable
{
/// <summary>
/// The Id of the entity

View File

@@ -3,12 +3,15 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
namespace Umbraco.Core.Models.EntityBase
{
/// <summary>
/// A base class for use to implement IRememberBeingDirty/ICanBeDirty
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
public abstract class TracksChangesEntityBase : IRememberBeingDirty
{
/// <summary>

View File

@@ -6,16 +6,6 @@ using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
internal sealed class Folder : Entity
{
public Folder(string folderPath)
{
Path = folderPath;
}
public string Path { get; set; }
}
/// <summary>
/// Represents an abstract file which provides basic functionality for a File with an Alias and Name
/// </summary>
@@ -114,5 +104,18 @@ namespace Umbraco.Core.Models
/// </summary>
/// <returns>True if file is valid, otherwise false</returns>
public abstract bool IsValid();
public override object DeepClone()
{
var clone = (File)base.DeepClone();
//need to manually assign since they are readonly properties
clone._alias = Alias;
clone._name = Name;
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -0,0 +1,14 @@
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
internal sealed class Folder : Entity
{
public Folder(string folderPath)
{
Path = folderPath;
}
public string Path { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
using System.Reflection;
namespace Umbraco.Core.Models
{
public interface IDeepCloneable
{
object DeepClone();
}
}

View File

@@ -14,7 +14,7 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class Member : ContentBase, IMember
{
private readonly IMemberType _contentType;
private IMemberType _contentType;
private readonly string _contentTypeAlias;
private string _username;
private string _email;
@@ -153,7 +153,7 @@ namespace Umbraco.Core.Models
/// <summary>
/// Gets or sets the raw password value
/// </summary>
[DataMember]
[IgnoreDataMember]
public string RawPasswordValue
{
get { return _rawPasswordValue; }
@@ -184,7 +184,7 @@ namespace Umbraco.Core.Models
/// Alias: umbracoMemberPasswordRetrievalQuestion
/// Part of the standard properties collection.
/// </remarks>
[IgnoreDataMember]
[DataMember]
public string PasswordQuestion
{
get
@@ -244,7 +244,7 @@ namespace Umbraco.Core.Models
/// Alias: umbracoMemberComments
/// Part of the standard properties collection.
/// </remarks>
[IgnoreDataMember]
[DataMember]
public string Comments
{
get
@@ -273,7 +273,7 @@ namespace Umbraco.Core.Models
/// Alias: umbracoMemberApproved
/// Part of the standard properties collection.
/// </remarks>
[IgnoreDataMember]
[DataMember]
public bool IsApproved
{
get
@@ -308,7 +308,7 @@ namespace Umbraco.Core.Models
/// Alias: umbracoMemberLockedOut
/// Part of the standard properties collection.
/// </remarks>
[IgnoreDataMember]
[DataMember]
public bool IsLockedOut
{
get
@@ -341,7 +341,7 @@ namespace Umbraco.Core.Models
/// Alias: umbracoMemberLastLogin
/// Part of the standard properties collection.
/// </remarks>
[IgnoreDataMember]
[DataMember]
public DateTime LastLoginDate
{
get
@@ -374,7 +374,7 @@ namespace Umbraco.Core.Models
/// Alias: umbracoMemberLastPasswordChangeDate
/// Part of the standard properties collection.
/// </remarks>
[IgnoreDataMember]
[DataMember]
public DateTime LastPasswordChangeDate
{
get
@@ -407,7 +407,7 @@ namespace Umbraco.Core.Models
/// Alias: umbracoMemberLastLockoutDate
/// Part of the standard properties collection.
/// </remarks>
[IgnoreDataMember]
[DataMember]
public DateTime LastLockoutDate
{
get
@@ -441,7 +441,7 @@ namespace Umbraco.Core.Models
/// Alias: umbracoMemberFailedPasswordAttempts
/// Part of the standard properties collection.
/// </remarks>
[IgnoreDataMember]
[DataMember]
public int FailedPasswordAttempts
{
get
@@ -563,11 +563,17 @@ namespace Umbraco.Core.Models
/* Internal experiment - only used for mapping queries.
* Adding these to have first level properties instead of the Properties collection.
*/
[IgnoreDataMember]
internal string LongStringPropertyValue { get; set; }
[IgnoreDataMember]
internal string ShortStringPropertyValue { get; set; }
[IgnoreDataMember]
internal int IntegerropertyValue { get; set; }
[IgnoreDataMember]
internal bool BoolPropertyValue { get; set; }
[IgnoreDataMember]
internal DateTime DateTimePropertyValue { get; set; }
[IgnoreDataMember]
internal string PropertyTypeAlias { get; set; }
private Attempt<T> WarnIfPropertyTypeNotFoundOnGet<T>(string propertyAlias, string propertyName, T defaultVal)
@@ -637,5 +643,17 @@ namespace Umbraco.Core.Models
return true;
}
public override object DeepClone()
{
var clone = (Member)base.DeepClone();
//need to manually clone this since it's not settable
clone._contentType = (IMemberType)ContentType.DeepClone();
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -7,7 +7,7 @@ using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
namespace Umbraco.Core.Models.Membership
{
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Models.Membership
/// </remarks>
[Serializable]
[DataContract(IsReference = true)]
public class User : TracksChangesEntityBase, IUser
public class User : Entity, IUser
{
public User(IUserType userType)
{
@@ -57,8 +57,6 @@ namespace Umbraco.Core.Models.Membership
}
private IUserType _userType;
private bool _hasIdentity;
private int _id;
private string _name;
private Type _userTypeKey;
private readonly List<string> _addedSections;
@@ -81,7 +79,6 @@ namespace Umbraco.Core.Models.Membership
private static readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartContentId);
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.AllowedSections);
private static readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo<User, object>(x => x.Id);
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Name);
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<User, Type>(x => x.ProviderUserKeyType);
@@ -93,52 +90,8 @@ namespace Umbraco.Core.Models.Membership
private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Language);
private static readonly PropertyInfo DefaultPermissionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.DefaultPermissions);
private static readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.DefaultToLiveEditing);
private static readonly PropertyInfo HasIdentitySelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.HasIdentity);
private static readonly PropertyInfo UserTypeSelector = ExpressionHelper.GetPropertyInfo<User, IUserType>(x => x.UserType);
#region Implementation of IEntity
[IgnoreDataMember]
public bool HasIdentity
{
get
{
return _hasIdentity;
}
protected set
{
SetPropertyValueAndDetectChanges(o =>
{
_hasIdentity = value;
return _hasIdentity;
}, _hasIdentity, HasIdentitySelector);
}
}
[DataMember]
public int Id
{
get
{
return _id;
}
set
{
SetPropertyValueAndDetectChanges(o =>
{
_id = value;
HasIdentity = true; //set the has Identity
return _id;
}, _id, IdSelector);
}
}
//this doesn't get used
[IgnoreDataMember]
public Guid Key { get; set; }
#endregion
#region Implementation of IMembershipUser
[IgnoreDataMember]
@@ -256,11 +209,7 @@ namespace Umbraco.Core.Models.Membership
[IgnoreDataMember]
public string RawPasswordAnswerValue { get; set; }
[IgnoreDataMember]
public string Comments { get; set; }
[IgnoreDataMember]
public DateTime CreateDate { get; set; }
[IgnoreDataMember]
public DateTime UpdateDate { get; set; }
public string Comments { get; set; }
[IgnoreDataMember]
public DateTime LastLoginDate { get; set; }
[IgnoreDataMember]
@@ -491,7 +440,7 @@ namespace Umbraco.Core.Models.Membership
_removedSections.Add(e.OldItems.Cast<string>().First());
}
}
/// <summary>
/// Internal class used to wrap the user in a profile
/// </summary>
@@ -515,6 +464,24 @@ namespace Umbraco.Core.Models.Membership
get { return _user.Name; }
set { _user.Name = value; }
}
protected bool Equals(UserProfile other)
{
return _user.Equals(other._user);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((UserProfile) obj);
}
public override int GetHashCode()
{
return _user.GetHashCode();
}
}
}
}

View File

@@ -26,7 +26,7 @@
/// <summary>
/// The value stored for the pre-value field
/// </summary>
public string Value { get; private set; }
public string Value { get; set; }
/// <summary>
/// The database id for the pre-value field value

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class Property : Entity
{
private readonly PropertyType _propertyType;
private PropertyType _propertyType;
private Guid _version;
private object _value;
private readonly PropertyTags _tagSupport = new PropertyTags();
@@ -156,5 +156,16 @@ namespace Umbraco.Core.Models
{
return _propertyType.IsPropertyValueValid(value);
}
public override object DeepClone()
{
var clone = (Property)base.DeepClone();
//need to manually assign since this is a readonly property
clone._propertyType = (PropertyType)PropertyType.DeepClone();
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Collections.Specialized;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
@@ -13,7 +14,7 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
public class PropertyCollection : KeyedCollection<string, Property>, INotifyCollectionChanged
public class PropertyCollection : KeyedCollection<string, Property>, INotifyCollectionChanged, IDeepCloneable
{
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
internal Action OnAdd;
@@ -195,5 +196,19 @@ namespace Umbraco.Core.Models
}
}
}
/// <summary>
/// Create a deep clone of this property collection
/// </summary>
/// <returns></returns>
public object DeepClone()
{
var newList = new PropertyCollection();
foreach (var p in this)
{
newList.Add((Property)p.DeepClone());
}
return newList;
}
}
}

View File

@@ -109,23 +109,6 @@ namespace Umbraco.Core.Models
}
}
internal PropertyGroup Clone()
{
var clone = (PropertyGroup) this.MemberwiseClone();
var collection = new PropertyTypeCollection();
foreach (var propertyType in this.PropertyTypes)
{
var property = propertyType.Clone();
property.ResetIdentity();
property.ResetDirtyProperties(false);
collection.Add(property);
}
clone.PropertyTypes = collection;
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;
}
/// <summary>
/// Sets the ParentId from the lazy integer id
/// </summary>
@@ -159,5 +142,24 @@ namespace Umbraco.Core.Models
//Calculate the hash code for the product.
return hashName ^ hashId;
}
//TODO: Remove this, its mostly a shallow clone and is not thread safe
internal PropertyGroup Clone()
{
var clone = (PropertyGroup)this.MemberwiseClone();
var collection = new PropertyTypeCollection();
foreach (var propertyType in this.PropertyTypes)
{
var property = propertyType.Clone();
property.ResetIdentity();
property.ResetDirtyProperties(false);
collection.Add(property);
}
clone.PropertyTypes = collection;
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Collections.Specialized;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
@@ -13,9 +14,10 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract]
public class PropertyGroupCollection : KeyedCollection<string, PropertyGroup>, INotifyCollectionChanged
public class PropertyGroupCollection : KeyedCollection<string, PropertyGroup>, INotifyCollectionChanged, IDeepCloneable
{
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
internal Action OnAdd;
internal PropertyGroupCollection()
@@ -131,5 +133,15 @@ namespace Umbraco.Core.Models
CollectionChanged(this, args);
}
}
public object DeepClone()
{
var newGroup = new PropertyGroupCollection();
foreach (var p in this)
{
newGroup.Add((PropertyGroup)p.DeepClone());
}
return newGroup;
}
}
}

View File

@@ -419,14 +419,6 @@ namespace Umbraco.Core.Models
return true;
}
internal PropertyType Clone()
{
var clone = (PropertyType) MemberwiseClone();
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;
}
public bool Equals(PropertyType other)
{
//Check whether the compared object is null.
@@ -450,5 +442,30 @@ namespace Umbraco.Core.Models
//Calculate the hash code for the product.
return hashName ^ hashAlias;
}
//TODO: Remove this
internal PropertyType Clone()
{
var clone = (PropertyType)this.MemberwiseClone();
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;
}
public override object DeepClone()
{
var clone = (PropertyType)base.DeepClone();
//need to manually assign the Lazy value as it will not be automatically mapped
if (PropertyGroupId != null)
{
var propGroupId = PropertyGroupId.Value;
clone._propertyGroupId = new Lazy<int>(() => propGroupId);
}
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Collections.Specialized;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
@@ -13,9 +14,12 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract]
public class PropertyTypeCollection : KeyedCollection<string, PropertyType>, INotifyCollectionChanged
public class PropertyTypeCollection : KeyedCollection<string, PropertyType>, INotifyCollectionChanged, IDeepCloneable
{
[IgnoreDataMember]
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
[IgnoreDataMember]
internal Action OnAdd;
internal PropertyTypeCollection()
@@ -131,5 +135,15 @@ namespace Umbraco.Core.Models
CollectionChanged(this, args);
}
}
public object DeepClone()
{
var newGroup = new PropertyTypeCollection();
foreach (var p in this)
{
newGroup.Add((PropertyType)p.DeepClone());
}
return newGroup;
}
}
}

View File

@@ -107,5 +107,6 @@ namespace Umbraco.Core.Models
{
get { return _relationType.Id; }
}
}
}

View File

@@ -127,5 +127,6 @@ namespace Umbraco.Core.Models
}, _childObjectType, ChildObjectTypeSelector);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.Reflection;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
@@ -34,7 +35,7 @@ namespace Umbraco.Core.Models
{
UpdateDate = updateDate;
CreateDate = createDate;
Key = Id.ToString().EncodeAsGuid();
Key = Id.ToString(CultureInfo.InvariantCulture).EncodeAsGuid();
Id = id;
ServerAddress = serverAddress;
ComputerName = computerName;
@@ -51,7 +52,7 @@ namespace Umbraco.Core.Models
{
CreateDate = createDate;
UpdateDate = createDate;
Key = 0.ToString().EncodeAsGuid();
Key = 0.ToString(CultureInfo.InvariantCulture).EncodeAsGuid();
ServerAddress = serverAddress;
ComputerName = computerName;
}

View File

@@ -132,5 +132,6 @@ namespace Umbraco.Core.Models
}, _comment, CommentSelector);
}
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
@@ -14,20 +15,18 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class Template : File, ITemplate
{
private readonly string _alias;
private readonly string _name;
private string _alias;
private string _name;
private int _creatorId;
private int _level;
private int _sortOrder;
private int _parentId;
private int _masterTemplateId;
private string _masterTemplateAlias;
private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.CreatorId);
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.Level);
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.SortOrder);
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.ParentId);
//private static readonly PropertyInfo MasterTemplateIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.MasterTemplateId);
private static readonly PropertyInfo MasterTemplateAliasSelector = ExpressionHelper.GetPropertyInfo<Template, string>(x => x.MasterTemplateAlias);
public Template(string path, string name, string alias)
@@ -189,5 +188,18 @@ namespace Umbraco.Core.Models
{
MasterTemplateId = new Lazy<int>(() => masterTemplate.Id);
}
public override object DeepClone()
{
var clone = (Template)base.DeepClone();
//need to manually assign since they are readonly properties
clone._alias = Alias;
clone._name = Name;
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Umbraco.Core.Models.EntityBase;
@@ -46,11 +47,13 @@ namespace Umbraco.Core.Models
public UmbracoEntity()
{
AdditionalData = new Dictionary<string, object>();
UmbracoProperties = new List<UmbracoProperty>();
}
public UmbracoEntity(bool trashed)
{
AdditionalData = new Dictionary<string, object>();
UmbracoProperties = new List<UmbracoProperty>();
Trashed = trashed;
}
@@ -58,6 +61,7 @@ namespace Umbraco.Core.Models
public UmbracoEntity(UInt64 trashed)
{
AdditionalData = new Dictionary<string, object>();
UmbracoProperties = new List<UmbracoProperty>();
Trashed = trashed == 1;
}
@@ -287,11 +291,39 @@ namespace Umbraco.Core.Models
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
/// </summary>
public IList<UmbracoProperty> UmbracoProperties { get; set; }
internal class UmbracoProperty
internal class UmbracoProperty : IDeepCloneable
{
public string PropertyEditorAlias { get; set; }
public string Value { get; set; }
public object DeepClone()
{
//Memberwise clone on Entity will work since it doesn't have any deep elements
// for any sub class this will work for standard properties as well that aren't complex object's themselves.
var clone = MemberwiseClone();
return clone;
}
protected bool Equals(UmbracoProperty other)
{
return PropertyEditorAlias.Equals(other.PropertyEditorAlias) && string.Equals(Value, other.Value);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((UmbracoProperty) obj);
}
public override int GetHashCode()
{
unchecked
{
return (PropertyEditorAlias.GetHashCode() * 397) ^ (Value != null ? Value.GetHashCode() : 0);
}
}
}
}
}

View File

@@ -37,7 +37,10 @@ namespace Umbraco.Core.Persistence.Caching
var containsKey = _cache.ContainsKey(compositeKey);
if (containsKey)
{
return _cache[compositeKey];
var result = _cache[compositeKey];
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
return (IEntity)result.DeepClone();
}
return null;
@@ -56,7 +59,12 @@ namespace Umbraco.Core.Persistence.Caching
into key
let containsKey = _cache.ContainsKey(key)
where containsKey
select _cache[key]).ToList();
select _cache[key]
into result
//don't return null objects
where result != null
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
select (IEntity)result.DeepClone()).ToList();
return list;
}
@@ -67,7 +75,14 @@ namespace Umbraco.Core.Persistence.Caching
/// <returns></returns>
public IEnumerable<IEntity> GetAllByType(Type type)
{
var list = _cache.Keys.Where(key => key.Contains(type.Name)).Select(key => _cache[key]).ToList();
var list = _cache.Keys
.Where(key => key.Contains(type.Name))
.Select(key => _cache[key])
//don't return null objects
.Where(result => result != null)
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
.Select(result => (IEntity)result.DeepClone())
.ToList();
return list;
}
@@ -78,6 +93,9 @@ namespace Umbraco.Core.Persistence.Caching
/// <param name="entity"></param>
public void Save(Type type, IEntity entity)
{
//IMPORTANT: we must clone to store, see: http://issues.umbraco.org/issue/U4-4259
entity = (IEntity)entity.DeepClone();
_cache.AddOrUpdate(GetCompositeId(type, entity.Id), entity, (x, y) => entity);
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -29,6 +29,9 @@ namespace Umbraco.Core.Persistence.Caching
/// when there are async requests being made even in the context of a web request, the HttpContext.Current will be null but the HttpRuntime.Cache will
/// always be available.
///
/// TODO: Each item that get's added to this cache will be a clone of the original with it's dirty properties reset, and every item that is resolved from the cache
/// is a clone of the item that is in there, otherwise we end up with thread safety issues since multiple thread would be working on the exact same entity at the same time.
///
/// </remarks>
internal sealed class RuntimeCacheProvider : IRepositoryCacheProvider
{
@@ -64,8 +67,11 @@ namespace Umbraco.Core.Persistence.Caching
{
//ensure the key doesn't exist anymore in the tracker
_keyTracker.Remove(key);
return null;
}
return result;
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
return (IEntity)result.DeepClone();
}
public IEnumerable<IEntity> GetByIds(Type type, List<Guid> ids)
@@ -85,7 +91,8 @@ namespace Umbraco.Core.Persistence.Caching
}
else
{
collection.Add(result);
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
collection.Add((IEntity)result.DeepClone());
}
}
return collection;
@@ -110,7 +117,8 @@ namespace Umbraco.Core.Persistence.Caching
}
else
{
collection.Add(result);
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
collection.Add((IEntity)result.DeepClone());
}
}
}
@@ -119,6 +127,9 @@ namespace Umbraco.Core.Persistence.Caching
public void Save(Type type, IEntity entity)
{
//IMPORTANT: we must clone to store, see: http://issues.umbraco.org/issue/U4-4259
entity = (IEntity)entity.DeepClone();
var key = GetCompositeId(type, entity.Id);
_keyTracker.TryAdd(key);

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Threading;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
@@ -11,6 +13,8 @@ using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Services;
using NullCacheProvider = Umbraco.Core.Persistence.Caching.NullCacheProvider;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -19,16 +23,30 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
internal class DataTypeDefinitionRepository : PetaPocoRepositoryBase<int, IDataTypeDefinition>, IDataTypeDefinitionRepository
{
public DataTypeDefinitionRepository(IDatabaseUnitOfWork work)
private readonly CacheHelper _cacheHelper;
private readonly IContentTypeRepository _contentTypeRepository;
private readonly DataTypePreValueRepository _preValRepository;
public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper,
IContentTypeRepository contentTypeRepository)
: base(work)
{
_cacheHelper = cacheHelper;
_contentTypeRepository = contentTypeRepository;
_preValRepository = new DataTypePreValueRepository(work, NullCacheProvider.Current);
}
public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, CacheHelper cacheHelper,
IContentTypeRepository contentTypeRepository)
: base(work, cache)
{
_cacheHelper = cacheHelper;
_contentTypeRepository = contentTypeRepository;
_preValRepository = new DataTypePreValueRepository(work, NullCacheProvider.Current);
}
private readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
#region Overrides of RepositoryBase<int,DataTypeDefinition>
protected override IDataTypeDefinition PerformGet(int id)
@@ -83,6 +101,37 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
/// <summary>
/// Override the delete method so that we can ensure that all related content type's are updated as part of the overall transaction
/// </summary>
/// <param name="entity"></param>
public override void Delete(IDataTypeDefinition entity)
{
//Find ContentTypes using this IDataTypeDefinition on a PropertyType
var query = Query<PropertyType>.Builder.Where(x => x.DataTypeDefinitionId == entity.Id);
var contentTypes = _contentTypeRepository.GetByQuery(query);
//Loop through the list of results and remove the PropertyTypes that references the DataTypeDefinition that is being deleted
foreach (var contentType in contentTypes)
{
if (contentType == null) continue;
foreach (var group in contentType.PropertyGroups)
{
var types = @group.PropertyTypes.Where(x => x.DataTypeDefinitionId == entity.Id).ToList();
foreach (var propertyType in types)
{
@group.PropertyTypes.Remove(propertyType);
}
}
_contentTypeRepository.AddOrUpdate(contentType);
}
//call the base method to queue the deletion of this data type
base.Delete(entity);
}
#endregion
#region Overrides of PetaPocoRepositoryBase<int,DataTypeDefinition>
@@ -117,6 +166,42 @@ namespace Umbraco.Core.Persistence.Repositories
#region Unit of Work Implementation
public override void PersistUpdatedItem(IEntity entity)
{
if (entity is PreValue)
{
_preValRepository.PersistUpdatedItem(entity);
}
else
{
base.PersistUpdatedItem(entity);
}
}
public override void PersistNewItem(IEntity entity)
{
if (entity is PreValue)
{
_preValRepository.PersistNewItem(entity);
}
else
{
base.PersistNewItem(entity);
}
}
public override void PersistDeletedItem(IEntity entity)
{
if (entity is PreValue)
{
_preValRepository.PersistDeletedItem(entity);
}
else
{
base.PersistDeletedItem(entity);
}
}
protected override void PersistNewItem(IDataTypeDefinition entity)
{
((DataTypeDefinition)entity).AddingEntity();
@@ -238,5 +323,321 @@ AND umbracoNode.id <> @id",
}
#endregion
public PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId)
{
using (var l = new UpgradeableReadLock(Locker))
{
var cached = _cacheHelper.RuntimeCache.GetCacheItemsByKeySearch<PreValueCollection>(GetPrefixedCacheKey(dataTypeId));
if (cached != null && cached.Any())
{
//return from the cache
return cached.First();
}
l.UpgradeToWriteLock();
return GetAndCachePreValueCollection(dataTypeId);
}
}
public string GetPreValueAsString(int preValueId)
{
using (var l = new UpgradeableReadLock(Locker))
{
//We need to see if we can find the cached PreValueCollection based on the cache key above
var regex = CacheKeys.DataTypePreValuesCacheKey + @"[\d]+-[,\d]*" + preValueId + @"[,\d$]*";
var cached = _cacheHelper.RuntimeCache.GetCacheItemsByKeyExpression<PreValueCollection>(regex);
if (cached != null && cached.Any())
{
//return from the cache
var collection = cached.First();
var preVal = collection.PreValuesAsArray.Single(x => x.Id == preValueId);
return preVal.Value;
}
l.UpgradeToWriteLock();
//go and find the data type id for the pre val id passed in
var dto = Database.FirstOrDefault<DataTypePreValueDto>("WHERE id = @preValueId", new { preValueId = preValueId });
if (dto == null)
{
return string.Empty;
}
// go cache the collection
var preVals = GetAndCachePreValueCollection(dto.DataTypeNodeId);
//return the single value for this id
var pv = preVals.PreValuesAsArray.Single(x => x.Id == preValueId);
return pv.Value;
}
}
public void AddOrUpdatePreValues(int dataTypeId, IDictionary<string, PreValue> values)
{
var dtd = Get(dataTypeId);
if (dtd == null)
{
throw new InvalidOperationException("No data type found with id " + dataTypeId);
}
AddOrUpdatePreValues(dtd, values);
}
public void AddOrUpdatePreValues(IDataTypeDefinition dataType, IDictionary<string, PreValue> values)
{
var currentVals = new DataTypePreValueDto[]{};
if (dataType.HasIdentity)
{
//first just get all pre-values for this data type so we can compare them to see if we need to insert or update or replace
var sql = new Sql().Select("*")
.From<DataTypePreValueDto>()
.Where<DataTypePreValueDto>(dto => dto.DataTypeNodeId == dataType.Id)
.OrderBy<DataTypePreValueDto>(dto => dto.SortOrder);
currentVals = Database.Fetch<DataTypePreValueDto>(sql).ToArray();
}
//already existing, need to be updated
var valueIds = values.Where(x => x.Value.Id > 0).Select(x => x.Value.Id).ToArray();
var existingByIds = currentVals.Where(x => valueIds.Contains(x.Id)).ToArray();
//These ones need to be removed from the db, they no longer exist in the new values
var deleteById = currentVals.Where(x => valueIds.Contains(x.Id) == false);
foreach (var d in deleteById)
{
_preValRepository.Delete(new PreValueEntity
{
Alias = d.Alias,
Id = d.Id,
Value = d.Value,
DataType = dataType,
SortOrder = d.SortOrder
});
}
var sortOrder = 1;
foreach (var pre in values)
{
var existing = existingByIds.FirstOrDefault(valueDto => valueDto.Id == pre.Value.Id);
if (existing != null)
{
existing.Value = pre.Value.Value;
existing.SortOrder = sortOrder;
_preValRepository.AddOrUpdate(new PreValueEntity
{
Alias = existing.Alias,
Id = existing.Id,
SortOrder = existing.SortOrder,
Value = existing.Value,
DataType = dataType,
});
}
else
{
_preValRepository.AddOrUpdate(new PreValueEntity
{
Alias = pre.Key,
SortOrder = sortOrder,
Value = pre.Value.Value,
DataType = dataType,
});
}
sortOrder++;
}
}
private string GetPrefixedCacheKey(int dataTypeId)
{
return CacheKeys.DataTypePreValuesCacheKey + dataTypeId + "-";
}
private PreValueCollection GetAndCachePreValueCollection(int dataTypeId)
{
//go get the data
var dtos = Database.Fetch<DataTypePreValueDto>("WHERE datatypeNodeId = @Id", new { Id = dataTypeId });
var list = dtos.Select(x => new Tuple<PreValue, string, int>(new PreValue(x.Id, x.Value), x.Alias, x.SortOrder)).ToList();
var collection = PreValueConverter.ConvertToPreValuesCollection(list);
//now create the cache key, this needs to include all pre-value ids so that we can use this cached item in the GetPreValuesAsString method
//the key will be: "UmbracoPreValDATATYPEID-CSVOFPREVALIDS
var key = GetPrefixedCacheKey(dataTypeId)
+ string.Join(",", collection.FormatAsDictionary().Select(x => x.Value.Id).ToArray());
//store into cache
_cacheHelper.RuntimeCache.InsertCacheItem(key, () => collection,
//30 mins
new TimeSpan(0, 0, 30),
//sliding is true
true);
return collection;
}
/// <summary>
/// Private class to handle pre-value crud based on units of work with transactions
/// </summary>
public class PreValueEntity : Entity, IAggregateRoot
{
public string Value { get; set; }
public string Alias { get; set; }
public IDataTypeDefinition DataType { get; set; }
public int SortOrder { get; set; }
}
/// <summary>
/// Private class to handle pre-value crud based on standard principles and units of work with transactions
/// </summary>
private class DataTypePreValueRepository : PetaPocoRepositoryBase<int, PreValueEntity>
{
public DataTypePreValueRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache) : base(work, cache)
{
}
#region Not implemented (don't need to for the purposes of this repo)
protected override PreValueEntity PerformGet(int id)
{
throw new NotImplementedException();
}
protected override IEnumerable<PreValueEntity> PerformGetAll(params int[] ids)
{
throw new NotImplementedException();
}
protected override IEnumerable<PreValueEntity> PerformGetByQuery(IQuery<PreValueEntity> query)
{
throw new NotImplementedException();
}
protected override Sql GetBaseQuery(bool isCount)
{
throw new NotImplementedException();
}
protected override string GetBaseWhereClause()
{
throw new NotImplementedException();
}
protected override IEnumerable<string> GetDeleteClauses()
{
return new List<string>();
}
protected override Guid NodeObjectTypeId
{
get { throw new NotImplementedException(); }
}
#endregion
protected override void PersistDeletedItem(PreValueEntity entity)
{
Database.Execute(
"DELETE FROM cmsDataTypePreValues WHERE id=@Id",
new { Id = entity.Id });
}
protected override void PersistNewItem(PreValueEntity entity)
{
if (entity.DataType.HasIdentity == false)
{
throw new InvalidOperationException("Cannot insert a pre value for a data type that has no identity");
}
//Cannot add a duplicate alias
var exists = Database.ExecuteScalar<int>(@"SELECT COUNT(*) FROM cmsDataTypePreValues
WHERE alias = @alias
AND datatypeNodeId = @dtdid",
new { alias = entity.Alias, dtdid = entity.DataType.Id });
if (exists > 0)
{
throw new DuplicateNameException("A pre value with the alias " + entity.Alias + " already exists for this data type");
}
var dto = new DataTypePreValueDto
{
DataTypeNodeId = entity.DataType.Id,
Value = entity.Value,
SortOrder = entity.SortOrder,
Alias = entity.Alias
};
Database.Insert(dto);
}
protected override void PersistUpdatedItem(PreValueEntity entity)
{
if (entity.DataType.HasIdentity == false)
{
throw new InvalidOperationException("Cannot update a pre value for a data type that has no identity");
}
//Cannot change to a duplicate alias
var exists = Database.ExecuteScalar<int>(@"SELECT COUNT(*) FROM cmsDataTypePreValues
WHERE alias = @alias
AND datatypeNodeId = @dtdid
AND id <> @id",
new { id = entity.Id, alias = entity.Alias, dtdid = entity.DataType.Id });
if (exists > 0)
{
throw new DuplicateNameException("A pre value with the alias " + entity.Alias + " already exists for this data type");
}
var dto = new DataTypePreValueDto
{
DataTypeNodeId = entity.DataType.Id,
Id = entity.Id,
Value = entity.Value,
SortOrder = entity.SortOrder,
Alias = entity.Alias
};
Database.Update(dto);
}
}
internal static class PreValueConverter
{
/// <summary>
/// Converts the tuple to a pre-value collection
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
internal static PreValueCollection ConvertToPreValuesCollection(IEnumerable<Tuple<PreValue, string, int>> list)
{
//now we need to determine if they are dictionary based, otherwise they have to be array based
var dictionary = new Dictionary<string, PreValue>();
//need to check all of the keys, if there's only one and it is empty then it's an array
var keys = list.Select(x => x.Item2).Distinct().ToArray();
if (keys.Length == 1 && keys[0].IsNullOrWhiteSpace())
{
return new PreValueCollection(list.OrderBy(x => x.Item3).Select(x => x.Item1));
}
foreach (var item in list
.OrderBy(x => x.Item3) //we'll order them first so we maintain the order index in the dictionary
.GroupBy(x => x.Item2)) //group by alias
{
if (item.Count() > 1)
{
//if there's more than 1 item per key, then it cannot be a dictionary, just return the array
return new PreValueCollection(list.OrderBy(x => x.Item3).Select(x => x.Item1));
}
dictionary.Add(item.Key, item.First().Item1);
}
return new PreValueCollection(dictionary);
}
}
}
}

View File

@@ -1,9 +1,15 @@
using Umbraco.Core.Models;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IDataTypeDefinitionRepository : IRepositoryQueryable<int, IDataTypeDefinition>
{
PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId);
string GetPreValueAsString(int preValueId);
void AddOrUpdatePreValues(IDataTypeDefinition dataType, IDictionary<string, PreValue> values);
void AddOrUpdatePreValues(int dataTypeId, IDictionary<string, PreValue> values);
}
}

View File

@@ -72,7 +72,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// Deletes the passed in entity
/// </summary>
/// <param name="entity"></param>
public void Delete(TEntity entity)
public virtual void Delete(TEntity entity)
{
if(_work != null)
{

View File

@@ -81,14 +81,16 @@ namespace Umbraco.Core.Persistence
return new ContentTypeRepository(
uow,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current,
new TemplateRepository(uow, NullCacheProvider.Current));
CreateTemplateRepository(uow));
}
public virtual IDataTypeDefinitionRepository CreateDataTypeDefinitionRepository(IDatabaseUnitOfWork uow)
{
return new DataTypeDefinitionRepository(
uow,
NullCacheProvider.Current);
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current,
_cacheHelper,
CreateContentTypeRepository(uow));
}
public virtual IDictionaryRepository CreateDictionaryRepository(IDatabaseUnitOfWork uow)

View File

@@ -120,10 +120,11 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of string values</returns>
public IEnumerable<string> GetPreValuesByDataTypeId(int id)
{
using (var uow = _uowProvider.GetUnitOfWork())
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(_uowProvider.GetUnitOfWork()))
{
var dtos = uow.Database.Fetch<DataTypePreValueDto>("WHERE datatypeNodeId = @Id", new {Id = id});
var list = dtos.Select(x => x.Value).ToList();
var collection = repository.GetPreValuesCollectionByDataTypeId(id);
//now convert the collection to a string list
var list = collection.PreValuesAsArray.Select(x => x.Value).ToList();
return list;
}
}
@@ -135,12 +136,9 @@ namespace Umbraco.Core.Services
/// <returns></returns>
public PreValueCollection GetPreValuesCollectionByDataTypeId(int id)
{
using (var uow = _uowProvider.GetUnitOfWork())
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(_uowProvider.GetUnitOfWork()))
{
var dtos = uow.Database.Fetch<DataTypePreValueDto>("WHERE datatypeNodeId = @Id", new { Id = id });
var list = dtos.Select(x => new Tuple<PreValue, string, int>(new PreValue(x.Id, x.Value, x.SortOrder), x.Alias, x.SortOrder)).ToList();
return PreValueConverter.ConvertToPreValuesCollection(list);
return repository.GetPreValuesCollectionByDataTypeId(id);
}
}
@@ -151,10 +149,9 @@ namespace Umbraco.Core.Services
/// <returns>PreValue as a string</returns>
public string GetPreValueAsString(int id)
{
using (var uow = _uowProvider.GetUnitOfWork())
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(_uowProvider.GetUnitOfWork()))
{
var dto = uow.Database.FirstOrDefault<DataTypePreValueDto>("WHERE id = @Id", new { Id = id });
return dto != null ? dto.Value : string.Empty;
return repository.GetPreValueAsString(id);
}
}
@@ -168,17 +165,14 @@ namespace Umbraco.Core.Services
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition), this))
return;
using (new WriteLock(Locker))
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow))
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow))
{
dataTypeDefinition.CreatorId = userId;
repository.AddOrUpdate(dataTypeDefinition);
uow.Commit();
dataTypeDefinition.CreatorId = userId;
repository.AddOrUpdate(dataTypeDefinition);
uow.Commit();
Saved.RaiseEvent(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition, false), this);
}
Saved.RaiseEvent(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition, false), this);
}
Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id);
@@ -194,31 +188,29 @@ namespace Umbraco.Core.Services
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitions), this))
return;
using (new WriteLock(Locker))
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow))
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow))
foreach (var dataTypeDefinition in dataTypeDefinitions)
{
foreach (var dataTypeDefinition in dataTypeDefinitions)
{
dataTypeDefinition.CreatorId = userId;
repository.AddOrUpdate(dataTypeDefinition);
}
uow.Commit();
Saved.RaiseEvent(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitions, false), this);
dataTypeDefinition.CreatorId = userId;
repository.AddOrUpdate(dataTypeDefinition);
}
uow.Commit();
Saved.RaiseEvent(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitions, false), this);
}
Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId, -1);
}
/// <summary>
/// Saves a list of PreValues for a given DataTypeDefinition
/// </summary>
/// <param name="id">Id of the DataTypeDefinition to save PreValues for</param>
/// <param name="dataTypeId">Id of the DataTypeDefinition to save PreValues for</param>
/// <param name="values">List of string values to save</param>
[Obsolete("This should no longer be used, use the alternative SavePreValues or SaveDataTypeAndPreValues methods instead. This will only insert pre-values without keys")]
public void SavePreValues(int id, IEnumerable<string> values)
public void SavePreValues(int dataTypeId, IEnumerable<string> values)
{
//TODO: Should we raise an event here since we are really saving values for the data type?
@@ -230,7 +222,7 @@ namespace Umbraco.Core.Services
{
var sortOrderObj =
uow.Database.ExecuteScalar<object>(
"SELECT max(sortorder) FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId", new { DataTypeId = id });
"SELECT max(sortorder) FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId", new { DataTypeId = dataTypeId });
int sortOrder;
if (sortOrderObj == null || int.TryParse(sortOrderObj.ToString(), out sortOrder) == false)
{
@@ -239,7 +231,7 @@ namespace Umbraco.Core.Services
foreach (var value in values)
{
var dto = new DataTypePreValueDto { DataTypeNodeId = id, Value = value, SortOrder = sortOrder };
var dto = new DataTypePreValueDto { DataTypeNodeId = dataTypeId, Value = value, SortOrder = sortOrder };
uow.Database.Insert(dto);
sortOrder++;
}
@@ -253,26 +245,40 @@ namespace Umbraco.Core.Services
/// <summary>
/// Saves/updates the pre-values
/// </summary>
/// <param name="id"></param>
/// <param name="dataTypeId"></param>
/// <param name="values"></param>
/// <remarks>
/// We need to actually look up each pre-value and maintain it's id if possible - this is because of silly property editors
/// like 'dropdown list publishing keys'
/// </remarks>
public void SavePreValues(int id, IDictionary<string, PreValue> values)
public void SavePreValues(int dataTypeId, IDictionary<string, PreValue> values)
{
var dtd = this.GetDataTypeDefinitionById(dataTypeId);
if (dtd == null)
{
throw new InvalidOperationException("No data type found for id " + dataTypeId);
}
SavePreValues(dtd, values);
}
/// <summary>
/// Saves/updates the pre-values
/// </summary>
/// <param name="dataTypeDefinition"></param>
/// <param name="values"></param>
/// <remarks>
/// We need to actually look up each pre-value and maintain it's id if possible - this is because of silly property editors
/// like 'dropdown list publishing keys'
/// </remarks>
public void SavePreValues(IDataTypeDefinition dataTypeDefinition, IDictionary<string, PreValue> values)
{
//TODO: Should we raise an event here since we are really saving values for the data type?
using (new WriteLock(Locker))
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow))
{
using (var uow = _uowProvider.GetUnitOfWork())
{
using (var transaction = uow.Database.GetTransaction())
{
AddOrUpdatePreValues(id, values, uow);
transaction.Complete();
}
}
repository.AddOrUpdatePreValues(dataTypeDefinition, values);
uow.Commit();
}
}
@@ -287,73 +293,25 @@ namespace Umbraco.Core.Services
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition), this))
return;
using (new WriteLock(Locker))
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow))
{
var uow = (PetaPocoUnitOfWork)_uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow))
{
dataTypeDefinition.CreatorId = userId;
repository.AddOrUpdate(dataTypeDefinition);
dataTypeDefinition.CreatorId = userId;
//complete the transaction, but run the delegate before the db transaction is finalized
uow.Commit(database => AddOrUpdatePreValues(dataTypeDefinition.Id, values, uow));
//add/update the dtd
repository.AddOrUpdate(dataTypeDefinition);
Saved.RaiseEvent(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition, false), this);
}
//add/update the prevalues
repository.AddOrUpdatePreValues(dataTypeDefinition, values);
uow.Commit();
Saved.RaiseEvent(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition, false), this);
}
Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id);
}
private void AddOrUpdatePreValues(int id, IDictionary<string, PreValue> preValueCollection, IDatabaseUnitOfWork uow)
{
//first just get all pre-values for this data type so we can compare them to see if we need to insert or update or replace
var sql = new Sql().Select("*")
.From<DataTypePreValueDto>()
.Where<DataTypePreValueDto>(dto => dto.DataTypeNodeId == id)
.OrderBy<DataTypePreValueDto>(dto => dto.SortOrder);
var currentVals = uow.Database.Fetch<DataTypePreValueDto>(sql).ToArray();
//already existing, need to be updated
var valueIds = preValueCollection.Where(x => x.Value.Id > 0).Select(x => x.Value.Id).ToArray();
var existingByIds = currentVals.Where(x => valueIds.Contains(x.Id)).ToArray();
//These ones need to be removed from the db, they no longer exist in the new values
var deleteById = currentVals.Where(x => valueIds.Contains(x.Id) == false);
foreach (var d in deleteById)
{
uow.Database.Execute(
"DELETE FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId AND id=@Id",
new { DataTypeId = id, Id = d.Id });
}
var sortOrder = 1;
foreach (var pre in preValueCollection)
{
var existing = existingByIds.FirstOrDefault(valueDto => valueDto.Id == pre.Value.Id);
if (existing != null)
{
existing.Value = pre.Value.Value;
existing.SortOrder = sortOrder;
uow.Database.Update(existing);
}
else
{
var dto = new DataTypePreValueDto
{
DataTypeNodeId = id,
Value = pre.Value.Value,
SortOrder = sortOrder,
Alias = pre.Key
};
uow.Database.Insert(dto);
}
sortOrder++;
}
}
/// <summary>
/// Deletes an <see cref="IDataTypeDefinition"/>
@@ -370,31 +328,9 @@ namespace Umbraco.Core.Services
return;
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow))
{
//Find ContentTypes using this IDataTypeDefinition on a PropertyType
var query = Query<PropertyType>.Builder.Where(x => x.DataTypeDefinitionId == dataTypeDefinition.Id);
var contentTypes = repository.GetByQuery(query);
//Loop through the list of results and remove the PropertyTypes that references the DataTypeDefinition that is being deleted
foreach (var contentType in contentTypes)
{
if (contentType == null) continue;
foreach (var group in contentType.PropertyGroups)
{
var types = @group.PropertyTypes.Where(x => x.DataTypeDefinitionId == dataTypeDefinition.Id).ToList();
foreach (var propertyType in types)
{
@group.PropertyTypes.Remove(propertyType);
}
}
repository.AddOrUpdate(contentType);
}
var dataTypeRepository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow);
dataTypeRepository.Delete(dataTypeDefinition);
repository.Delete(dataTypeDefinition);
uow.Commit();
@@ -447,40 +383,6 @@ namespace Umbraco.Core.Services
public static event TypedEventHandler<IDataTypeService, SaveEventArgs<IDataTypeDefinition>> Saved;
#endregion
internal static class PreValueConverter
{
/// <summary>
/// Converts the tuple to a pre-value collection
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
internal static PreValueCollection ConvertToPreValuesCollection(IEnumerable<Tuple<PreValue, string, int>> list)
{
//now we need to determine if they are dictionary based, otherwise they have to be array based
var dictionary = new Dictionary<string, PreValue>();
//need to check all of the keys, if there's only one and it is empty then it's an array
var keys = list.Select(x => x.Item2).Distinct().ToArray();
if (keys.Length == 1 && keys[0].IsNullOrWhiteSpace())
{
return new PreValueCollection(list.OrderBy(x => x.Item3).Select(x => x.Item1));
}
foreach (var item in list
.OrderBy(x => x.Item3) //we'll order them first so we maintain the order index in the dictionary
.GroupBy(x => x.Item2)) //group by alias
{
if (item.Count() > 1)
{
//if there's more than 1 item per key, then it cannot be a dictionary, just return the array
return new PreValueCollection(list.OrderBy(x => x.Item3).Select(x => x.Item1));
}
dictionary.Add(item.Key, item.First().Item1);
}
return new PreValueCollection(dictionary);
}
}
}
}

View File

@@ -103,17 +103,24 @@ namespace Umbraco.Core.Services
/// <summary>
/// Saves a list of PreValues for a given DataTypeDefinition
/// </summary>
/// <param name="id">Id of the DataTypeDefinition to save PreValues for</param>
/// <param name="dataTypeId">Id of the DataTypeDefinition to save PreValues for</param>
/// <param name="values">List of string values to save</param>
[Obsolete("This should no longer be used, use the alternative SavePreValues or SaveDataTypeAndPreValues methods instead. This will only insert pre-values without keys")]
void SavePreValues(int id, IEnumerable<string> values);
void SavePreValues(int dataTypeId, IEnumerable<string> values);
/// <summary>
/// Saves a list of PreValues for a given DataTypeDefinition
/// </summary>
/// <param name="id">Id of the DataTypeDefinition to save PreValues for</param>
/// <param name="dataTypeId">Id of the DataTypeDefinition to save PreValues for</param>
/// <param name="values">List of key/value pairs to save</param>
void SavePreValues(int id, IDictionary<string, PreValue> values);
void SavePreValues(int dataTypeId, IDictionary<string, PreValue> values);
/// <summary>
/// Saves a list of PreValues for a given DataTypeDefinition
/// </summary>
/// <param name="dataTypeDefinition">The DataTypeDefinition to save PreValues for</param>
/// <param name="values">List of key/value pairs to save</param>
void SavePreValues(IDataTypeDefinition dataTypeDefinition, IDictionary<string, PreValue> values);
/// <summary>
/// Saves the data type and it's prevalues

View File

@@ -922,11 +922,13 @@ namespace Umbraco.Core.Services
.Select(x => x.Attribute("Value").Value);
var valuesWithKeys = prevaluesElement.Elements("PreValue")
.Where(x => ((string) x.Attribute("Alias")).IsNullOrWhiteSpace() == false)
.ToDictionary(key => (string) key.Attribute("Alias"), val => new PreValue((string) val.Attribute("Value")));
.Where(x => ((string) x.Attribute("Alias")).IsNullOrWhiteSpace() == false)
.ToDictionary(
key => (string) key.Attribute("Alias"),
val => new PreValue((string) val.Attribute("Value")));
//save the values with keys
_dataTypeService.SavePreValues(dataTypeDefinition.Id, valuesWithKeys);
_dataTypeService.SavePreValues(dataTypeDefinition, valuesWithKeys);
//save the values without keys (this is legacy)
_dataTypeService.SavePreValues(dataTypeDefinition.Id, valuesWithoutKeys);

View File

@@ -1248,5 +1248,24 @@ namespace Umbraco.Core
*/
}
public static bool ContainsAny(this string haystack, IEnumerable<string> needles, StringComparison comparison = StringComparison.CurrentCulture)
{
if (haystack == null) throw new ArgumentNullException("haystack");
if (string.IsNullOrEmpty(haystack) == false || needles.Any())
{
return needles.Any(value => haystack.IndexOf(value) >= 0);
}
return false;
}
public static bool CsvContains(this string csv, string value)
{
if (string.IsNullOrEmpty(csv))
{
return false;
}
var idCheckList = csv.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
return idCheckList.Contains(value);
}
}
}

View File

@@ -335,7 +335,10 @@
<Compile Include="Models\ContentTypeCompositionBase.cs" />
<Compile Include="Models\ContentTypeExtensions.cs" />
<Compile Include="Models\ContentTypeSort.cs" />
<Compile Include="Models\DeepCloneHelper.cs" />
<Compile Include="Models\IDeepCloneable.cs" />
<Compile Include="Models\EntityExtensions.cs" />
<Compile Include="Models\Folder.cs" />
<Compile Include="Models\IMemberGroup.cs" />
<Compile Include="Models\IRelation.cs" />
<Compile Include="Models\IRelationType.cs" />

View File

@@ -0,0 +1,253 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Tests.Models.Collections
{
public abstract class Item : IEntity, ICanBeDirty
{
private bool _hasIdentity;
private int? _hash;
private int _id;
private Guid _key;
protected Item()
{
_propertyChangedInfo = new Dictionary<string, bool>();
}
/// <summary>
/// Integer Id
/// </summary>
[DataMember]
public int Id
{
get
{
return _id;
}
set
{
_id = value;
HasIdentity = true;
}
}
/// <summary>
/// Guid based Id
/// </summary>
/// <remarks>The key is currectly used to store the Unique Id from the
/// umbracoNode table, which many of the entities are based on.</remarks>
[DataMember]
public Guid Key
{
get
{
if (_key == Guid.Empty)
return _id.ToGuid();
return _key;
}
set { _key = value; }
}
/// <summary>
/// Gets or sets the Created Date
/// </summary>
[DataMember]
public DateTime CreateDate { get; set; }
/// <summary>
/// Gets or sets the Modified Date
/// </summary>
[DataMember]
public DateTime UpdateDate { get; set; }
/// <summary>
/// Gets or sets the WasCancelled flag, which is used to track
/// whether some action against an entity was cancelled through some event.
/// This only exists so we have a way to check if an event was cancelled through
/// the new api, which also needs to take effect in the legacy api.
/// </summary>
[IgnoreDataMember]
internal bool WasCancelled { get; set; }
/// <summary>
/// Property changed event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Method to call on a property setter.
/// </summary>
/// <param name="propertyInfo">The property info.</param>
protected virtual void OnPropertyChanged(PropertyInfo propertyInfo)
{
_propertyChangedInfo[propertyInfo.Name] = true;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name));
}
}
internal virtual void ResetIdentity()
{
_hasIdentity = false;
_id = default(int);
}
/// <summary>
/// Method to call on entity saved when first added
/// </summary>
internal virtual void AddingEntity()
{
CreateDate = DateTime.Now;
UpdateDate = DateTime.Now;
}
/// <summary>
/// Method to call on entity saved/updated
/// </summary>
internal virtual void UpdatingEntity()
{
UpdateDate = DateTime.Now;
}
/// <summary>
/// Tracks the properties that have changed
/// </summary>
//private readonly IDictionary<string, bool> _propertyChangedInfo = new Dictionary<string, bool>();
private IDictionary<string, bool> _propertyChangedInfo;
/// <summary>
/// Indicates whether a specific property on the current entity is dirty.
/// </summary>
/// <param name="propertyName">Name of the property to check</param>
/// <returns>True if Property is dirty, otherwise False</returns>
public virtual bool IsPropertyDirty(string propertyName)
{
return _propertyChangedInfo.Any(x => x.Key == propertyName);
}
/// <summary>
/// Indicates whether the current entity is dirty.
/// </summary>
/// <returns>True if entity is dirty, otherwise False</returns>
public virtual bool IsDirty()
{
return _propertyChangedInfo.Any();
}
/// <summary>
/// Resets dirty properties by clearing the dictionary used to track changes.
/// </summary>
/// <remarks>
/// Please note that resetting the dirty properties could potentially
/// obstruct the saving of a new or updated entity.
/// </remarks>
public virtual void ResetDirtyProperties()
{
_propertyChangedInfo.Clear();
}
/// <summary>
/// Indicates whether the current entity has an identity, eg. Id.
/// </summary>
public virtual bool HasIdentity
{
get
{
return _hasIdentity;
}
protected set
{
_hasIdentity = value;
}
}
public static bool operator ==(Item left, Item right)
{
/*if (ReferenceEquals(null, left))
return false;
if(ReferenceEquals(null, right))
return false;*/
return ReferenceEquals(left, right);
return left.Equals(right);
}
public static bool operator !=(Item left, Item right)
{
return !(left == right);
}
/*public virtual bool SameIdentityAs(IEntity other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return SameIdentityAs(other as Entity);
}
public virtual bool Equals(Entity other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return SameIdentityAs(other);
}
public virtual Type GetRealType()
{
return GetType();
}
public virtual bool SameIdentityAs(Entity other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
if (GetType() == other.GetRealType() && HasIdentity && other.HasIdentity)
return other.Id.Equals(Id);
return false;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
return SameIdentityAs(obj as IEntity);
}
public override int GetHashCode()
{
if (!_hash.HasValue)
_hash = !HasIdentity ? new int?(base.GetHashCode()) : new int?(Id.GetHashCode() * 397 ^ GetType().GetHashCode());
return _hash.Value;
}*/
public object DeepClone()
{
return this.MemberwiseClone();
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
namespace Umbraco.Tests.Models.Collections
{
public class OrderItem : Item
{
public readonly int PartNumber;
public readonly string Description;
public readonly double UnitPrice;
private int _quantity = 0;
public OrderItem(int partNumber, string description,
int quantity, double unitPrice)
{
this.PartNumber = partNumber;
this.Description = description;
this.Quantity = quantity;
this.UnitPrice = unitPrice;
}
public int Quantity
{
get { return _quantity; }
set
{
if (value < 0)
throw new ArgumentException("Quantity cannot be negative.");
_quantity = value;
}
}
public override string ToString()
{
return String.Format(
"{0,9} {1,6} {2,-12} at {3,8:#,###.00} = {4,10:###,###.00}",
PartNumber, _quantity, Description, UnitPrice,
UnitPrice * _quantity);
}
}
}

View File

@@ -1,15 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
@@ -72,353 +65,4 @@ namespace Umbraco.Tests.Models.Collections
Assert.That(contentType.PropertyGroups.Any(x => x.Name.InvariantEquals("Test")), Is.False);
}
}
public class SimpleOrder : KeyedCollection<int, OrderItem>, INotifyCollectionChanged
{
// The parameterless constructor of the base class creates a
// KeyedCollection with an internal dictionary. For this code
// example, no other constructors are exposed.
//
public SimpleOrder() : base() { }
public SimpleOrder(IEnumerable<OrderItem> properties)
{
Reset(properties);
}
// This is the only method that absolutely must be overridden,
// because without it the KeyedCollection cannot extract the
// keys from the items. The input parameter type is the
// second generic type argument, in this case OrderItem, and
// the return value type is the first generic type argument,
// in this case int.
//
protected override int GetKeyForItem(OrderItem item)
{
// In this example, the key is the part number.
return item.PartNumber;
}
internal void Reset(IEnumerable<OrderItem> properties)
{
Clear();
properties.ForEach(Add);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
protected override void SetItem(int index, OrderItem item)
{
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
}
protected override void RemoveItem(int index)
{
var removed = this[index];
base.RemoveItem(index);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
}
protected override void InsertItem(int index, OrderItem item)
{
base.InsertItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
protected override void ClearItems()
{
base.ClearItems();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public new bool Contains(int partNumber)
{
return this.Any(x => x.PartNumber == partNumber);
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
if (CollectionChanged != null)
{
CollectionChanged(this, args);
}
}
}
public class OrderItem : Item
{
public readonly int PartNumber;
public readonly string Description;
public readonly double UnitPrice;
private int _quantity = 0;
public OrderItem(int partNumber, string description,
int quantity, double unitPrice)
{
this.PartNumber = partNumber;
this.Description = description;
this.Quantity = quantity;
this.UnitPrice = unitPrice;
}
public int Quantity
{
get { return _quantity; }
set
{
if (value < 0)
throw new ArgumentException("Quantity cannot be negative.");
_quantity = value;
}
}
public override string ToString()
{
return String.Format(
"{0,9} {1,6} {2,-12} at {3,8:#,###.00} = {4,10:###,###.00}",
PartNumber, _quantity, Description, UnitPrice,
UnitPrice * _quantity);
}
}
public abstract class Item : IEntity, ICanBeDirty
{
private bool _hasIdentity;
private int? _hash;
private int _id;
private Guid _key;
protected Item()
{
_propertyChangedInfo = new Dictionary<string, bool>();
}
/// <summary>
/// Integer Id
/// </summary>
[DataMember]
public int Id
{
get
{
return _id;
}
set
{
_id = value;
HasIdentity = true;
}
}
/// <summary>
/// Guid based Id
/// </summary>
/// <remarks>The key is currectly used to store the Unique Id from the
/// umbracoNode table, which many of the entities are based on.</remarks>
[DataMember]
public Guid Key
{
get
{
if (_key == Guid.Empty)
return _id.ToGuid();
return _key;
}
set { _key = value; }
}
/// <summary>
/// Gets or sets the Created Date
/// </summary>
[DataMember]
public DateTime CreateDate { get; set; }
/// <summary>
/// Gets or sets the Modified Date
/// </summary>
[DataMember]
public DateTime UpdateDate { get; set; }
/// <summary>
/// Gets or sets the WasCancelled flag, which is used to track
/// whether some action against an entity was cancelled through some event.
/// This only exists so we have a way to check if an event was cancelled through
/// the new api, which also needs to take effect in the legacy api.
/// </summary>
[IgnoreDataMember]
internal bool WasCancelled { get; set; }
/// <summary>
/// Property changed event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Method to call on a property setter.
/// </summary>
/// <param name="propertyInfo">The property info.</param>
protected virtual void OnPropertyChanged(PropertyInfo propertyInfo)
{
_propertyChangedInfo[propertyInfo.Name] = true;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name));
}
}
internal virtual void ResetIdentity()
{
_hasIdentity = false;
_id = default(int);
}
/// <summary>
/// Method to call on entity saved when first added
/// </summary>
internal virtual void AddingEntity()
{
CreateDate = DateTime.Now;
UpdateDate = DateTime.Now;
}
/// <summary>
/// Method to call on entity saved/updated
/// </summary>
internal virtual void UpdatingEntity()
{
UpdateDate = DateTime.Now;
}
/// <summary>
/// Tracks the properties that have changed
/// </summary>
//private readonly IDictionary<string, bool> _propertyChangedInfo = new Dictionary<string, bool>();
private IDictionary<string, bool> _propertyChangedInfo;
/// <summary>
/// Indicates whether a specific property on the current entity is dirty.
/// </summary>
/// <param name="propertyName">Name of the property to check</param>
/// <returns>True if Property is dirty, otherwise False</returns>
public virtual bool IsPropertyDirty(string propertyName)
{
return _propertyChangedInfo.Any(x => x.Key == propertyName);
}
/// <summary>
/// Indicates whether the current entity is dirty.
/// </summary>
/// <returns>True if entity is dirty, otherwise False</returns>
public virtual bool IsDirty()
{
return _propertyChangedInfo.Any();
}
/// <summary>
/// Resets dirty properties by clearing the dictionary used to track changes.
/// </summary>
/// <remarks>
/// Please note that resetting the dirty properties could potentially
/// obstruct the saving of a new or updated entity.
/// </remarks>
public virtual void ResetDirtyProperties()
{
_propertyChangedInfo.Clear();
}
/// <summary>
/// Indicates whether the current entity has an identity, eg. Id.
/// </summary>
public virtual bool HasIdentity
{
get
{
return _hasIdentity;
}
protected set
{
_hasIdentity = value;
}
}
public static bool operator ==(Item left, Item right)
{
/*if (ReferenceEquals(null, left))
return false;
if(ReferenceEquals(null, right))
return false;*/
return ReferenceEquals(left, right);
return left.Equals(right);
}
public static bool operator !=(Item left, Item right)
{
return !(left == right);
}
/*public virtual bool SameIdentityAs(IEntity other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return SameIdentityAs(other as Entity);
}
public virtual bool Equals(Entity other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return SameIdentityAs(other);
}
public virtual Type GetRealType()
{
return GetType();
}
public virtual bool SameIdentityAs(Entity other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
if (GetType() == other.GetRealType() && HasIdentity && other.HasIdentity)
return other.Id.Equals(Id);
return false;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
return SameIdentityAs(obj as IEntity);
}
public override int GetHashCode()
{
if (!_hash.HasValue)
_hash = !HasIdentity ? new int?(base.GetHashCode()) : new int?(Id.GetHashCode() * 397 ^ GetType().GetHashCode());
return _hash.Value;
}*/
}
}

View File

@@ -0,0 +1,82 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using Umbraco.Core;
namespace Umbraco.Tests.Models.Collections
{
public class SimpleOrder : KeyedCollection<int, OrderItem>, INotifyCollectionChanged
{
// The parameterless constructor of the base class creates a
// KeyedCollection with an internal dictionary. For this code
// example, no other constructors are exposed.
//
public SimpleOrder() : base() { }
public SimpleOrder(IEnumerable<OrderItem> properties)
{
Reset(properties);
}
// This is the only method that absolutely must be overridden,
// because without it the KeyedCollection cannot extract the
// keys from the items. The input parameter type is the
// second generic type argument, in this case OrderItem, and
// the return value type is the first generic type argument,
// in this case int.
//
protected override int GetKeyForItem(OrderItem item)
{
// In this example, the key is the part number.
return item.PartNumber;
}
internal void Reset(IEnumerable<OrderItem> properties)
{
Clear();
properties.ForEach(Add);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
protected override void SetItem(int index, OrderItem item)
{
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
}
protected override void RemoveItem(int index)
{
var removed = this[index];
base.RemoveItem(index);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
}
protected override void InsertItem(int index, OrderItem item)
{
base.InsertItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
protected override void ClearItems()
{
base.ClearItems();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public new bool Contains(int partNumber)
{
return this.Any(x => x.PartNumber == partNumber);
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
if (CollectionChanged != null)
{
CollectionChanged(this, args);
}
}
}
}

View File

@@ -6,6 +6,8 @@ using System.Web;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Serialization;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
@@ -159,7 +161,7 @@ namespace Umbraco.Tests.Models
[Test]
public void Can_Clone_Content()
public void Can_Clone_Content_With_Reset_Identity()
{
// Arrange
var contentType = MockedContentTypes.CreateTextpageContentType();
@@ -175,6 +177,143 @@ namespace Umbraco.Tests.Models
Assert.AreNotSame(clone.Id, content.Id);
Assert.AreNotSame(clone.Version, content.Version);
Assert.That(clone.HasIdentity, Is.False);
Assert.AreNotSame(content.Properties, clone.Properties);
}
[Test]
public void Can_Deep_Clone()
{
// Arrange
var contentType = MockedContentTypes.CreateTextpageContentType();
contentType.Id = 99;
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
var i = 200;
foreach (var property in content.Properties)
{
property.Id = ++i;
}
content.Id = 10;
content.CreateDate = DateTime.Now;
content.CreatorId = 22;
content.ExpireDate = DateTime.Now;
content.Key = Guid.NewGuid();
content.Language = "en";
content.Level = 3;
content.Path = "-1,4,10";
content.ReleaseDate = DateTime.Now;
content.ChangePublishedState(PublishedState.Published);
content.SortOrder = 5;
content.Template = new Template("-1,2,3,4", "Test Template", "testTemplate")
{
Id = 88
};
content.Trashed = false;
content.UpdateDate = DateTime.Now;
content.Version = Guid.NewGuid();
content.WriterId = 23;
((IUmbracoEntity)content).AdditionalData.Add("test1", 123);
((IUmbracoEntity)content).AdditionalData.Add("test2", "hello");
// Act
var clone = (Content)content.DeepClone();
// Assert
Assert.AreNotSame(clone, content);
Assert.AreEqual(clone, content);
Assert.AreEqual(clone.Id, content.Id);
Assert.AreEqual(clone.Version, content.Version);
Assert.AreEqual(((IUmbracoEntity)clone).AdditionalData, ((IUmbracoEntity)content).AdditionalData);
Assert.AreNotSame(clone.ContentType, content.ContentType);
Assert.AreEqual(clone.ContentType, content.ContentType);
Assert.AreEqual(clone.ContentType.PropertyGroups.Count, content.ContentType.PropertyGroups.Count);
for (var index = 0; index < content.ContentType.PropertyGroups.Count; index++)
{
Assert.AreNotSame(clone.ContentType.PropertyGroups[index], content.ContentType.PropertyGroups[index]);
Assert.AreEqual(clone.ContentType.PropertyGroups[index], content.ContentType.PropertyGroups[index]);
}
Assert.AreEqual(clone.ContentType.PropertyTypes.Count(), content.ContentType.PropertyTypes.Count());
for (var index = 0; index < content.ContentType.PropertyTypes.Count(); index++)
{
Assert.AreNotSame(clone.ContentType.PropertyTypes.ElementAt(index), content.ContentType.PropertyTypes.ElementAt(index));
Assert.AreEqual(clone.ContentType.PropertyTypes.ElementAt(index), content.ContentType.PropertyTypes.ElementAt(index));
}
Assert.AreEqual(clone.ContentTypeId, content.ContentTypeId);
Assert.AreEqual(clone.CreateDate, content.CreateDate);
Assert.AreEqual(clone.CreatorId, content.CreatorId);
Assert.AreEqual(clone.ExpireDate, content.ExpireDate);
Assert.AreEqual(clone.Key, content.Key);
Assert.AreEqual(clone.Language, content.Language);
Assert.AreEqual(clone.Level, content.Level);
Assert.AreEqual(clone.Path, content.Path);
Assert.AreEqual(clone.ReleaseDate, content.ReleaseDate);
Assert.AreEqual(clone.Published, content.Published);
Assert.AreEqual(clone.PublishedState, content.PublishedState);
Assert.AreEqual(clone.SortOrder, content.SortOrder);
Assert.AreEqual(clone.PublishedState, content.PublishedState);
Assert.AreNotSame(clone.Template, content.Template);
Assert.AreEqual(clone.Template, content.Template);
Assert.AreEqual(clone.Trashed, content.Trashed);
Assert.AreEqual(clone.UpdateDate, content.UpdateDate);
Assert.AreEqual(clone.Version, content.Version);
Assert.AreEqual(clone.WriterId, content.WriterId);
Assert.AreNotSame(clone.Properties, content.Properties);
Assert.AreEqual(clone.Properties.Count(), content.Properties.Count());
for (var index = 0; index < content.Properties.Count; index++)
{
Assert.AreNotSame(clone.Properties[index], content.Properties[index]);
Assert.AreEqual(clone.Properties[index], content.Properties[index]);
}
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(content, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
// Arrange
var contentType = MockedContentTypes.CreateTextpageContentType();
contentType.Id = 99;
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
var i = 200;
foreach (var property in content.Properties)
{
property.Id = ++i;
}
content.Id = 10;
content.CreateDate = DateTime.Now;
content.CreatorId = 22;
content.ExpireDate = DateTime.Now;
content.Key = Guid.NewGuid();
content.Language = "en";
content.Level = 3;
content.Path = "-1,4,10";
content.ReleaseDate = DateTime.Now;
content.ChangePublishedState(PublishedState.Published);
content.SortOrder = 5;
content.Template = new Template("-1,2,3,4", "Test Template", "testTemplate")
{
Id = 88
};
content.Trashed = false;
content.UpdateDate = DateTime.Now;
content.Version = Guid.NewGuid();
content.WriterId = 23;
((IUmbracoEntity)content).AdditionalData.Add("test1", 123);
((IUmbracoEntity)content).AdditionalData.Add("test2", "hello");
var result = ss.ToStream(content);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
/*[Test]

View File

@@ -0,0 +1,367 @@
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Serialization;
using Umbraco.Tests.TestHelpers.Entities;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class ContentTypeTests
{
[Test]
public void Can_Deep_Clone_Content_Type_Sort()
{
var contentType = new ContentTypeSort(new Lazy<int>(() => 3), 4, "test");
var clone = (ContentTypeSort) contentType.DeepClone();
Assert.AreNotSame(clone, contentType);
Assert.AreEqual(clone, contentType);
Assert.AreEqual(clone.Id.Value, contentType.Id.Value);
Assert.AreEqual(clone.SortOrder, contentType.SortOrder);
Assert.AreEqual(clone.Alias, contentType.Alias);
}
[Test]
public void Can_Deep_Clone_Content_Type()
{
// Arrange
var contentType = MockedContentTypes.CreateTextpageContentType();
contentType.Id = 99;
var i = 200;
foreach (var propertyType in contentType.PropertyTypes)
{
propertyType.Id = ++i;
}
contentType.AllowedTemplates = new[] { new Template("-1,2", "Name", "name") { Id = 200 }, new Template("-1,3", "Name2", "name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] {new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2")};
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template("-1,2,3,4", "Test Template", "testTemplate")
{
Id = 88
});
contentType.Description = "test";
contentType.Icon = "icon";
contentType.IsContainer = true;
contentType.Thumbnail = "thumb";
contentType.Key = Guid.NewGuid();
contentType.Level = 3;
contentType.Path = "-1,4,10";
contentType.SortOrder = 5;
contentType.Trashed = false;
contentType.UpdateDate = DateTime.Now;
((IUmbracoEntity)contentType).AdditionalData.Add("test1", 123);
((IUmbracoEntity)contentType).AdditionalData.Add("test2", "hello");
// Act
var clone = (ContentType)contentType.DeepClone();
// Assert
Assert.AreNotSame(clone, contentType);
Assert.AreEqual(clone, contentType);
Assert.AreEqual(clone.Id, contentType.Id);
Assert.AreEqual(((IUmbracoEntity)clone).AdditionalData, ((IUmbracoEntity)contentType).AdditionalData);
Assert.AreEqual(clone.AllowedTemplates.Count(), contentType.AllowedTemplates.Count());
for (var index = 0; index < contentType.AllowedTemplates.Count(); index++)
{
Assert.AreNotSame(clone.AllowedTemplates.ElementAt(index), contentType.AllowedTemplates.ElementAt(index));
Assert.AreEqual(clone.AllowedTemplates.ElementAt(index), contentType.AllowedTemplates.ElementAt(index));
}
Assert.AreEqual(clone.PropertyGroups.Count, contentType.PropertyGroups.Count);
for (var index = 0; index < contentType.PropertyGroups.Count; index++)
{
Assert.AreNotSame(clone.PropertyGroups[index], contentType.PropertyGroups[index]);
Assert.AreEqual(clone.PropertyGroups[index], contentType.PropertyGroups[index]);
}
Assert.AreEqual(clone.PropertyTypes.Count(), contentType.PropertyTypes.Count());
for (var index = 0; index < contentType.PropertyTypes.Count(); index++)
{
Assert.AreNotSame(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index));
Assert.AreEqual(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index));
}
Assert.AreEqual(clone.CreateDate, contentType.CreateDate);
Assert.AreEqual(clone.CreatorId, contentType.CreatorId);
Assert.AreEqual(clone.Key, contentType.Key);
Assert.AreEqual(clone.Level, contentType.Level);
Assert.AreEqual(clone.Path, contentType.Path);
Assert.AreEqual(clone.SortOrder, contentType.SortOrder);
Assert.AreNotSame(clone.DefaultTemplate, contentType.DefaultTemplate);
Assert.AreEqual(clone.DefaultTemplate, contentType.DefaultTemplate);
Assert.AreEqual(clone.DefaultTemplateId, contentType.DefaultTemplateId);
Assert.AreEqual(clone.Trashed, contentType.Trashed);
Assert.AreEqual(clone.UpdateDate, contentType.UpdateDate);
Assert.AreEqual(clone.Thumbnail, contentType.Thumbnail);
Assert.AreEqual(clone.Icon, contentType.Icon);
Assert.AreEqual(clone.IsContainer, contentType.IsContainer);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(contentType, null));
}
}
[Test]
public void Can_Serialize_Content_Type_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
// Arrange
var contentType = MockedContentTypes.CreateTextpageContentType();
contentType.Id = 99;
var i = 200;
foreach (var propertyType in contentType.PropertyTypes)
{
propertyType.Id = ++i;
}
contentType.AllowedTemplates = new[] { new Template("-1,2", "Name", "name") { Id = 200 }, new Template("-1,3", "Name2", "name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template("-1,2,3,4", "Test Template", "testTemplate")
{
Id = 88
});
contentType.Description = "test";
contentType.Icon = "icon";
contentType.IsContainer = true;
contentType.Thumbnail = "thumb";
contentType.Key = Guid.NewGuid();
contentType.Level = 3;
contentType.Path = "-1,4,10";
contentType.SortOrder = 5;
contentType.Trashed = false;
contentType.UpdateDate = DateTime.Now;
((IUmbracoEntity)contentType).AdditionalData.Add("test1", 123);
((IUmbracoEntity)contentType).AdditionalData.Add("test2", "hello");
var result = ss.ToStream(contentType);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
[Test]
public void Can_Deep_Clone_Media_Type()
{
// Arrange
var contentType = MockedContentTypes.CreateImageMediaType();
contentType.Id = 99;
var i = 200;
foreach (var propertyType in contentType.PropertyTypes)
{
propertyType.Id = ++i;
}
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.Description = "test";
contentType.Icon = "icon";
contentType.IsContainer = true;
contentType.Thumbnail = "thumb";
contentType.Key = Guid.NewGuid();
contentType.Level = 3;
contentType.Path = "-1,4,10";
contentType.SortOrder = 5;
contentType.Trashed = false;
contentType.UpdateDate = DateTime.Now;
((IUmbracoEntity)contentType).AdditionalData.Add("test1", 123);
((IUmbracoEntity)contentType).AdditionalData.Add("test2", "hello");
// Act
var clone = (MediaType)contentType.DeepClone();
// Assert
Assert.AreNotSame(clone, contentType);
Assert.AreEqual(clone, contentType);
Assert.AreEqual(clone.Id, contentType.Id);
Assert.AreEqual(((IUmbracoEntity)clone).AdditionalData, ((IUmbracoEntity)contentType).AdditionalData);
Assert.AreEqual(clone.PropertyGroups.Count, contentType.PropertyGroups.Count);
for (var index = 0; index < contentType.PropertyGroups.Count; index++)
{
Assert.AreNotSame(clone.PropertyGroups[index], contentType.PropertyGroups[index]);
Assert.AreEqual(clone.PropertyGroups[index], contentType.PropertyGroups[index]);
}
Assert.AreEqual(clone.PropertyTypes.Count(), contentType.PropertyTypes.Count());
for (var index = 0; index < contentType.PropertyTypes.Count(); index++)
{
Assert.AreNotSame(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index));
Assert.AreEqual(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index));
}
Assert.AreEqual(clone.CreateDate, contentType.CreateDate);
Assert.AreEqual(clone.CreatorId, contentType.CreatorId);
Assert.AreEqual(clone.Key, contentType.Key);
Assert.AreEqual(clone.Level, contentType.Level);
Assert.AreEqual(clone.Path, contentType.Path);
Assert.AreEqual(clone.SortOrder, contentType.SortOrder);
Assert.AreEqual(clone.Trashed, contentType.Trashed);
Assert.AreEqual(clone.UpdateDate, contentType.UpdateDate);
Assert.AreEqual(clone.Thumbnail, contentType.Thumbnail);
Assert.AreEqual(clone.Icon, contentType.Icon);
Assert.AreEqual(clone.IsContainer, contentType.IsContainer);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(contentType, null));
}
}
[Test]
public void Can_Serialize_Media_Type_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
// Arrange
var contentType = MockedContentTypes.CreateImageMediaType();
contentType.Id = 99;
var i = 200;
foreach (var propertyType in contentType.PropertyTypes)
{
propertyType.Id = ++i;
}
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.Description = "test";
contentType.Icon = "icon";
contentType.IsContainer = true;
contentType.Thumbnail = "thumb";
contentType.Key = Guid.NewGuid();
contentType.Level = 3;
contentType.Path = "-1,4,10";
contentType.SortOrder = 5;
contentType.Trashed = false;
contentType.UpdateDate = DateTime.Now;
((IUmbracoEntity)contentType).AdditionalData.Add("test1", 123);
((IUmbracoEntity)contentType).AdditionalData.Add("test2", "hello");
var result = ss.ToStream(contentType);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
[Test]
public void Can_Deep_Clone_Member_Type()
{
// Arrange
var contentType = MockedContentTypes.CreateSimpleMemberType();
contentType.Id = 99;
var i = 200;
foreach (var propertyType in contentType.PropertyTypes)
{
propertyType.Id = ++i;
}
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.Description = "test";
contentType.Icon = "icon";
contentType.IsContainer = true;
contentType.Thumbnail = "thumb";
contentType.Key = Guid.NewGuid();
contentType.Level = 3;
contentType.Path = "-1,4,10";
contentType.SortOrder = 5;
contentType.Trashed = false;
contentType.UpdateDate = DateTime.Now;
contentType.SetMemberCanEditProperty("title", true);
contentType.SetMemberCanViewProperty("bodyText", true);
((IUmbracoEntity)contentType).AdditionalData.Add("test1", 123);
((IUmbracoEntity)contentType).AdditionalData.Add("test2", "hello");
// Act
var clone = (MemberType)contentType.DeepClone();
// Assert
Assert.AreNotSame(clone, contentType);
Assert.AreEqual(clone, contentType);
Assert.AreEqual(clone.Id, contentType.Id);
Assert.AreEqual(((IUmbracoEntity)clone).AdditionalData, ((IUmbracoEntity)contentType).AdditionalData);
Assert.AreEqual(clone.PropertyGroups.Count, contentType.PropertyGroups.Count);
for (var index = 0; index < contentType.PropertyGroups.Count; index++)
{
Assert.AreNotSame(clone.PropertyGroups[index], contentType.PropertyGroups[index]);
Assert.AreEqual(clone.PropertyGroups[index], contentType.PropertyGroups[index]);
}
Assert.AreEqual(clone.PropertyTypes.Count(), contentType.PropertyTypes.Count());
for (var index = 0; index < contentType.PropertyTypes.Count(); index++)
{
Assert.AreNotSame(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index));
Assert.AreEqual(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index));
}
Assert.AreEqual(clone.CreateDate, contentType.CreateDate);
Assert.AreEqual(clone.CreatorId, contentType.CreatorId);
Assert.AreEqual(clone.Key, contentType.Key);
Assert.AreEqual(clone.Level, contentType.Level);
Assert.AreEqual(clone.Path, contentType.Path);
Assert.AreEqual(clone.SortOrder, contentType.SortOrder);
Assert.AreEqual(clone.Trashed, contentType.Trashed);
Assert.AreEqual(clone.UpdateDate, contentType.UpdateDate);
Assert.AreEqual(clone.Thumbnail, contentType.Thumbnail);
Assert.AreEqual(clone.Icon, contentType.Icon);
Assert.AreEqual(clone.IsContainer, contentType.IsContainer);
Assert.AreEqual(clone.MemberTypePropertyTypes, contentType.MemberTypePropertyTypes);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(contentType, null));
}
}
[Test]
public void Can_Serialize_Member_Type_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
// Arrange
var contentType = MockedContentTypes.CreateSimpleMemberType();
contentType.Id = 99;
var i = 200;
foreach (var propertyType in contentType.PropertyTypes)
{
propertyType.Id = ++i;
}
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.Description = "test";
contentType.Icon = "icon";
contentType.IsContainer = true;
contentType.Thumbnail = "thumb";
contentType.Key = Guid.NewGuid();
contentType.Level = 3;
contentType.Path = "-1,4,10";
contentType.SortOrder = 5;
contentType.Trashed = false;
contentType.UpdateDate = DateTime.Now;
contentType.SetMemberCanEditProperty("title", true);
contentType.SetMemberCanViewProperty("bodyText", true);
((IUmbracoEntity)contentType).AdditionalData.Add("test1", 123);
((IUmbracoEntity)contentType).AdditionalData.Add("test2", "hello");
var result = ss.ToStream(contentType);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class DataTypeDefinitionTests
{
[Test]
public void Can_Deep_Clone()
{
var dtd = new DataTypeDefinition(9, Guid.NewGuid())
{
CreateDate = DateTime.Now,
CreatorId = 5,
DatabaseType = DataTypeDatabaseType.Nvarchar,
Id = 4,
Key = Guid.NewGuid(),
Level = 7,
Name = "Test",
ParentId = 9,
Path = "-1,2",
SortOrder = 8,
Trashed = true,
UpdateDate = DateTime.Now
};
var clone = (DataTypeDefinition) dtd.DeepClone();
Assert.AreNotSame(clone, dtd);
Assert.AreEqual(clone, dtd);
Assert.AreEqual(clone.CreateDate, dtd.CreateDate);
Assert.AreEqual(clone.CreatorId, dtd.CreatorId);
Assert.AreEqual(clone.DatabaseType, dtd.DatabaseType);
Assert.AreEqual(clone.Id, dtd.Id);
Assert.AreEqual(clone.Key, dtd.Key);
Assert.AreEqual(clone.Level, dtd.Level);
Assert.AreEqual(clone.Name, dtd.Name);
Assert.AreEqual(clone.ParentId, dtd.ParentId);
Assert.AreEqual(clone.Path, dtd.Path);
Assert.AreEqual(clone.SortOrder, dtd.SortOrder);
Assert.AreEqual(clone.Trashed, dtd.Trashed);
Assert.AreEqual(clone.UpdateDate, dtd.UpdateDate);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(dtd, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var dtd = new DataTypeDefinition(9, Guid.NewGuid())
{
CreateDate = DateTime.Now,
CreatorId = 5,
DatabaseType = DataTypeDatabaseType.Nvarchar,
Id = 4,
Key = Guid.NewGuid(),
Level = 7,
Name = "Test",
ParentId = 9,
Path = "-1,2",
SortOrder = 8,
Trashed = true,
UpdateDate = DateTime.Now
};
var result = ss.ToStream(dtd);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class DeepCloneHelperTests
{
[Test]
public void Deep_Clone_Ref_Properties()
{
var test1 = new Test1()
{
MyTest1 = new Test1(),
MyTest2 = new Test2()
};
var clone = (Test1)test1.DeepClone();
Assert.AreNotSame(test1, clone);
Assert.AreNotSame(test1.MyTest1, clone.MyTest1);
Assert.AreSame(test1.MyTest2, clone.MyTest2);
}
[Test]
public void Deep_Clone_Array_Property()
{
var test1 = new Test3()
{
MyTest1 = new object[] { new Test1(), new Test1() }
};
var clone = (Test3)test1.DeepClone();
Assert.AreNotSame(test1, clone);
Assert.AreEqual(test1.MyTest1.Count(), clone.MyTest1.Count());
for (int i = 0; i < test1.MyTest1.Count(); i++)
{
Assert.IsNotNull(clone.MyTest1.ElementAt(i));
Assert.AreNotSame(clone.MyTest1.ElementAt(i), test1.MyTest1.ElementAt(i));
}
}
[Test]
public void Deep_Clone_Typed_Array_Property()
{
var test1 = new Test4()
{
MyTest1 = new[] { new Test1(), new Test1() }
};
var clone = (Test4)test1.DeepClone();
Assert.AreNotSame(test1, clone);
Assert.AreEqual(test1.MyTest1.Count(), clone.MyTest1.Count());
for (int i = 0; i < test1.MyTest1.Count(); i++)
{
Assert.IsNotNull(clone.MyTest1.ElementAt(i));
Assert.AreNotSame(clone.MyTest1.ElementAt(i), test1.MyTest1.ElementAt(i));
}
}
[Test]
public void Deep_Clone_Enumerable_Property()
{
var test1 = new Test5()
{
MyTest1 = new[] { new Test1(), new Test1() }
};
var clone = (Test5)test1.DeepClone();
Assert.AreNotSame(test1, clone);
Assert.AreEqual(test1.MyTest1.Cast<object>().Count(), clone.MyTest1.Cast<object>().Count());
for (int i = 0; i < test1.MyTest1.Cast<object>().Count(); i++)
{
Assert.IsNotNull(clone.MyTest1.Cast<object>().ElementAt(i));
Assert.AreNotSame(clone.MyTest1.Cast<object>().ElementAt(i), test1.MyTest1.Cast<object>().ElementAt(i));
}
}
[Test]
public void Deep_Clone_Typed_Enumerable_Property()
{
var test1 = new Test6()
{
MyTest1 = new[] { new Test1(), new Test1() }
};
var clone = (Test6)test1.DeepClone();
Assert.AreNotSame(test1, clone);
Assert.AreEqual(test1.MyTest1.Count(), clone.MyTest1.Count());
for (int i = 0; i < test1.MyTest1.Count(); i++)
{
Assert.IsNotNull(clone.MyTest1.ElementAt(i));
Assert.AreNotSame(clone.MyTest1.ElementAt(i), test1.MyTest1.ElementAt(i));
}
}
[Test]
public void Deep_Clone_Custom_Enumerable_Property()
{
var test1 = new Test7()
{
MyTest1 = new List<Test1> { new Test1(), new Test1() }
};
var clone = (Test7)test1.DeepClone();
Assert.AreNotSame(test1, clone);
Assert.AreEqual(test1.MyTest1.Count(), clone.MyTest1.Count());
for (int i = 0; i < test1.MyTest1.Count(); i++)
{
Assert.IsNotNull(clone.MyTest1.ElementAt(i));
Assert.AreNotSame(clone.MyTest1.ElementAt(i), test1.MyTest1.ElementAt(i));
}
}
[Test]
public void Deep_Clone_Custom_Enumerable_Interface_Property()
{
var test1 = new Test8()
{
MyTest1 = new List<Test1> { new Test1(), new Test1() }
};
var clone = (Test8)test1.DeepClone();
Assert.AreNotSame(test1, clone);
Assert.AreEqual(test1.MyTest1.Count(), clone.MyTest1.Count());
for (int i = 0; i < test1.MyTest1.Count(); i++)
{
Assert.IsNotNull(clone.MyTest1.ElementAt(i));
Assert.AreNotSame(clone.MyTest1.ElementAt(i), test1.MyTest1.ElementAt(i));
}
}
[Test]
public void Cannot_Deep_Clone_Collection_Properties_That_Are_Not_Cloneable()
{
var test1 = new Test3()
{
MyTest1 = new object[]
{
new Test1(), "hello",
//not cloneable so this property will get skipped
new Test2()
}
};
var clone = (Test3)test1.DeepClone();
//it skipped this property so these will now be the same
Assert.AreSame(clone.MyTest1, test1.MyTest1);
}
public class Test1 : BaseCloneable
{
public string Name { get; set; }
public int Age { get; set; }
public Test1 MyTest1 { get; set; }
public Test2 MyTest2 { get; set; }
}
public class Test2
{
public string Name { get; set; }
public Test1 MyTest1 { get; set; }
}
public class Test3 : BaseCloneable
{
public string Name { get; set; }
public object[] MyTest1 { get; set; }
}
public class Test4 : BaseCloneable
{
public string Name { get; set; }
public Test1[] MyTest1 { get; set; }
}
public class Test5 : BaseCloneable
{
public string Name { get; set; }
public IEnumerable MyTest1 { get; set; }
}
public class Test6 : BaseCloneable
{
public string Name { get; set; }
public IEnumerable<Test1> MyTest1 { get; set; }
}
public class Test7 : BaseCloneable
{
public string Name { get; set; }
public List<Test1> MyTest1 { get; set; }
}
public class Test8 : BaseCloneable
{
public string Name { get; set; }
public ICollection<Test1> MyTest1 { get; set; }
}
public abstract class BaseCloneable : IDeepCloneable
{
public object DeepClone()
{
var clone = (IDeepCloneable)MemberwiseClone();
DeepCloneHelper.DeepCloneRefProperties(this, clone);
return clone;
}
}
}
}

View File

@@ -0,0 +1,136 @@
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class DictionaryItemTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new DictionaryItem("blah")
{
CreateDate = DateTime.Now,
Id = 8,
ItemKey = "blah",
Key = Guid.NewGuid(),
ParentId = Guid.NewGuid(),
UpdateDate = DateTime.Now,
Translations = new[]
{
new DictionaryTranslation(new Language("en-AU")
{
CreateDate = DateTime.Now,
CultureName = "en",
Id = 11,
IsoCode = "AU",
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
}, "colour")
{
CreateDate = DateTime.Now,
Id = 88,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
},
new DictionaryTranslation(new Language("en-US")
{
CreateDate = DateTime.Now,
CultureName = "en",
Id = 12,
IsoCode = "US",
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
}, "color")
{
CreateDate = DateTime.Now,
Id = 89,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
},
}
};
var clone = (DictionaryItem)item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreEqual(clone.CreateDate, item.CreateDate);
Assert.AreEqual(clone.Id, item.Id);
Assert.AreEqual(clone.ItemKey, item.ItemKey);
Assert.AreEqual(clone.Key, item.Key);
Assert.AreEqual(clone.ParentId, item.ParentId);
Assert.AreEqual(clone.UpdateDate, item.UpdateDate);
Assert.AreEqual(clone.Translations.Count(), item.Translations.Count());
for (var i = 0; i < item.Translations.Count(); i++)
{
Assert.AreNotSame(clone.Translations.ElementAt(i), item.Translations.ElementAt(i));
Assert.AreEqual(clone.Translations.ElementAt(i), item.Translations.ElementAt(i));
}
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new DictionaryItem("blah")
{
CreateDate = DateTime.Now,
Id = 8,
ItemKey = "blah",
Key = Guid.NewGuid(),
ParentId = Guid.NewGuid(),
UpdateDate = DateTime.Now,
Translations = new[]
{
new DictionaryTranslation(new Language("en-AU")
{
CreateDate = DateTime.Now,
CultureName = "en",
Id = 11,
IsoCode = "AU",
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
}, "colour")
{
CreateDate = DateTime.Now,
Id = 88,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
},
new DictionaryTranslation(new Language("en-US")
{
CreateDate = DateTime.Now,
CultureName = "en",
Id = 12,
IsoCode = "US",
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
}, "color")
{
CreateDate = DateTime.Now,
Id = 89,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
},
}
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,76 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class DictionaryTranslationTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new DictionaryTranslation(new Language("en-AU")
{
CreateDate = DateTime.Now,
CultureName = "en",
Id = 11,
IsoCode = "AU",
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
}, "colour")
{
CreateDate = DateTime.Now,
Id = 88,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
};
var clone = (DictionaryTranslation) item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreEqual(clone.CreateDate, item.CreateDate);
Assert.AreEqual(clone.Id, item.Id);
Assert.AreEqual(clone.Key, item.Key);
Assert.AreEqual(clone.UpdateDate, item.UpdateDate);
Assert.AreNotSame(clone.Language, item.Language);
Assert.AreEqual(clone.Language, item.Language);
Assert.AreEqual(clone.Value, item.Value);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new DictionaryTranslation(new Language("en-AU")
{
CreateDate = DateTime.Now,
CultureName = "en",
Id = 11,
IsoCode = "AU",
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
}, "colour")
{
CreateDate = DateTime.Now,
Id = 88,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,62 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class LanguageTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new Language("en-AU")
{
CreateDate = DateTime.Now,
CultureName = "AU",
Id = 11,
IsoCode = "en",
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
};
var clone = (Language) item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreEqual(clone.CreateDate, item.CreateDate);
Assert.AreEqual(clone.CultureName, item.CultureName);
Assert.AreEqual(clone.Id, item.Id);
Assert.AreEqual(clone.IsoCode, item.IsoCode);
Assert.AreEqual(clone.Key, item.Key);
Assert.AreEqual(clone.UpdateDate, item.UpdateDate);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new Language("en-AU")
{
CreateDate = DateTime.Now,
CultureName = "AU",
Id = 11,
IsoCode = "en",
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class MemberGroupTests
{
[Test]
public void Can_Deep_Clone()
{
// Arrange
var group = new MemberGroup()
{
CreateDate = DateTime.Now,
CreatorId = 4,
Id = 6,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
Name = "asdf"
};
group.AdditionalData.Add("test1", 123);
group.AdditionalData.Add("test2", "hello");
// Act
var clone = (MemberGroup)group.DeepClone();
// Assert
Assert.AreNotSame(clone, group);
Assert.AreEqual(clone, group);
Assert.AreEqual(clone.Id, group.Id);
Assert.AreEqual(clone.AdditionalData, group.AdditionalData);
Assert.AreEqual(clone.AdditionalData.Count, group.AdditionalData.Count);
Assert.AreEqual(clone.CreateDate, group.CreateDate);
Assert.AreEqual(clone.CreatorId, group.CreatorId);
Assert.AreEqual(clone.Key, group.Key);
Assert.AreEqual(clone.UpdateDate, group.UpdateDate);
Assert.AreEqual(clone.Name, group.Name);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(group, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var group = new MemberGroup()
{
CreateDate = DateTime.Now,
CreatorId = 4,
Id = 6,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
Name = "asdf"
};
group.AdditionalData.Add("test1", 123);
group.AdditionalData.Add("test2", "hello");
var result = ss.ToStream(group);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,156 @@
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Serialization;
using Umbraco.Tests.TestHelpers.Entities;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class MemberTests
{
[Test]
public void Can_Deep_Clone()
{
// Arrange
var memberType = MockedContentTypes.CreateSimpleMemberType("memberType", "Member Type");
memberType.Id = 99;
var member = MockedMember.CreateSimpleMember(memberType, "Name", "email@email.com", "pass", "user", Guid.NewGuid());
var i = 200;
foreach (var property in member.Properties)
{
property.Id = ++i;
}
member.Id = 10;
member.CreateDate = DateTime.Now;
member.CreatorId = 22;
member.Comments = "comments";
member.Key = Guid.NewGuid();
member.FailedPasswordAttempts = 22;
member.Level = 3;
member.Path = "-1,4,10";
member.Groups = new[] {"group1", "group2"};
member.IsApproved = true;
member.IsLockedOut = true;
member.LastLockoutDate = DateTime.Now;
member.LastLoginDate = DateTime.Now;
member.LastPasswordChangeDate = DateTime.Now;
member.PasswordQuestion = "question";
member.ProviderUserKey = Guid.NewGuid();
member.RawPasswordAnswerValue = "raw answer";
member.RawPasswordValue = "raw pass";
member.SortOrder = 5;
member.Trashed = false;
member.UpdateDate = DateTime.Now;
member.Version = Guid.NewGuid();
((IUmbracoEntity)member).AdditionalData.Add("test1", 123);
((IUmbracoEntity)member).AdditionalData.Add("test2", "hello");
// Act
var clone = (Member)member.DeepClone();
// Assert
Assert.AreNotSame(clone, member);
Assert.AreEqual(clone, member);
Assert.AreEqual(clone.Id, member.Id);
Assert.AreEqual(clone.Version, member.Version);
Assert.AreEqual(((IUmbracoEntity)clone).AdditionalData, ((IUmbracoEntity)member).AdditionalData);
Assert.AreNotSame(clone.ContentType, member.ContentType);
Assert.AreEqual(clone.ContentType, member.ContentType);
Assert.AreEqual(clone.ContentType.PropertyGroups.Count, member.ContentType.PropertyGroups.Count);
for (var index = 0; index < member.ContentType.PropertyGroups.Count; index++)
{
Assert.AreNotSame(clone.ContentType.PropertyGroups[index], member.ContentType.PropertyGroups[index]);
Assert.AreEqual(clone.ContentType.PropertyGroups[index], member.ContentType.PropertyGroups[index]);
}
Assert.AreEqual(clone.ContentType.PropertyTypes.Count(), member.ContentType.PropertyTypes.Count());
for (var index = 0; index < member.ContentType.PropertyTypes.Count(); index++)
{
Assert.AreNotSame(clone.ContentType.PropertyTypes.ElementAt(index), member.ContentType.PropertyTypes.ElementAt(index));
Assert.AreEqual(clone.ContentType.PropertyTypes.ElementAt(index), member.ContentType.PropertyTypes.ElementAt(index));
}
Assert.AreEqual(clone.ContentTypeId, member.ContentTypeId);
Assert.AreEqual(clone.CreateDate, member.CreateDate);
Assert.AreEqual(clone.CreatorId, member.CreatorId);
Assert.AreEqual(clone.Comments, member.Comments);
Assert.AreEqual(clone.Key, member.Key);
Assert.AreEqual(clone.FailedPasswordAttempts, member.FailedPasswordAttempts);
Assert.AreEqual(clone.Level, member.Level);
Assert.AreEqual(clone.Path, member.Path);
Assert.AreEqual(clone.Groups, member.Groups);
Assert.AreEqual(clone.Groups.Count(), member.Groups.Count());
Assert.AreEqual(clone.IsApproved, member.IsApproved);
Assert.AreEqual(clone.IsLockedOut, member.IsLockedOut);
Assert.AreEqual(clone.SortOrder, member.SortOrder);
Assert.AreEqual(clone.LastLockoutDate, member.LastLockoutDate);
Assert.AreNotSame(clone.LastLoginDate, member.LastLoginDate);
Assert.AreEqual(clone.LastPasswordChangeDate, member.LastPasswordChangeDate);
Assert.AreEqual(clone.Trashed, member.Trashed);
Assert.AreEqual(clone.UpdateDate, member.UpdateDate);
Assert.AreEqual(clone.Version, member.Version);
Assert.AreEqual(clone.PasswordQuestion, member.PasswordQuestion);
Assert.AreEqual(clone.ProviderUserKey, member.ProviderUserKey);
Assert.AreEqual(clone.RawPasswordAnswerValue, member.RawPasswordAnswerValue);
Assert.AreEqual(clone.RawPasswordValue, member.RawPasswordValue);
Assert.AreNotSame(clone.Properties, member.Properties);
Assert.AreEqual(clone.Properties.Count(), member.Properties.Count());
for (var index = 0; index < member.Properties.Count; index++)
{
Assert.AreNotSame(clone.Properties[index], member.Properties[index]);
Assert.AreEqual(clone.Properties[index], member.Properties[index]);
}
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(member, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var memberType = MockedContentTypes.CreateSimpleMemberType("memberType", "Member Type");
memberType.Id = 99;
var member = MockedMember.CreateSimpleMember(memberType, "Name", "email@email.com", "pass", "user", Guid.NewGuid());
var i = 200;
foreach (var property in member.Properties)
{
property.Id = ++i;
}
member.Id = 10;
member.CreateDate = DateTime.Now;
member.CreatorId = 22;
member.Comments = "comments";
member.Key = Guid.NewGuid();
member.FailedPasswordAttempts = 22;
member.Level = 3;
member.Path = "-1,4,10";
member.Groups = new[] { "group1", "group2" };
member.IsApproved = true;
member.IsLockedOut = true;
member.LastLockoutDate = DateTime.Now;
member.LastLoginDate = DateTime.Now;
member.LastPasswordChangeDate = DateTime.Now;
member.PasswordQuestion = "question";
member.ProviderUserKey = Guid.NewGuid();
member.RawPasswordAnswerValue = "raw answer";
member.RawPasswordValue = "raw pass";
member.SortOrder = 5;
member.Trashed = false;
member.UpdateDate = DateTime.Now;
member.Version = Guid.NewGuid();
((IUmbracoEntity)member).AdditionalData.Add("test1", 123);
((IUmbracoEntity)member).AdditionalData.Add("test2", "hello");
var result = ss.ToStream(member);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,148 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class PropertyGroupTests
{
[Test]
public void Can_Deep_Clone()
{
var pg = new PropertyGroup(
new PropertyTypeCollection(new[]
{
new PropertyType("TestPropertyEditor", DataTypeDatabaseType.Nvarchar)
{
Id = 3,
Alias = "test",
CreateDate = DateTime.Now,
DataTypeDefinitionId = 5,
DataTypeId = Guid.NewGuid(),
Description = "testing",
Key = Guid.NewGuid(),
Mandatory = true,
Name = "Test",
PropertyGroupId = new Lazy<int>(() => 11),
SortOrder = 9,
UpdateDate = DateTime.Now,
ValidationRegExp = "xxxx",
DataTypeDatabaseType = DataTypeDatabaseType.Nvarchar
},
new PropertyType("TestPropertyEditor", DataTypeDatabaseType.Nvarchar)
{
Id = 4,
Alias = "test2",
CreateDate = DateTime.Now,
DataTypeDefinitionId = 6,
DataTypeId = Guid.NewGuid(),
Description = "testing2",
Key = Guid.NewGuid(),
Mandatory = true,
Name = "Test2",
PropertyGroupId = new Lazy<int>(() => 12),
SortOrder = 10,
UpdateDate = DateTime.Now,
ValidationRegExp = "yyyy",
DataTypeDatabaseType = DataTypeDatabaseType.Nvarchar
}
}))
{
Id = 77,
CreateDate = DateTime.Now,
Key = Guid.NewGuid(),
Name = "Group1",
SortOrder = 555,
UpdateDate = DateTime.Now,
ParentId = 9
};
var clone = (PropertyGroup)pg.DeepClone();
Assert.AreNotSame(clone, pg);
Assert.AreEqual(clone, pg);
Assert.AreEqual(clone.Id, pg.Id);
Assert.AreEqual(clone.CreateDate, pg.CreateDate);
Assert.AreEqual(clone.Key, pg.Key);
Assert.AreEqual(clone.Name, pg.Name);
Assert.AreEqual(clone.SortOrder, pg.SortOrder);
Assert.AreEqual(clone.UpdateDate, pg.UpdateDate);
Assert.AreEqual(clone.ParentId, pg.ParentId);
Assert.AreNotSame(clone.PropertyTypes, pg.PropertyTypes);
Assert.AreEqual(clone.PropertyTypes, pg.PropertyTypes);
Assert.AreEqual(clone.PropertyTypes.Count, pg.PropertyTypes.Count);
for (var i = 0; i < pg.PropertyTypes.Count; i++)
{
Assert.AreNotSame(clone.PropertyTypes[i], pg.PropertyTypes[i]);
Assert.AreEqual(clone.PropertyTypes[i], pg.PropertyTypes[i]);
}
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(pg, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var pg = new PropertyGroup(
new PropertyTypeCollection(new[]
{
new PropertyType("TestPropertyEditor", DataTypeDatabaseType.Nvarchar)
{
Id = 3,
Alias = "test",
CreateDate = DateTime.Now,
DataTypeDefinitionId = 5,
DataTypeId = Guid.NewGuid(),
Description = "testing",
Key = Guid.NewGuid(),
Mandatory = true,
Name = "Test",
PropertyGroupId = new Lazy<int>(() => 11),
SortOrder = 9,
UpdateDate = DateTime.Now,
ValidationRegExp = "xxxx",
DataTypeDatabaseType = DataTypeDatabaseType.Nvarchar
},
new PropertyType("TestPropertyEditor2", DataTypeDatabaseType.Nvarchar)
{
Id = 4,
Alias = "test2",
CreateDate = DateTime.Now,
DataTypeDefinitionId = 6,
DataTypeId = Guid.NewGuid(),
Description = "testing2",
Key = Guid.NewGuid(),
Mandatory = true,
Name = "Test2",
PropertyGroupId = new Lazy<int>(() => 12),
SortOrder = 10,
UpdateDate = DateTime.Now,
ValidationRegExp = "yyyy",
DataTypeDatabaseType = DataTypeDatabaseType.Nvarchar
}
}))
{
Id = 77,
CreateDate = DateTime.Now,
Key = Guid.NewGuid(),
Name = "Group1",
SortOrder = 555,
UpdateDate = DateTime.Now,
ParentId = 9
};
var result = ss.ToStream(pg);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,88 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class PropertyTypeTests
{
[Test]
public void Can_Deep_Clone()
{
var pt = new PropertyType("TestPropertyEditor", DataTypeDatabaseType.Nvarchar)
{
Id = 3,
Alias = "test",
CreateDate = DateTime.Now,
DataTypeDefinitionId = 5,
DataTypeId = Guid.NewGuid(),
Description = "testing",
Key = Guid.NewGuid(),
Mandatory = true,
Name = "Test",
PropertyGroupId = new Lazy<int>(() => 11),
SortOrder = 9,
UpdateDate = DateTime.Now,
ValidationRegExp = "xxxx",
DataTypeDatabaseType = DataTypeDatabaseType.Nvarchar
};
var clone = (PropertyType)pt.DeepClone();
Assert.AreNotSame(clone, pt);
Assert.AreEqual(clone, pt);
Assert.AreEqual(clone.Id, pt.Id);
Assert.AreEqual(clone.Alias, pt.Alias);
Assert.AreEqual(clone.CreateDate, pt.CreateDate);
Assert.AreEqual(clone.DataTypeDefinitionId, pt.DataTypeDefinitionId);
Assert.AreEqual(clone.DataTypeId, pt.DataTypeId);
Assert.AreEqual(clone.Description, pt.Description);
Assert.AreEqual(clone.Key, pt.Key);
Assert.AreEqual(clone.Mandatory, pt.Mandatory);
Assert.AreEqual(clone.Name, pt.Name);
Assert.AreEqual(clone.PropertyGroupId.Value, pt.PropertyGroupId.Value);
Assert.AreEqual(clone.SortOrder, pt.SortOrder);
Assert.AreEqual(clone.UpdateDate, pt.UpdateDate);
Assert.AreEqual(clone.ValidationRegExp, pt.ValidationRegExp);
Assert.AreEqual(clone.DataTypeDatabaseType, pt.DataTypeDatabaseType);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(pt, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var pt = new PropertyType("TestPropertyEditor", DataTypeDatabaseType.Nvarchar)
{
Id = 3,
Alias = "test",
CreateDate = DateTime.Now,
DataTypeDefinitionId = 5,
DataTypeId = Guid.NewGuid(),
Description = "testing",
Key = Guid.NewGuid(),
Mandatory = true,
Name = "Test",
PropertyGroupId = new Lazy<int>(() => 11),
SortOrder = 9,
UpdateDate = DateTime.Now,
ValidationRegExp = "xxxx",
DataTypeDatabaseType = DataTypeDatabaseType.Nvarchar
};
var result = ss.ToStream(pt);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class RelationTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new Relation(9, 8, new RelationType(Guid.NewGuid(), Guid.NewGuid(), "test")
{
Id = 66
})
{
Comment = "test comment",
CreateDate = DateTime.Now,
Id = 4,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
};
var clone = (Relation) item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreEqual(clone.ChildId, item.ChildId);
Assert.AreEqual(clone.Comment, item.Comment);
Assert.AreEqual(clone.CreateDate, item.CreateDate);
Assert.AreEqual(clone.Id, item.Id);
Assert.AreEqual(clone.Key, item.Key);
Assert.AreEqual(clone.ParentId, item.ParentId);
Assert.AreNotSame(clone.RelationType, item.RelationType);
Assert.AreEqual(clone.RelationType, item.RelationType);
Assert.AreEqual(clone.RelationTypeId, item.RelationTypeId);
Assert.AreEqual(clone.UpdateDate, item.UpdateDate);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new Relation(9, 8, new RelationType(Guid.NewGuid(), Guid.NewGuid(), "test")
{
Id = 66
})
{
Comment = "test comment",
CreateDate = DateTime.Now,
Id = 4,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class RelationTypeTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new RelationType(Guid.NewGuid(), Guid.NewGuid(), "test")
{
Id = 66,
CreateDate = DateTime.Now,
IsBidirectional = true,
Key = Guid.NewGuid(),
Name = "Test",
UpdateDate = DateTime.Now
};
var clone = (RelationType)item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreEqual(clone.Alias, item.Alias);
Assert.AreEqual(clone.ChildObjectType, item.ChildObjectType);
Assert.AreEqual(clone.IsBidirectional, item.IsBidirectional);
Assert.AreEqual(clone.Id, item.Id);
Assert.AreEqual(clone.Key, item.Key);
Assert.AreEqual(clone.Name, item.Name);
Assert.AreNotSame(clone.ParentObjectType, item.ParentObjectType);
Assert.AreEqual(clone.UpdateDate, item.UpdateDate);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new RelationType(Guid.NewGuid(), Guid.NewGuid(), "test")
{
Id = 66,
CreateDate = DateTime.Now,
IsBidirectional = true,
Key = Guid.NewGuid(),
Name = "Test",
UpdateDate = DateTime.Now
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -1,6 +1,8 @@
using System.Linq;
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
@@ -128,5 +130,22 @@ namespace Umbraco.Tests.Models
Assert.That(properties, Is.Not.Null);
Assert.That(properties.Any(), Is.True);
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var stylesheet = new Stylesheet("/css/styles.css");
stylesheet.Content = @"@media screen and (min-width: 600px) and (min-width: 900px) {
.class {
background: #666;
}
}";
var result = ss.ToStream(stylesheet);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,77 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class TaskTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new Task(new TaskType("test") {Id = 3})
{
AssigneeUserId = 4,
Closed = true,
Comment = "blah",
CreateDate = DateTime.Now,
EntityId = 99,
Id = 2,
Key = Guid.NewGuid(),
OwnerUserId = 89,
TaskType = new TaskType("asdf") {Id = 99},
UpdateDate = DateTime.Now
};
var clone = (Task) item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreEqual(clone.CreateDate, item.CreateDate);
Assert.AreEqual(clone.UpdateDate, item.UpdateDate);
Assert.AreEqual(clone.AssigneeUserId, item.AssigneeUserId);
Assert.AreEqual(clone.Closed, item.Closed);
Assert.AreEqual(clone.Comment, item.Comment);
Assert.AreEqual(clone.EntityId, item.EntityId);
Assert.AreEqual(clone.Id, item.Id);
Assert.AreEqual(clone.Key, item.Key);
Assert.AreEqual(clone.OwnerUserId, item.OwnerUserId);
Assert.AreNotSame(clone.TaskType, item.TaskType);
Assert.AreEqual(clone.TaskType, item.TaskType);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new Task(new TaskType("test") { Id = 3 })
{
AssigneeUserId = 4,
Closed = true,
Comment = "blah",
CreateDate = DateTime.Now,
EntityId = 99,
Id = 2,
Key = Guid.NewGuid(),
OwnerUserId = 89,
TaskType = new TaskType("asdf") { Id = 99 },
UpdateDate = DateTime.Now
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class TaskTypeTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new TaskType("test")
{
Id = 3,
Alias = "test",
CreateDate = DateTime.Now,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
};
var clone = (TaskType)item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreEqual(clone.CreateDate, item.CreateDate);
Assert.AreEqual(clone.Id, item.Id);
Assert.AreEqual(clone.Key, item.Key);
Assert.AreEqual(clone.Alias, item.Alias);
Assert.AreEqual(clone.UpdateDate, item.UpdateDate);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new TaskType("test")
{
Id = 3,
Alias = "test",
CreateDate = DateTime.Now,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,80 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class TemplateTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new Template("-1,2,3", "Test", "test")
{
Id = 3,
CreateDate = DateTime.Now,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
Content = "blah",
CreatorId = 66,
Level = 55,
ParentId = 2,
SortOrder = 99,
MasterTemplateAlias = "master",
MasterTemplateId = new Lazy<int>(() => 88)
};
var clone = (Template)item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreEqual(clone.CreateDate, item.CreateDate);
Assert.AreEqual(clone.Alias, item.Alias);
Assert.AreEqual(clone.CreatorId, item.CreatorId);
Assert.AreEqual(clone.Id, item.Id);
Assert.AreEqual(clone.Key, item.Key);
Assert.AreEqual(clone.Level, item.Level);
Assert.AreEqual(clone.MasterTemplateAlias, item.MasterTemplateAlias);
Assert.AreEqual(clone.MasterTemplateId.Value, item.MasterTemplateId.Value);
Assert.AreEqual(clone.Name, item.Name);
Assert.AreEqual(clone.ParentId, item.ParentId);
Assert.AreEqual(clone.SortOrder, item.SortOrder);
Assert.AreEqual(clone.UpdateDate, item.UpdateDate);
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new Template("-1,2,3", "Test", "test")
{
Id = 3,
CreateDate = DateTime.Now,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
Content = "blah",
CreatorId = 66,
Level = 55,
ParentId = 2,
SortOrder = 99,
MasterTemplateAlias = "master",
MasterTemplateId = new Lazy<int>(() => 88)
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
@@ -19,5 +20,125 @@ namespace Umbraco.Tests.Models
Assert.IsTrue(trashedWithBool.Trashed);
Assert.IsTrue(trashedWithInt.Trashed);
}
[Test]
public void Can_Deep_Clone()
{
var item = new UmbracoEntity()
{
Id = 3,
ContentTypeAlias = "test1",
CreatorId = 4,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
CreateDate = DateTime.Now,
Name = "Test",
ParentId = 5,
SortOrder = 6,
Path = "-1,23",
Level = 7,
ContentTypeIcon = "icon",
ContentTypeThumbnail = "thumb",
HasChildren = true,
HasPendingChanges = true,
IsDraft = true,
IsPublished = true,
NodeObjectTypeId = Guid.NewGuid()
};
item.AdditionalData.Add("test1", 3);
item.AdditionalData.Add("test2", "valuie");
item.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty()
{
Value = "test",
PropertyEditorAlias = "TestPropertyEditor"
});
item.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty()
{
Value = "test2",
PropertyEditorAlias = "TestPropertyEditor2"
});
var clone = (UmbracoEntity)item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreEqual(clone.CreateDate, item.CreateDate);
Assert.AreEqual(clone.ContentTypeAlias, item.ContentTypeAlias);
Assert.AreEqual(clone.CreatorId, item.CreatorId);
Assert.AreEqual(clone.Id, item.Id);
Assert.AreEqual(clone.Key, item.Key);
Assert.AreEqual(clone.Level, item.Level);
Assert.AreEqual(clone.Name, item.Name);
Assert.AreEqual(clone.ParentId, item.ParentId);
Assert.AreEqual(clone.SortOrder, item.SortOrder);
Assert.AreEqual(clone.Path, item.Path);
Assert.AreEqual(clone.ContentTypeIcon, item.ContentTypeIcon);
Assert.AreEqual(clone.ContentTypeThumbnail, item.ContentTypeThumbnail);
Assert.AreEqual(clone.HasChildren, item.HasChildren);
Assert.AreEqual(clone.HasPendingChanges, item.HasPendingChanges);
Assert.AreEqual(clone.IsDraft, item.IsDraft);
Assert.AreEqual(clone.IsPublished, item.IsPublished);
Assert.AreEqual(clone.NodeObjectTypeId, item.NodeObjectTypeId);
Assert.AreEqual(clone.UpdateDate, item.UpdateDate);
Assert.AreEqual(clone.AdditionalData.Count, item.AdditionalData.Count);
Assert.AreEqual(clone.AdditionalData, item.AdditionalData);
Assert.AreEqual(clone.UmbracoProperties.Count, item.UmbracoProperties.Count);
for (var i = 0; i < clone.UmbracoProperties.Count; i++)
{
Assert.AreNotSame(clone.UmbracoProperties[i], item.UmbracoProperties[i]);
Assert.AreEqual(clone.UmbracoProperties[i], item.UmbracoProperties[i]);
}
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new UmbracoEntity()
{
Id = 3,
ContentTypeAlias = "test1",
CreatorId = 4,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
CreateDate = DateTime.Now,
Name = "Test",
ParentId = 5,
SortOrder = 6,
Path = "-1,23",
Level = 7,
ContentTypeIcon = "icon",
ContentTypeThumbnail = "thumb",
HasChildren = true,
HasPendingChanges = true,
IsDraft = true,
IsPublished = true,
NodeObjectTypeId = Guid.NewGuid()
};
item.AdditionalData.Add("test1", 3);
item.AdditionalData.Add("test2", "valuie");
item.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty()
{
Value = "test",
PropertyEditorAlias = "TestPropertyEditor"
});
item.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty()
{
Value = "test2",
PropertyEditorAlias = "TestPropertyEditor2"
});
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class UserTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new User(new UserType(){Id = 3})
{
Id = 3,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
CreateDate = DateTime.Now,
Name = "Test",
Comments = "comments",
DefaultPermissions = new[]{"a","b","c"},
DefaultToLiveEditing = false,
Email = "test@test.com",
Language = "en",
FailedPasswordAttempts = 3,
IsApproved = true,
IsLockedOut = true,
LastLockoutDate = DateTime.Now,
LastLoginDate = DateTime.Now,
LastPasswordChangeDate = DateTime.Now,
//Password = "test pass",
//PasswordAnswer = "answer",
PasswordQuestion = "question",
//ProviderUserKey = "user key",
SessionTimeout = 5,
StartContentId = 3,
StartMediaId = 8,
Username = "username"
};
var clone = (User)item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
Assert.AreNotSame(clone.UserType, item.UserType);
Assert.AreEqual(clone.UserType, item.UserType);
//Verify normal properties with reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new User(new UserType() { Id = 3 })
{
Id = 3,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
CreateDate = DateTime.Now,
Name = "Test",
Comments = "comments",
DefaultPermissions = new[] { "a", "b", "c" },
DefaultToLiveEditing = false,
Email = "test@test.com",
Language = "en",
FailedPasswordAttempts = 3,
IsApproved = true,
IsLockedOut = true,
LastLockoutDate = DateTime.Now,
LastLoginDate = DateTime.Now,
LastPasswordChangeDate = DateTime.Now,
//Password = "test pass",
//PasswordAnswer = "answer",
PasswordQuestion = "question",
//ProviderUserKey = "user key",
SessionTimeout = 5,
StartContentId = 3,
StartMediaId = 8,
Username = "username"
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class UserTypeTests
{
[Test]
public void Can_Deep_Clone()
{
var item = new UserType()
{
Id = 3,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
CreateDate = DateTime.Now,
Name = "Test",
Alias = "test",
Permissions = new[] {"a", "b", "c"}
};
var clone = (UserType)item.DeepClone();
Assert.AreNotSame(clone, item);
Assert.AreEqual(clone, item);
//Verify normal properties with reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null));
}
}
[Test]
public void Can_Serialize_Without_Error()
{
var ss = new SerializationService(new JsonNetSerializer());
var item = new UserType()
{
Id = 3,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now,
CreateDate = DateTime.Now,
Name = "Test",
Alias = "test",
Permissions = new[] { "a", "b", "c" }
};
var result = ss.ToStream(item);
var json = result.ResultStream.ToJsonString();
Console.WriteLine(json);
}
}
}

View File

@@ -3,14 +3,16 @@ using System.Data;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Tests.TestHelpers;
using NullCacheProvider = Umbraco.Core.Persistence.Caching.NullCacheProvider;
namespace Umbraco.Tests.Persistence.Repositories
{
@@ -26,7 +28,10 @@ namespace Umbraco.Tests.Persistence.Repositories
private DataTypeDefinitionRepository CreateRepository(IDatabaseUnitOfWork unitOfWork)
{
var dataTypeDefinitionRepository = new DataTypeDefinitionRepository(unitOfWork, NullCacheProvider.Current);
var dataTypeDefinitionRepository = new DataTypeDefinitionRepository(
unitOfWork, NullCacheProvider.Current, CacheHelper.CreateDisabledCacheHelper(),
new ContentTypeRepository(unitOfWork, NullCacheProvider.Current,
new TemplateRepository(unitOfWork, NullCacheProvider.Current)));
return dataTypeDefinitionRepository;
}
@@ -304,6 +309,137 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
[Test]
public void Can_Get_Pre_Value_Collection()
{
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
int dtid;
using (var repository = CreateRepository(unitOfWork))
{
var dataTypeDefinition = new DataTypeDefinition(-1, new Guid(Constants.PropertyEditors.RadioButtonList)) { Name = "test" };
repository.AddOrUpdate(dataTypeDefinition);
unitOfWork.Commit();
dtid = dataTypeDefinition.Id;
}
DatabaseContext.Database.Insert(new DataTypePreValueDto() { DataTypeNodeId = dtid, SortOrder = 0, Value = "test1"});
DatabaseContext.Database.Insert(new DataTypePreValueDto() { DataTypeNodeId = dtid, SortOrder = 1, Value = "test2" });
using (var repository = CreateRepository(unitOfWork))
{
var collection = repository.GetPreValuesCollectionByDataTypeId(dtid);
Assert.AreEqual(2, collection.PreValuesAsArray.Count());
}
}
[Test]
public void Can_Get_Pre_Value_As_String()
{
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
int dtid;
using (var repository = CreateRepository(unitOfWork))
{
var dataTypeDefinition = new DataTypeDefinition(-1, new Guid(Constants.PropertyEditors.RadioButtonList)) { Name = "test" };
repository.AddOrUpdate(dataTypeDefinition);
unitOfWork.Commit();
dtid = dataTypeDefinition.Id;
}
var id = DatabaseContext.Database.Insert(new DataTypePreValueDto() { DataTypeNodeId = dtid, SortOrder = 0, Value = "test1" });
DatabaseContext.Database.Insert(new DataTypePreValueDto() { DataTypeNodeId = dtid, SortOrder = 1, Value = "test2" });
using (var repository = CreateRepository(unitOfWork))
{
var val = repository.GetPreValueAsString(Convert.ToInt32(id));
Assert.AreEqual("test1", val);
}
}
[Test]
public void Can_Get_Pre_Value_Collection_With_Cache()
{
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var cache = new CacheHelper(new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), new StaticCacheProvider());
Func<DataTypeDefinitionRepository> creator = () => new DataTypeDefinitionRepository(
unitOfWork, NullCacheProvider.Current, cache,
new ContentTypeRepository(unitOfWork, NullCacheProvider.Current,
new TemplateRepository(unitOfWork, NullCacheProvider.Current)));
DataTypeDefinition dtd;
using (var repository = creator())
{
dtd = new DataTypeDefinition(-1, new Guid(Constants.PropertyEditors.RadioButtonList)) { Name = "test" };
repository.AddOrUpdate(dtd);
unitOfWork.Commit();
}
DatabaseContext.Database.Insert(new DataTypePreValueDto() { DataTypeNodeId = dtd.Id, SortOrder = 0, Value = "test1" });
DatabaseContext.Database.Insert(new DataTypePreValueDto() { DataTypeNodeId = dtd.Id, SortOrder = 1, Value = "test2" });
//this will cache the result
using (var repository = creator())
{
var collection = repository.GetPreValuesCollectionByDataTypeId(dtd.Id);
}
var cached = cache.RuntimeCache.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-");
Assert.IsNotNull(cached);
Assert.AreEqual(1, cached.Count());
Assert.AreEqual(2, cached.Single().FormatAsDictionary().Count);
}
[Test]
public void Can_Get_Pre_Value_As_String_With_Cache()
{
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var cache = new CacheHelper(new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), new StaticCacheProvider());
Func<DataTypeDefinitionRepository> creator = () => new DataTypeDefinitionRepository(
unitOfWork, NullCacheProvider.Current, cache,
new ContentTypeRepository(unitOfWork, NullCacheProvider.Current,
new TemplateRepository(unitOfWork, NullCacheProvider.Current)));
DataTypeDefinition dtd;
using (var repository = creator())
{
dtd = new DataTypeDefinition(-1, new Guid(Constants.PropertyEditors.RadioButtonList)) { Name = "test" };
repository.AddOrUpdate(dtd);
unitOfWork.Commit();
}
var id = DatabaseContext.Database.Insert(new DataTypePreValueDto() { DataTypeNodeId = dtd.Id, SortOrder = 0, Value = "test1" });
DatabaseContext.Database.Insert(new DataTypePreValueDto() { DataTypeNodeId = dtd.Id, SortOrder = 1, Value = "test2" });
//this will cache the result
using (var repository = creator())
{
var val = repository.GetPreValueAsString(Convert.ToInt32(id));
}
var cached = cache.RuntimeCache.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-");
Assert.IsNotNull(cached);
Assert.AreEqual(1, cached.Count());
Assert.AreEqual(2, cached.Single().FormatAsDictionary().Count);
using (var repository = creator())
{
//ensure it still gets resolved!
var val = repository.GetPreValueAsString(Convert.ToInt32(id));
Assert.AreEqual("test1", val);
}
}
[TearDown]
public override void TearDown()
{

View File

@@ -75,6 +75,36 @@ namespace Umbraco.Tests.Services
var dataTypeService = ServiceContext.DataTypeService;
var textfieldId = new Guid("ec15c1e5-9d90-422a-aa52-4f7622c63bea");
// Act
IDataTypeDefinition dataTypeDefinition = new DataTypeDefinition(-1, textfieldId) { Name = "Testing prevals", DatabaseType = DataTypeDatabaseType.Ntext };
dataTypeService.Save(dataTypeDefinition);
dataTypeService.SavePreValues(dataTypeDefinition, new Dictionary<string, PreValue>
{
{"preVal1", new PreValue("Hello")},
{"preVal2", new PreValue("World")}
});
//re-get
dataTypeDefinition = dataTypeService.GetDataTypeDefinitionById(dataTypeDefinition.Id);
var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeDefinition.Id);
// Assert
Assert.That(dataTypeDefinition, Is.Not.Null);
Assert.That(dataTypeDefinition.HasIdentity, Is.True);
Assert.AreEqual(true, preVals.IsDictionaryBased);
Assert.AreEqual(2, preVals.PreValuesAsDictionary.Keys.Count);
Assert.AreEqual("preVal1", preVals.PreValuesAsDictionary.Keys.First());
Assert.AreEqual("preVal2", preVals.PreValuesAsDictionary.Keys.Last());
Assert.AreEqual("Hello", preVals.PreValuesAsDictionary["preVal1"].Value);
Assert.AreEqual("World", preVals.PreValuesAsDictionary["preVal2"].Value);
}
[Test]
public void DataTypeService_Can_Persist_Dtd_And_Dictionary_Based_Pre_Values()
{
// Arrange
var dataTypeService = ServiceContext.DataTypeService;
var textfieldId = new Guid("ec15c1e5-9d90-422a-aa52-4f7622c63bea");
// Act
IDataTypeDefinition dataTypeDefinition = new DataTypeDefinition(-1, textfieldId) { Name = "Testing prevals", DatabaseType = DataTypeDatabaseType.Ntext };
dataTypeService.SaveDataTypeAndPreValues(dataTypeDefinition, new Dictionary<string, PreValue>
@@ -97,6 +127,77 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("World", preVals.PreValuesAsDictionary["preVal2"].Value);
}
[Test]
public void DataTypeService_Can_Update_Pre_Values()
{
// Arrange
var dataTypeService = ServiceContext.DataTypeService;
var textfieldId = new Guid("ec15c1e5-9d90-422a-aa52-4f7622c63bea");
// Act
IDataTypeDefinition dataTypeDefinition = new DataTypeDefinition(-1, textfieldId) { Name = "Testing prevals", DatabaseType = DataTypeDatabaseType.Ntext };
dataTypeService.SaveDataTypeAndPreValues(dataTypeDefinition, new Dictionary<string, PreValue>
{
{"preVal1", new PreValue("Hello")},
{"preVal2", new PreValue("World")}
});
//re-get
dataTypeDefinition = dataTypeService.GetDataTypeDefinitionById(dataTypeDefinition.Id);
var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeDefinition.Id);
//update them (ensure Ids are there!)
var asDictionary = preVals.FormatAsDictionary();
asDictionary["preVal1"].Value = "Hello2";
asDictionary["preVal2"].Value = "World2";
dataTypeService.SavePreValues(dataTypeDefinition, asDictionary);
var preValsAgain = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeDefinition.Id);
// Assert
Assert.AreEqual(preVals.PreValuesAsDictionary.Values.First().Id, preValsAgain.PreValuesAsDictionary.Values.First().Id);
Assert.AreEqual(preVals.PreValuesAsDictionary.Values.Last().Id, preValsAgain.PreValuesAsDictionary.Values.Last().Id);
Assert.AreEqual("preVal1", preValsAgain.PreValuesAsDictionary.Keys.First());
Assert.AreEqual("preVal2", preValsAgain.PreValuesAsDictionary.Keys.Last());
Assert.AreEqual("Hello2", preValsAgain.PreValuesAsDictionary["preVal1"].Value);
Assert.AreEqual("World2", preValsAgain.PreValuesAsDictionary["preVal2"].Value);
}
[Test]
public void DataTypeService_Can_Remove_Pre_Value()
{
// Arrange
var dataTypeService = ServiceContext.DataTypeService;
var textfieldId = new Guid("ec15c1e5-9d90-422a-aa52-4f7622c63bea");
// Act
IDataTypeDefinition dataTypeDefinition = new DataTypeDefinition(-1, textfieldId) { Name = "Testing prevals", DatabaseType = DataTypeDatabaseType.Ntext };
dataTypeService.SaveDataTypeAndPreValues(dataTypeDefinition, new Dictionary<string, PreValue>
{
{"preVal1", new PreValue("Hello")},
{"preVal2", new PreValue("World")}
});
//re-get
dataTypeDefinition = dataTypeService.GetDataTypeDefinitionById(dataTypeDefinition.Id);
var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeDefinition.Id);
//update them (ensure Ids are there!)
var asDictionary = preVals.FormatAsDictionary();
asDictionary.Remove("preVal2");
dataTypeService.SavePreValues(dataTypeDefinition, asDictionary);
var preValsAgain = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeDefinition.Id);
// Assert
Assert.AreEqual(1, preValsAgain.FormatAsDictionary().Count);
Assert.AreEqual(preVals.PreValuesAsDictionary.Values.First().Id, preValsAgain.PreValuesAsDictionary.Values.First().Id);
Assert.AreEqual("preVal1", preValsAgain.PreValuesAsDictionary.Keys.First());
}
[Test]
public void DataTypeService_Can_Persist_Array_Based_Pre_Values()
{

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Services;
namespace Umbraco.Tests.Services
@@ -21,7 +22,7 @@ namespace Umbraco.Tests.Services
new Tuple<PreValue, string, int>(new PreValue(13, "value4"), "key4", 1)
};
var result = DataTypeService.PreValueConverter.ConvertToPreValuesCollection(list);
var result = DataTypeDefinitionRepository.PreValueConverter.ConvertToPreValuesCollection(list);
Assert.Throws<InvalidOperationException>(() =>
{
@@ -47,7 +48,7 @@ namespace Umbraco.Tests.Services
new Tuple<PreValue, string, int>(new PreValue(13, "value4"), "", 1)
};
var result = DataTypeService.PreValueConverter.ConvertToPreValuesCollection(list);
var result = DataTypeDefinitionRepository.PreValueConverter.ConvertToPreValuesCollection(list);
Assert.Throws<InvalidOperationException>(() =>
{
@@ -73,7 +74,7 @@ namespace Umbraco.Tests.Services
new Tuple<PreValue, string, int>(new PreValue(13, "value4"), "key4", 1)
};
var result = DataTypeService.PreValueConverter.ConvertToPreValuesCollection(list);
var result = DataTypeDefinitionRepository.PreValueConverter.ConvertToPreValuesCollection(list);
Assert.Throws<InvalidOperationException>(() =>
{

View File

@@ -179,7 +179,27 @@
<Compile Include="Migrations\Upgrades\ValidateV7TagsUpgradeTest.cs" />
<Compile Include="MockTests.cs" />
<Compile Include="Models\Mapping\AutoMapperTests.cs" />
<Compile Include="Models\Collections\Item.cs" />
<Compile Include="Models\Collections\OrderItem.cs" />
<Compile Include="Models\Collections\SimpleOrder.cs" />
<Compile Include="Models\ContentTypeTests.cs" />
<Compile Include="Models\DataTypeDefinitionTests.cs" />
<Compile Include="Models\DeepCloneHelperTests.cs" />
<Compile Include="Models\DictionaryItemTests.cs" />
<Compile Include="Models\DictionaryTranslationTests.cs" />
<Compile Include="Models\LanguageTests.cs" />
<Compile Include="Models\MemberGroupTests.cs" />
<Compile Include="Models\MemberTests.cs" />
<Compile Include="Models\PropertyGroupTests.cs" />
<Compile Include="Models\PropertyTypeTests.cs" />
<Compile Include="Models\RelationTests.cs" />
<Compile Include="Models\RelationTypeTests.cs" />
<Compile Include="Models\TaskTests.cs" />
<Compile Include="Models\TaskTypeTests.cs" />
<Compile Include="Models\TemplateTests.cs" />
<Compile Include="Models\UmbracoEntityTests.cs" />
<Compile Include="Models\UserTests.cs" />
<Compile Include="Models\UserTypeTests.cs" />
<Compile Include="Mvc\UmbracoViewPageTests.cs" />
<Compile Include="Persistence\Auditing\AuditTests.cs" />
<Compile Include="BootManagers\CoreBootManagerTests.cs" />

View File

@@ -4,7 +4,8 @@ angular.module("umbraco.install").controller("Umbraco.Installer.DataBaseControll
$scope.dbs = [
{name: 'Microsoft SQL Server Compact (SQL CE)', id: 0},
{name: 'Microsoft SQL Server', id: 1},
{name: 'MySQL', id: 2},
{ name: 'Microsoft SQL Azure', id: 3 },
{ name: 'MySQL', id: 2 },
{name: 'Custom connection string', id: -1}];
if(installerService.status.current.model.dbType === undefined){

View File

@@ -129,11 +129,15 @@ namespace Umbraco.Web.Cache
payloads.ForEach(payload =>
{
//clear both the Id and Unique Id cache since we cache both in the legacy classes :(
ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(
string.Format("{0}{1}", CacheKeys.DataTypeCacheKey, payload.Id));
ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(
string.Format("{0}{1}", CacheKeys.DataTypeCacheKey, payload.Id));
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(
string.Format("{0}{1}", CacheKeys.DataTypeCacheKey, payload.UniqueId));
//clears the prevalue cache
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(
string.Format("{0}{1}", CacheKeys.DataTypePreValuesCacheKey, payload.Id));
PublishedContentType.ClearDataType(payload.Id);
});

View File

@@ -55,7 +55,8 @@ namespace Umbraco.Web.Install.Controllers
public bool PostValidateDatabaseConnection(DatabaseModel model)
{
var dbHelper = new DatabaseHelper();
return dbHelper.CheckConnection(model, ApplicationContext);
var canConnect = dbHelper.CheckConnection(model, ApplicationContext);
return canConnect;
}
/// <summary>