More unit tests.
Fixes more data layer bugs: 27079, 27080, 27081, 27082 Checked in SQL for foreign keys, indexes and unique constraints into seperate file to be merged into install script after all tests have been written. [TFS Changeset #66149]
This commit is contained in:
@@ -513,7 +513,8 @@ order by level,sortOrder";
|
||||
{
|
||||
if (!_hasChildrenInitialized)
|
||||
{
|
||||
int tmpChildrenCount = SqlHelper.ExecuteScalar<int>("select count(id) from umbracoNode where ParentId = " + _id);
|
||||
int tmpChildrenCount = SqlHelper.ExecuteScalar<int>("select count(id) from umbracoNode where ParentId = @id",
|
||||
SqlHelper.CreateParameter("@id", Id));
|
||||
HasChildren = (tmpChildrenCount > 0);
|
||||
}
|
||||
return _hasChildren;
|
||||
|
||||
@@ -85,12 +85,16 @@ namespace umbraco.cms.businesslogic
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constants
|
||||
#region Constants and static members
|
||||
|
||||
private const string m_SQLOptimizedGetAll = @"
|
||||
SELECT id, createDate, trashed, parentId, nodeObjectType, nodeUser, level, path, sortOrder, uniqueID, text,
|
||||
masterContentType,Alias,icon,thumbnail,description
|
||||
FROM umbracoNode INNER JOIN cmsContentType ON umbracoNode.id = cmsContentType.nodeId
|
||||
WHERE nodeObjectType = @nodeObjectType";
|
||||
WHERE nodeObjectType = @nodeObjectType";
|
||||
|
||||
private static readonly object m_Locker = new object();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Methods
|
||||
@@ -104,8 +108,15 @@ namespace umbraco.cms.businesslogic
|
||||
{
|
||||
if (HttpRuntime.Cache[string.Format("UmbracoContentType{0}", id.ToString())] == null)
|
||||
{
|
||||
ContentType ct = new ContentType(id);
|
||||
HttpRuntime.Cache.Insert(string.Format("UmbracoContentType{0}", id.ToString()), ct);
|
||||
lock (m_Locker)
|
||||
{
|
||||
//double check
|
||||
if (HttpRuntime.Cache[string.Format("UmbracoContentType{0}", id.ToString())] == null)
|
||||
{
|
||||
ContentType ct = new ContentType(id);
|
||||
HttpRuntime.Cache.Insert(string.Format("UmbracoContentType{0}", id.ToString()), ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ContentType)HttpRuntime.Cache[string.Format("UmbracoContentType{0}", id.ToString())];
|
||||
}
|
||||
@@ -297,7 +308,8 @@ namespace umbraco.cms.businesslogic
|
||||
{
|
||||
get
|
||||
{
|
||||
string cacheKey = "ContentType_PropertyTypes_Content:" + this.Id;
|
||||
string cacheKey = GetPropertiesCacheKey();
|
||||
|
||||
return Cache.GetCacheItem<List<PropertyType>>(cacheKey, propertyTypesCacheSyncLock,
|
||||
TimeSpan.FromMinutes(15),
|
||||
delegate
|
||||
@@ -380,6 +392,7 @@ namespace umbraco.cms.businesslogic
|
||||
set
|
||||
{
|
||||
m_masterContentType = value;
|
||||
|
||||
SqlHelper.ExecuteNonQuery("update cmsContentType set masterContentType = @masterContentType where nodeId = @nodeId",
|
||||
SqlHelper.CreateParameter("@masterContentType", value),
|
||||
SqlHelper.CreateParameter("@nodeId", Id));
|
||||
@@ -469,9 +482,7 @@ namespace umbraco.cms.businesslogic
|
||||
/// </summary>
|
||||
/// <returns>The list of all ContentTypes</returns>
|
||||
public ContentType[] GetAll()
|
||||
{
|
||||
//write optimized sql for this!
|
||||
|
||||
{
|
||||
var contentTypes = new List<ContentType>();
|
||||
|
||||
using (IRecordsReader dr =
|
||||
@@ -520,17 +531,14 @@ namespace umbraco.cms.businesslogic
|
||||
/// <summary>
|
||||
/// Adding a PropertyType to a Tab, the Tabs are primarily used for making the
|
||||
/// editing interface more userfriendly.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pt">The PropertyType</param>
|
||||
/// <param name="TabId">The Id of the Tab</param>
|
||||
public void SetTabOnPropertyType(PropertyType pt, int TabId)
|
||||
{
|
||||
SqlHelper.ExecuteNonQuery(
|
||||
"update cmsPropertyType set tabId = " + TabId.ToString() + " where id = " +
|
||||
pt.Id.ToString());
|
||||
|
||||
// Remove from cache
|
||||
{
|
||||
// This is essentially just a wrapper for the property
|
||||
pt.TabId = TabId;
|
||||
//flush the content type cache, the the tab cache (why so much cache?! argh!)
|
||||
FlushFromCache(Id);
|
||||
foreach (TabI t in getVirtualTabs.ToList())
|
||||
FlushTabCache(t.Id, pt.ContentTypeId);
|
||||
@@ -541,10 +549,8 @@ namespace umbraco.cms.businesslogic
|
||||
/// </summary>
|
||||
/// <param name="pt">The PropertyType which should be freed from its tab</param>
|
||||
public void removePropertyTypeFromTab(PropertyType pt)
|
||||
{
|
||||
SqlHelper.ExecuteNonQuery(
|
||||
"update cmsPropertyType set tabId = NULL where id = " + pt.Id.ToString());
|
||||
|
||||
{
|
||||
pt.TabId = 0; //this will set to null in the database.
|
||||
// Remove from cache
|
||||
FlushFromCache(Id);
|
||||
}
|
||||
@@ -578,8 +584,17 @@ namespace umbraco.cms.businesslogic
|
||||
/// <param name="id">The Id of the Tab to be deleted.</param>
|
||||
public void DeleteVirtualTab(int id)
|
||||
{
|
||||
SqlHelper.ExecuteNonQuery(
|
||||
"Update cmsPropertyType set tabId = NULL where tabId =" + id);
|
||||
//set each property on the tab to have a tab id of zero
|
||||
this.getVirtualTabs.ToList()
|
||||
.Where(x => x.Id == id)
|
||||
.Single()
|
||||
.PropertyTypes
|
||||
.ToList()
|
||||
.ForEach(x =>
|
||||
{
|
||||
x.TabId = 0;
|
||||
});
|
||||
|
||||
SqlHelper.ExecuteNonQuery("delete from cmsTab where id =" + id);
|
||||
|
||||
// Remove from cache
|
||||
@@ -687,6 +702,19 @@ namespace umbraco.cms.businesslogic
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected void PopulateContentTypeNodeFromReader(IRecordsReader dr)
|
||||
{
|
||||
_alias = dr.GetString("Alias");
|
||||
_iconurl = dr.GetString("icon");
|
||||
if (!dr.IsNull("masterContentType"))
|
||||
m_masterContentType = dr.GetInt("masterContentType");
|
||||
|
||||
if (!dr.IsNull("thumbnail"))
|
||||
_thumbnail = dr.GetString("thumbnail");
|
||||
if (!dr.IsNull("description"))
|
||||
_description = dr.GetString("description");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set up the internal data of the ContentType
|
||||
/// </summary>
|
||||
@@ -725,18 +753,27 @@ namespace umbraco.cms.businesslogic
|
||||
protected void FlushFromCache(int Id)
|
||||
{
|
||||
if (HttpRuntime.Cache[string.Format("UmbracoContentType{0}", Id.ToString())] != null)
|
||||
HttpRuntime.Cache.Remove(string.Format("UmbracoContentType{0}", Id.ToString()));
|
||||
{
|
||||
lock (m_Locker)
|
||||
{
|
||||
//double check
|
||||
if (HttpRuntime.Cache[string.Format("UmbracoContentType{0}", Id.ToString())] != null)
|
||||
{
|
||||
HttpRuntime.Cache.Remove(string.Format("UmbracoContentType{0}", Id.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HttpRuntime.Cache[string.Format("ContentType_PropertyTypes_Content:{0}", Id.ToString())] != null)
|
||||
HttpRuntime.Cache.Remove(string.Format("ContentType_PropertyTypes_Content:{0}", Id.ToString()));
|
||||
string cacheKey = GetPropertiesCacheKey();
|
||||
Cache.ClearCacheItem(cacheKey);
|
||||
|
||||
ClearVirtualTabs();
|
||||
}
|
||||
|
||||
protected void FlushAllFromCache()
|
||||
{
|
||||
cache.Cache.ClearCacheByKeySearch("UmbracoContentType");
|
||||
cache.Cache.ClearCacheByKeySearch("ContentType_PropertyTypes_Content");
|
||||
Cache.ClearCacheByKeySearch("UmbracoContentType");
|
||||
Cache.ClearCacheByKeySearch("ContentType_PropertyTypes_Content");
|
||||
|
||||
ClearVirtualTabs();
|
||||
}
|
||||
@@ -745,6 +782,15 @@ namespace umbraco.cms.businesslogic
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// The cache key used to cache the properties for the content type
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string GetPropertiesCacheKey()
|
||||
{
|
||||
return "ContentType_PropertyTypes_Content:" + this.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the locally loaded tabs which forces them to be reloaded next time they requested
|
||||
/// </summary>
|
||||
@@ -795,19 +841,6 @@ namespace umbraco.cms.businesslogic
|
||||
m_VirtualTabs.Sort((a, b) => a.SortOrder.CompareTo(b.SortOrder));
|
||||
}
|
||||
|
||||
private void PopulateContentTypeNodeFromReader(IRecordsReader dr)
|
||||
{
|
||||
_alias = dr.GetString("Alias");
|
||||
_iconurl = dr.GetString("icon");
|
||||
if (!dr.IsNull("masterContentType"))
|
||||
m_masterContentType = dr.GetInt("masterContentType");
|
||||
|
||||
if (!dr.IsNull("thumbnail"))
|
||||
_thumbnail = dr.GetString("thumbnail");
|
||||
if (!dr.IsNull("description"))
|
||||
_description = dr.GetString("description");
|
||||
}
|
||||
|
||||
private void populateMasterContentTypes(PropertyType pt, int docTypeId)
|
||||
{
|
||||
foreach (web.DocumentType docType in web.DocumentType.GetAllAsList())
|
||||
|
||||
31
umbraco/cms/businesslogic/cache/Cache.cs
vendored
31
umbraco/cms/businesslogic/cache/Cache.cs
vendored
@@ -9,6 +9,8 @@ namespace umbraco.cms.businesslogic.cache
|
||||
public class Cache
|
||||
{
|
||||
|
||||
public static readonly object m_Locker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Clears everything in umbraco's runtime cache, which means that not only
|
||||
/// umbraco content is removed, but also other cache items from pages running in
|
||||
@@ -35,8 +37,15 @@ namespace umbraco.cms.businesslogic.cache
|
||||
{
|
||||
if (System.Web.HttpRuntime.Cache[Key] != null)
|
||||
{
|
||||
System.Web.HttpRuntime.Cache.Remove(Key);
|
||||
System.Web.HttpContext.Current.Trace.Warn("Cache", "Item " + Key + " removed from cache");
|
||||
lock (m_Locker)
|
||||
{
|
||||
//check again
|
||||
if (System.Web.HttpRuntime.Cache[Key] != null)
|
||||
{
|
||||
System.Web.HttpRuntime.Cache.Remove(Key);
|
||||
System.Web.HttpContext.Current.Trace.Warn("Cache", "Item " + Key + " removed from cache");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,10 +63,20 @@ namespace umbraco.cms.businesslogic.cache
|
||||
if (c != null)
|
||||
{
|
||||
System.Collections.IDictionaryEnumerator cacheEnumerator = c.GetEnumerator();
|
||||
while ( cacheEnumerator.MoveNext() )
|
||||
if (cacheEnumerator.Key != null && c[cacheEnumerator.Key.ToString()] != null && c[cacheEnumerator.Key.ToString()].GetType() != null && c[cacheEnumerator.Key.ToString()].GetType().ToString() == TypeName)
|
||||
c.Remove(cacheEnumerator.Key.ToString());
|
||||
|
||||
while (cacheEnumerator.MoveNext())
|
||||
{
|
||||
if (cacheEnumerator.Key != null && c[cacheEnumerator.Key.ToString()] != null && c[cacheEnumerator.Key.ToString()].GetType() != null && c[cacheEnumerator.Key.ToString()].GetType().ToString() == TypeName)
|
||||
{
|
||||
lock (m_Locker)
|
||||
{
|
||||
//check again
|
||||
if (cacheEnumerator.Key != null && c[cacheEnumerator.Key.ToString()] != null && c[cacheEnumerator.Key.ToString()].GetType() != null && c[cacheEnumerator.Key.ToString()].GetType().ToString() == TypeName)
|
||||
{
|
||||
c.Remove(cacheEnumerator.Key.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception CacheE)
|
||||
|
||||
@@ -88,6 +88,13 @@ namespace umbraco.cms.businesslogic.propertytype
|
||||
get { return _id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Setting the tab id is not meant to be used directly in code. Use the ContentType SetTabOnPropertyType method instead
|
||||
/// as that will handle all of the caching properly, this will not.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Setting the tab id to a negative value will actually set the value to NULL in the database
|
||||
/// </remarks>
|
||||
public int TabId
|
||||
{
|
||||
get { return _tabId; }
|
||||
@@ -95,8 +102,15 @@ namespace umbraco.cms.businesslogic.propertytype
|
||||
{
|
||||
_tabId = value;
|
||||
this.InvalidateCache();
|
||||
object tabId = value;
|
||||
if (value < 1)
|
||||
{
|
||||
tabId = DBNull.Value;
|
||||
}
|
||||
|
||||
SqlHelper.ExecuteNonQuery( "Update cmsPropertyType set tabId = @tabId where id = @id",
|
||||
SqlHelper.CreateParameter("@tabId", value), SqlHelper.CreateParameter("@id", this.Id));
|
||||
SqlHelper.CreateParameter("@tabId", tabId),
|
||||
SqlHelper.CreateParameter("@id", this.Id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +339,7 @@ namespace umbraco.cms.businesslogic.propertytype
|
||||
protected virtual void FlushCache()
|
||||
{
|
||||
// clear local cache
|
||||
cache.Cache.ClearCacheItem(GetCacheKey(Id));
|
||||
Cache.ClearCacheItem(GetCacheKey(Id));
|
||||
|
||||
// clear cache in contentype
|
||||
Cache.ClearCacheItem("ContentType_PropertyTypes_Content:" + this._contenttypeid.ToString());
|
||||
|
||||
@@ -8,6 +8,9 @@ using umbraco.BusinessLogic;
|
||||
using umbraco.cms.businesslogic.propertytype;
|
||||
using umbraco.DataLayer;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Umbraco.Test")]
|
||||
|
||||
namespace umbraco.cms.businesslogic.web
|
||||
{
|
||||
@@ -22,16 +25,23 @@ namespace umbraco.cms.businesslogic.web
|
||||
|
||||
public DocumentType(Guid id) : base(id) { }
|
||||
|
||||
//public DocumentType(bool useOptimizedMode, int id)
|
||||
// : base(useOptimizedMode, id)
|
||||
//{
|
||||
|
||||
//}
|
||||
public DocumentType(int id, bool noSetup) : base(id, noSetup) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constants and Static members
|
||||
public static Guid _objectType = new Guid("a2cb7800-f571-4787-9638-bc48539a0efb");
|
||||
|
||||
public static Guid _objectType = new Guid("a2cb7800-f571-4787-9638-bc48539a0efb");
|
||||
|
||||
internal const string m_SQLOptimizedGetAll = @"
|
||||
SELECT id, createDate, trashed, parentId, nodeObjectType, nodeUser, level, path, sortOrder, uniqueID, text,
|
||||
masterContentType,Alias,icon,thumbnail,description,
|
||||
templateNodeId, IsDefault
|
||||
FROM umbracoNode
|
||||
INNER JOIN cmsContentType ON umbracoNode.id = cmsContentType.nodeId
|
||||
LEFT OUTER JOIN cmsDocumentType ON cmsContentType.nodeId = cmsDocumentType.contentTypeNodeId
|
||||
WHERE nodeObjectType = @nodeObjectType";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Members
|
||||
@@ -138,16 +148,40 @@ namespace umbraco.cms.businesslogic.web
|
||||
}
|
||||
|
||||
public static List<DocumentType> GetAllAsList()
|
||||
{
|
||||
List<DocumentType> retVal = new List<DocumentType>();
|
||||
Guid[] Ids = getAllUniquesFromObjectType(_objectType);
|
||||
for (int i = 0; i < Ids.Length; i++)
|
||||
{
|
||||
|
||||
var documentTypes = new List<DocumentType>();
|
||||
|
||||
using (IRecordsReader dr =
|
||||
SqlHelper.ExecuteReader(m_SQLOptimizedGetAll, SqlHelper.CreateParameter("@nodeObjectType", DocumentType._objectType)))
|
||||
{
|
||||
retVal.Add(new DocumentType(Ids[i]));
|
||||
while (dr.Read())
|
||||
{
|
||||
//check if the document id has already been added
|
||||
if (documentTypes.Where(x => x.Id == dr.Get<int>("id")).Count() == 0)
|
||||
{
|
||||
//create the DocumentType object without setting up
|
||||
DocumentType dt = new DocumentType(dr.Get<int>("id"), true);
|
||||
//populate it's CMSNode properties
|
||||
dt.PopulateCMSNodeFromReader(dr);
|
||||
//populate it's ContentType properties
|
||||
dt.PopulateContentTypeNodeFromReader(dr);
|
||||
//populate from it's DocumentType properties
|
||||
dt.PopulateDocumentTypeNodeFromReader(dr);
|
||||
|
||||
documentTypes.Add(dt);
|
||||
}
|
||||
else
|
||||
{
|
||||
//we've already created the document type with this id, so we'll add the rest of it's templates to itself
|
||||
var dt = documentTypes.Where(x => x.Id == dr.Get<int>("id")).Single();
|
||||
dt.PopulateDocumentTypeNodeFromReader(dr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retVal.Sort(delegate(DocumentType dt1, DocumentType dt2) { return dt1.Text.CompareTo(dt2.Text); });
|
||||
return retVal;
|
||||
return documentTypes.OrderBy(x => x.Text).ToList();
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -212,6 +246,10 @@ namespace umbraco.cms.businesslogic.web
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Throws an exception if trying to delete a document type that is assigned as a master document type</exception>
|
||||
public override void delete()
|
||||
{
|
||||
DeleteEventArgs e = new DeleteEventArgs();
|
||||
@@ -349,27 +387,34 @@ namespace umbraco.cms.businesslogic.web
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected void PopulateDocumentTypeNodeFromReader(IRecordsReader dr)
|
||||
{
|
||||
if (!dr.IsNull("templateNodeId"))
|
||||
{
|
||||
_templateIds.Add(dr.GetInt("templateNodeId"));
|
||||
if (!dr.IsNull("IsDefault"))
|
||||
{
|
||||
if (dr.GetBoolean("IsDefault"))
|
||||
{
|
||||
_defaultTemplate = dr.GetInt("templateNodeId");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void setupNode()
|
||||
{
|
||||
base.setupNode();
|
||||
|
||||
if (SqlHelper.ExecuteScalar<int>("select count(TemplateNodeId) as tmp from cmsDocumentType where contentTypeNodeId =" + Id) > 0)
|
||||
using (IRecordsReader dr = SqlHelper.ExecuteReader("Select templateNodeId, IsDefault from cmsDocumentType where contentTypeNodeId = @id",
|
||||
SqlHelper.CreateParameter("@id", Id)))
|
||||
{
|
||||
IRecordsReader dr =
|
||||
SqlHelper.ExecuteReader(
|
||||
"Select templateNodeId, IsDefault from cmsDocumentType where contentTypeNodeId =" +
|
||||
Id);
|
||||
while (dr.Read())
|
||||
{
|
||||
if (template.Template.IsNode(dr.GetInt("templateNodeId")))
|
||||
{
|
||||
_templateIds.Add(dr.GetInt("templateNodeId"));
|
||||
if (dr.GetBoolean("IsDefault"))
|
||||
_defaultTemplate = dr.GetInt("templateNodeId");
|
||||
}
|
||||
PopulateDocumentTypeNodeFromReader(dr);
|
||||
}
|
||||
dr.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user