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:
Shandem
2010-05-17 15:41:04 +00:00
parent e1eb00fd78
commit cab24fd0d2
14 changed files with 1501 additions and 119 deletions

View File

@@ -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;

View File

@@ -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())

View File

@@ -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)

View File

@@ -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());

View File

@@ -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