diff --git a/umbraco/cms/businesslogic/Content.cs b/umbraco/cms/businesslogic/Content.cs index 99febce984..98dd7341b9 100644 --- a/umbraco/cms/businesslogic/Content.cs +++ b/umbraco/cms/businesslogic/Content.cs @@ -9,6 +9,7 @@ using umbraco.cms.businesslogic.propertytype; using umbraco.DataLayer; using System.Runtime.CompilerServices; using umbraco.cms.helpers; +using umbraco.BusinessLogic; namespace umbraco.cms.businesslogic { @@ -202,24 +203,24 @@ namespace umbraco.cms.businesslogic { get { - //EnsureProperties(); - //return m_LoadedProperties.ToArray(); + EnsureProperties(); + return m_LoadedProperties.ToArray(); - if (this.ContentType == null) - return new Property[0]; + //if (this.ContentType == null) + // return new Property[0]; - List result = new List(); - foreach (PropertyType prop in this.ContentType.PropertyTypes) - { - if (prop == null) - continue; - Property p = getProperty(prop); - if (p == null) - continue; - result.Add(p); - } + //List result = new List(); + //foreach (PropertyType prop in this.ContentType.PropertyTypes) + //{ + // if (prop == null) + // continue; + // Property p = getProperty(prop); + // if (p == null) + // continue; + // result.Add(p); + //} - return result.ToArray(); + //return result.ToArray(); } } @@ -253,11 +254,13 @@ namespace umbraco.cms.businesslogic #region Public Methods /// - /// Used to persist object changes to the database. In Version3.0 it's just a stub for future compatibility + /// Used to persist object changes to the database. This ensures that the properties are re-loaded from the database. /// public override void Save() - { + { base.Save(); + + ClearLoadedProperties(); } /// @@ -284,32 +287,31 @@ namespace umbraco.cms.businesslogic public Property getProperty(PropertyType pt) { - object o = SqlHelper.ExecuteScalar( - "select id from cmsPropertyData where versionId=@version and propertyTypeId=@propertyTypeId", - SqlHelper.CreateParameter("@version", this.Version), - SqlHelper.CreateParameter("@propertyTypeId", pt.Id)); - if (o == null) - return null; - int propertyId; - if (!int.TryParse(o.ToString(), out propertyId)) - return null; - try - { - return new Property(propertyId, pt); - } - catch - { - return null; - } + //object o = SqlHelper.ExecuteScalar( + // "select id from cmsPropertyData where versionId=@version and propertyTypeId=@propertyTypeId", + // SqlHelper.CreateParameter("@version", this.Version), + // SqlHelper.CreateParameter("@propertyTypeId", pt.Id)); + //if (o == null) + // return null; + //int propertyId; + //if (!int.TryParse(o.ToString(), out propertyId)) + // return null; + //try + //{ + // return new Property(propertyId, pt); + //} + //catch (Exception ex) + //{ + // Log.Add(LogTypes.Error, this.Id, "An error occurred retreiving property. EXCEPTION: " + ex.Message); + // return null; + //} + EnsureProperties(); - - //EnsureProperties(); - - //var prop = m_LoadedProperties - // .Where(x => x.PropertyType.Id == pt.Id) - // .SingleOrDefault(); - //return prop; + var prop = m_LoadedProperties + .Where(x => x.PropertyType.Id == pt.Id) + .SingleOrDefault(); + return prop; } @@ -321,7 +323,10 @@ namespace umbraco.cms.businesslogic /// The new Property public Property addProperty(PropertyType pt, Guid versionId) { + ClearLoadedProperties(); + return property.Property.MakeNew(pt, this, versionId); + } /// @@ -440,6 +445,30 @@ namespace umbraco.cms.businesslogic x.AppendChild(c.ToXml(xd, true)); } } + + /// + /// Deletes the current Content object, must be overridden in the child class. + /// + public override void delete() + { + ClearLoadedProperties(); + + // Delete all data associated with this content + this.deleteAllProperties(); + + // Delete version history + SqlHelper.ExecuteNonQuery("Delete from cmsContentVersion where ContentId = " + this.Id); + + // Delete Contentspecific data () + SqlHelper.ExecuteNonQuery("Delete from cmsContent where NodeId = " + this.Id); + + // Delete xml + SqlHelper.ExecuteNonQuery("delete from cmsContentXml where nodeID = @nodeId", SqlHelper.CreateParameter("@nodeId", this.Id)); + + // Delete Nodeinformation!! + base.delete(); + } + #endregion #region Protected Methods @@ -453,6 +482,8 @@ namespace umbraco.cms.businesslogic /// protected void InitializeContent(int InitContentType, Guid InitVersion, DateTime InitVersionDate, string InitContentTypeIcon) { + ClearLoadedProperties(); + if (_contentType == null) _contentType = ContentType.GetContentType(InitContentType); _version = InitVersion; @@ -477,6 +508,8 @@ namespace umbraco.cms.businesslogic /// The new version Id protected Guid createNewVersion() { + ClearLoadedProperties(); + Guid newVersion = Guid.NewGuid(); bool tempHasVersion = hasVersion(); foreach (propertytype.PropertyType pt in this.ContentType.PropertyTypes) @@ -498,28 +531,6 @@ namespace umbraco.cms.businesslogic return newVersion; } - /// - /// Deletes the current Content object, must be overridden in the child class. - /// - protected new void delete() - { - - // Delete all data associated with this content - this.deleteAllProperties(); - - // Delete version history - SqlHelper.ExecuteNonQuery("Delete from cmsContentVersion where ContentId = " + this.Id); - - // Delete Contentspecific data () - SqlHelper.ExecuteNonQuery("Delete from cmsContent where NodeId = " + this.Id); - - // Delete xml - SqlHelper.ExecuteNonQuery("delete from cmsContentXml where nodeID = @nodeId", SqlHelper.CreateParameter("@nodeId", this.Id)); - - // Delete Nodeinformation!! - base.delete(); - } - protected virtual XmlNode generateXmlWithoutSaving(XmlDocument xd) { string nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : Casing.SafeAlias(ContentType.Alias); @@ -552,6 +563,14 @@ namespace umbraco.cms.businesslogic #region Private Methods + /// + /// Clears the locally loaded properties which forces them to be reloaded next time they requested + /// + private void ClearLoadedProperties() + { + m_LoadedProperties = null; + } + /// /// Makes sure that the properties are initialized. If they are already initialized, this does nothing. /// diff --git a/umbraco/cms/businesslogic/datatype/BaseDataType.cs b/umbraco/cms/businesslogic/datatype/BaseDataType.cs index fc35d269df..3f842fd39c 100644 --- a/umbraco/cms/businesslogic/datatype/BaseDataType.cs +++ b/umbraco/cms/businesslogic/datatype/BaseDataType.cs @@ -55,39 +55,63 @@ namespace umbraco.cms.businesslogic.datatype // get it by lookup the value associated to the datatypedefinition id. public string DataFieldName { - get { - if (_datafield == "") - { + get + { + if (_datafield == "") + { string dbtypestr = SqlHelper.ExecuteScalar("select dbType from cmsDataType where nodeId = @datadefinitionid", SqlHelper.CreateParameter("@datadefinitionid", _datatypedefinitionid)); - DBTypes DataTypeSQLType = (DBTypes) Enum.Parse(typeof(DBTypes),dbtypestr,true); - _DBType = DataTypeSQLType; - switch (DataTypeSQLType) - { - case DBTypes.Date : - _datafield = "dataDate"; - break; - case DBTypes.Integer : - _datafield = "DataInt"; - break; - case DBTypes.Ntext : - _datafield = "dataNtext"; - break; - case DBTypes.Nvarchar : - _datafield = "dataNvarchar"; - break; - } - return _datafield; - } - return _datafield; - } + DBTypes DataTypeSQLType = GetDBType(dbtypestr); + _DBType = DataTypeSQLType; + _datafield = GetDataFieldName(_DBType); + } + return _datafield; + } } #endregion - } - public enum DBTypes - { - Integer, - Date, - Nvarchar, - Ntext + + /// + /// This is used internally for performance reasons since we are querying for all of the data properties at once in the + /// DefaultData object, therefore, the DefaultDataObject will set these properties manually instead of incurring a bunch + /// of additional SQL calls. + /// + /// + /// + internal void SetDataTypeProperties(string dataField, DBTypes dataType) + { + _datafield = dataField; + _DBType = dataType; + } + + /// + /// Returns the DBType based on the row value in the dbType column of the cmsDataType + /// + /// + /// + internal static DBTypes GetDBType(string dbtypestr) + { + return (DBTypes)Enum.Parse(typeof(DBTypes), dbtypestr, true); + } + + /// + /// Returns the data column for the data base where the value resides based on the dbType + /// + /// + /// + internal static string GetDataFieldName(DBTypes dbType) + { + switch (dbType) + { + case DBTypes.Date: + return "dataDate"; + case DBTypes.Integer: + return "dataInt"; + case DBTypes.Ntext: + return "dataNtext"; + case DBTypes.Nvarchar: + return "dataNvarchar"; + default: + return "dataNvarchar"; + } + } } } diff --git a/umbraco/cms/businesslogic/datatype/DBTypes.cs b/umbraco/cms/businesslogic/datatype/DBTypes.cs new file mode 100644 index 0000000000..7b2e787efd --- /dev/null +++ b/umbraco/cms/businesslogic/datatype/DBTypes.cs @@ -0,0 +1,15 @@ +using System; +using System.Data; +using umbraco.DataLayer; +using umbraco.BusinessLogic; + +namespace umbraco.cms.businesslogic.datatype +{ + public enum DBTypes + { + Integer, + Date, + Nvarchar, + Ntext + } +} diff --git a/umbraco/cms/businesslogic/datatype/DefaultData.cs b/umbraco/cms/businesslogic/datatype/DefaultData.cs index 1127c493c3..b3826c11d8 100644 --- a/umbraco/cms/businesslogic/datatype/DefaultData.cs +++ b/umbraco/cms/businesslogic/datatype/DefaultData.cs @@ -17,6 +17,7 @@ namespace umbraco.cms.businesslogic.datatype private object m_Value; protected BaseDataType _dataType; private bool m_PreviewMode; + private bool m_ValueLoaded = false; protected static ISqlHelper SqlHelper { @@ -48,7 +49,34 @@ namespace umbraco.cms.businesslogic.datatype /// protected virtual void LoadValueFromDatabase() { - m_Value = SqlHelper.ExecuteScalar("SELECT " + _dataType.DataFieldName + " FROM cmsPropertyData WHERE id = " + m_PropertyId); + + //this is an optimized version of this query. In one call it will return the data type + //and the values, this will then set the underlying db type and value of the BaseDataType object + //instead of having it query the database itself. + var sql = @" + SELECT dataInt, dataDate, dataNvarchar, dataNtext, dbType FROM cmsPropertyData + INNER JOIN cmsPropertyType ON cmsPropertyType.id = cmsPropertyData.propertytypeid + INNER JOIN cmsDataType ON cmsDataType.nodeId = cmsPropertyType.dataTypeId + WHERE cmsPropertyData.id = " + m_PropertyId; + + using (var r = SqlHelper.ExecuteReader(sql)) + { + if (r.Read()) + { + //the type stored in the cmsDataType table + var strDbType = r.GetString("dbType"); + //get the enum of the data type + var dbType = BaseDataType.GetDBType(strDbType); + //get the column name in the cmsPropertyData table that stores the correct information for the data type + var fieldName = BaseDataType.GetDataFieldName(dbType); + //get the value for the data type, if null, set it to an empty string + m_Value = r.GetObject(fieldName) ?? string.Empty; + + //now that we've set our value, we can update our BaseDataType object with the correct values from the db + //instead of making it query for itself. This is a peformance optimization enhancement. + _dataType.SetDataTypeProperties(fieldName, dbType); + } + } } public DBTypes DatabaseType @@ -82,6 +110,12 @@ namespace umbraco.cms.businesslogic.datatype { get { + //Lazy load the value when it is required. + if (!m_ValueLoaded) + { + LoadValueFromDatabase(); + m_ValueLoaded = true; + } return m_Value; } set @@ -140,7 +174,7 @@ namespace umbraco.cms.businesslogic.datatype set { m_PropertyId = value; - LoadValueFromDatabase(); + //LoadValueFromDatabase(); } } diff --git a/umbraco/cms/businesslogic/web/Document.cs b/umbraco/cms/businesslogic/web/Document.cs index 0a26987618..6198642358 100644 --- a/umbraco/cms/businesslogic/web/Document.cs +++ b/umbraco/cms/businesslogic/web/Document.cs @@ -79,7 +79,7 @@ namespace umbraco.cms.businesslogic.web { using (IRecordsReader dr = - SqlHelper.ExecuteReader(string.Format(m_SQLOptimizedSingle, "umbracoNode.id = @id", "cmsContentVersion.id desc"), + SqlHelper.ExecuteReader(string.Format(m_SQLOptimizedSingle.Trim(), "umbracoNode.id = @id", "cmsContentVersion.id desc"), SqlHelper.CreateParameter("@id", id))) { if (dr.Read()) diff --git a/umbraco/cms/umbraco.cms.csproj b/umbraco/cms/umbraco.cms.csproj index 5729b9c5b7..9023d983ec 100644 --- a/umbraco/cms/umbraco.cms.csproj +++ b/umbraco/cms/umbraco.cms.csproj @@ -172,6 +172,7 @@ + True diff --git a/umbraco/datalayer/SqlHelper.cs b/umbraco/datalayer/SqlHelper.cs index 1dde01ee0b..24567f4f9c 100644 --- a/umbraco/datalayer/SqlHelper.cs +++ b/umbraco/datalayer/SqlHelper.cs @@ -194,7 +194,7 @@ namespace umbraco.DataLayer P[] parametersConverted = ConvertParameters(parameters); try { - return ConvertScalar(ExecuteScalar(commandConverted, parametersConverted)); + return ConvertScalar(ExecuteScalar(commandConverted.TrimToOneLine(), parametersConverted)); } catch (Exception e) { @@ -217,7 +217,7 @@ namespace umbraco.DataLayer P[] parametersConverted = ConvertParameters(parameters); try { - return ExecuteNonQuery(commandConverted, parametersConverted); + return ExecuteNonQuery(commandConverted.TrimToOneLine(), parametersConverted); } catch (Exception e) { @@ -239,8 +239,8 @@ namespace umbraco.DataLayer string commandConverted = ConvertCommand(commandText); P[] parametersConverted = ConvertParameters(parameters); try - { - return ExecuteReader(commandConverted, parametersConverted); + { + return ExecuteReader(commandConverted.TrimToOneLine(), parametersConverted); } catch (Exception e) { @@ -263,7 +263,7 @@ namespace umbraco.DataLayer P[] parametersConverted = ConvertParameters(parameters); try { - return ExecuteXmlReader(commandConverted, parametersConverted); + return ExecuteXmlReader(commandConverted.TrimToOneLine(), parametersConverted); } catch (Exception e) { diff --git a/umbraco/datalayer/StringExtensions.cs b/umbraco/datalayer/StringExtensions.cs new file mode 100644 index 0000000000..e8cac836c1 --- /dev/null +++ b/umbraco/datalayer/StringExtensions.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace umbraco.DataLayer +{ + public static class StringExtensions + { + + /// + /// This trims all white spaces from beginning and end of the string and removes any line breaks (repacing with a space) + /// + /// + /// + public static string TrimToOneLine(this string str) + { + return str.Replace(Environment.NewLine, " ").Trim(); + } + + } +} diff --git a/umbraco/datalayer/umbraco.datalayer.csproj b/umbraco/datalayer/umbraco.datalayer.csproj index ceab08c57b..548b04ff1d 100644 --- a/umbraco/datalayer/umbraco.datalayer.csproj +++ b/umbraco/datalayer/umbraco.datalayer.csproj @@ -94,6 +94,7 @@ + diff --git a/umbraco/presentation/umbraco/controls/ContentControl.cs b/umbraco/presentation/umbraco/controls/ContentControl.cs index ce8d74489a..808e0ed721 100644 --- a/umbraco/presentation/umbraco/controls/ContentControl.cs +++ b/umbraco/presentation/umbraco/controls/ContentControl.cs @@ -32,8 +32,7 @@ namespace umbraco.controls public event EventHandler Save; private publishModes CanPublish = publishModes.NoPublish; public TabPage tpProp; - public bool DoesPublish = false; - private Hashtable inTab = new Hashtable(); + public bool DoesPublish = false; public TextBox NameTxt = new TextBox(); public PlaceHolder NameTxtHolder = new PlaceHolder(); public RequiredFieldValidator NameTxtValidator = new RequiredFieldValidator(); @@ -100,6 +99,8 @@ namespace umbraco.controls Save += new EventHandler(standardSaveAndPublishHandler); prntpage = (UmbracoEnsuredPage)Page; int i = 0; + var inTab = new Hashtable(); + foreach (ContentType.TabI t in _content.ContentType.getVirtualTabs.ToList()) { var tp = this.Panels[i] as TabPage; @@ -124,13 +125,21 @@ namespace umbraco.controls i++; } - // Add property pane tpProp = NewTabPage(ui.Text("general", "properties", null)); addSaveAndPublishButtons(ref tpProp); tpProp.Controls.Add( new LiteralControl("
There were errors - data has not been saved!
")); + + //if the property is not in a tab, add it to the general tab + var props = _content.GenericProperties; + foreach (Property p in props) + { + if (inTab[p.PropertyType.Id.ToString()] == null) + addControlNew(p, tpProp, ui.Text("general", "properties", null)); + } + } /// @@ -185,13 +194,7 @@ namespace umbraco.controls } protected override void OnLoad(EventArgs e) - { - var props = _content.getProperties; - foreach (Property p in props) - { - if (inTab[p.PropertyType.Id.ToString()] == null) - addControlNew(p, tpProp, ui.Text("general", "properties", null)); - } + { base.OnLoad(e); ContentControlLoadEventArgs contentcontrolEvent = new ContentControlLoadEventArgs(); diff --git a/umbraco/presentation/umbraco/dashboard/LatestEdits.ascx.cs b/umbraco/presentation/umbraco/dashboard/LatestEdits.ascx.cs index 8bc001a977..9cbec94fab 100644 --- a/umbraco/presentation/umbraco/dashboard/LatestEdits.ascx.cs +++ b/umbraco/presentation/umbraco/dashboard/LatestEdits.ascx.cs @@ -7,6 +7,7 @@ namespace dashboardUtilities using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; using umbraco.IO; + using umbraco.cms.businesslogic.web; /// /// Summary description for LatestEdits. @@ -35,17 +36,10 @@ namespace dashboardUtilities printedIds.Add(NodeId); try { - umbraco.cms.businesslogic.web.Document d = new umbraco.cms.businesslogic.web.Document(int.Parse(NodeId.ToString())); - string parent = ""; - try - { - if (d.Parent != null) - parent = " (" + d.Parent.Text + ")"; - } - catch {} + Document d = new Document(int.Parse(NodeId.ToString())); count++; return - " " + d.Text + parent + ". " + umbraco.ui.Text("general", "edited", bp.getUser()) + " " + umbraco.library.ShortDateWithTimeAndGlobal(DateTime.Parse(Date.ToString()).ToString(), umbraco.ui.Culture(bp.getUser())) + "
"; + " " + d.Text + ". " + umbraco.ui.Text("general", "edited", bp.getUser()) + " " + umbraco.library.ShortDateWithTimeAndGlobal(DateTime.Parse(Date.ToString()).ToString(), umbraco.ui.Culture(bp.getUser())) + "
"; } catch { return ""; diff --git a/umbraco/presentation/web.config.SHANDEMVAIO.xslt b/umbraco/presentation/web.config.SHANDEMVAIO.xslt index 740c8c6370..96f46733ff 100644 --- a/umbraco/presentation/web.config.SHANDEMVAIO.xslt +++ b/umbraco/presentation/web.config.SHANDEMVAIO.xslt @@ -12,7 +12,7 @@ - + diff --git a/umbraco/presentation/web.config.SHOCKING.xslt b/umbraco/presentation/web.config.SHOCKING.xslt index f76ed897a6..9c422cf9f2 100644 --- a/umbraco/presentation/web.config.SHOCKING.xslt +++ b/umbraco/presentation/web.config.SHOCKING.xslt @@ -20,7 +20,7 @@ - +