diff --git a/src/Umbraco.Core/Persistence/PetaPoco.cs b/src/Umbraco.Core/Persistence/PetaPoco.cs index 32f9024d49..8a32deb331 100644 --- a/src/Umbraco.Core/Persistence/PetaPoco.cs +++ b/src/Umbraco.Core/Persistence/PetaPoco.cs @@ -1,10 +1,10 @@ /* PetaPoco v4.0.3 - A Tiny ORMish thing for your POCO's. * Copyright © 2011 Topten Software. All Rights Reserved. - * + * * Apache License 2.0 - http://www.toptensoftware.com/petapoco/license - * - * Special thanks to Rob Conery (@robconery) for original inspiration (ie:Massive) and for - * use of Subsonic's T4 templates, Rob Sullivan (@DataChomp) for hard core DBA advice + * + * Special thanks to Rob Conery (@robconery) for original inspiration (ie:Massive) and for + * use of Subsonic's T4 templates, Rob Sullivan (@DataChomp) for hard core DBA advice * and Adam Schroder (@schotime) for lots of suggestions, improvements and Oracle support */ @@ -88,7 +88,7 @@ namespace Umbraco.Core.Persistence } // Results from paged request - public class Page + public class Page { public long CurrentPage { get; set; } public long TotalPages { get; set; } @@ -202,7 +202,7 @@ namespace Umbraco.Core.Persistence if (_providerName != null) _factory = DbProviderFactories.GetFactory(_providerName); - + string dbtype = (_factory == null ? _sharedConnection.GetType() : _factory.GetType()).Name; if (dbtype.StartsWith("MySql")) _dbType = DBType.MySql; @@ -385,7 +385,7 @@ namespace Umbraco.Core.Persistence return "SET TRANSACTION ISOLATION LEVEL READ COMMITTED"; } } - + // Helper to handle named parameters from object properties static Regex rxParams = new Regex(@"(? args_dest) @@ -425,8 +425,8 @@ namespace Umbraco.Core.Persistence } // Expand collections to parameter lists - if ((arg_val as System.Collections.IEnumerable) != null && - (arg_val as string) == null && + if ((arg_val as System.Collections.IEnumerable) != null && + (arg_val as string) == null && (arg_val as byte[]) == null) { var sb = new StringBuilder(); @@ -487,10 +487,10 @@ namespace Umbraco.Core.Persistence } else if (t == typeof(string)) { - // out of memory exception occurs if trying to save more than 4000 characters to SQL Server CE NText column. + // out of memory exception occurs if trying to save more than 4000 characters to SQL Server CE NText column. //Set before attempting to set Size, or Size will always max out at 4000 if ((item as string).Length + 1 > 4000 && p.GetType().Name == "SqlCeParameter") - p.GetType().GetProperty("SqlDbType").SetValue(p, SqlDbType.NText, null); + p.GetType().GetProperty("SqlDbType").SetValue(p, SqlDbType.NText, null); p.Size = (item as string).Length + 1; if(p.Size < 4000) @@ -676,12 +676,12 @@ namespace Umbraco.Core.Persistence public bool ForceDateTimesToUtc { get; set; } // Return a typed list of pocos - public List Fetch(string sql, params object[] args) + public List Fetch(string sql, params object[] args) { return Query(sql, args).ToList(); } - public List Fetch(Sql sql) + public List Fetch(Sql sql) { return Fetch(sql.SQL, sql.Arguments); } @@ -726,7 +726,7 @@ namespace Umbraco.Core.Persistence return true; } - public void BuildPageQueries(long skip, long take, string sql, ref object[] args, out string sqlCount, out string sqlPage) + public void BuildPageQueries(long skip, long take, string sql, ref object[] args, out string sqlCount, out string sqlPage) { // Add auto select clause if (EnableAutoSelect) @@ -764,8 +764,8 @@ namespace Umbraco.Core.Persistence } - // Fetch a page - public Page Page(long page, long itemsPerPage, string sql, params object[] args) + // Fetch a page + public Page Page(long page, long itemsPerPage, string sql, params object[] args) { string sqlCount, sqlPage; BuildPageQueries((page-1)*itemsPerPage, itemsPerPage, sql, ref args, out sqlCount, out sqlPage); @@ -791,7 +791,7 @@ namespace Umbraco.Core.Persistence return result; } - public Page Page(long page, long itemsPerPage, Sql sql) + public Page Page(long page, long itemsPerPage, Sql sql) { return Page(page, itemsPerPage, sql.SQL, sql.Arguments); } @@ -820,7 +820,7 @@ namespace Umbraco.Core.Persistence } // Return an enumerable collection of pocos - public IEnumerable Query(string sql, params object[] args) + public IEnumerable Query(string sql, params object[] args) { if (EnableAutoSelect) sql = AddSelectClause(sql); @@ -1033,7 +1033,7 @@ namespace Umbraco.Core.Persistence } private List Delegates { get; set; } private Delegate GetItem(int index) { return Delegates[index]; } - + /// /// Calls the delegate at the specified index and returns its values /// @@ -1068,7 +1068,7 @@ namespace Umbraco.Core.Persistence // Create a multi-poco factory Func CreateMultiPocoFactory(Type[] types, string sql, IDataReader r) - { + { // Call each delegate var dels = new List(); int pos = 0; @@ -1088,7 +1088,7 @@ namespace Umbraco.Core.Persistence static Dictionary AutoMappers = new Dictionary(); static System.Threading.ReaderWriterLockSlim RWLock = new System.Threading.ReaderWriterLockSlim(); - // Get (or create) the multi-poco factory for a query + // Get (or create) the multi-poco factory for a query Func GetMultiPocoFactory(Type[] types, string sql, IDataReader r) { // Build a key string (this is crap, should address this at some point) @@ -1113,8 +1113,8 @@ namespace Umbraco.Core.Persistence if (MultiPocoFactories.TryGetValue(key, out oFactory)) { //mpFactory = oFactory; - return (Func)oFactory; - } + return (Func)oFactory; + } } finally { @@ -1130,9 +1130,9 @@ namespace Umbraco.Core.Persistence if (MultiPocoFactories.TryGetValue(key, out oFactory)) { return (Func)oFactory; - } - - // Create the factory + } + + // Create the factory var factory = CreateMultiPocoFactory(types, sql, r); MultiPocoFactories.Add(key, factory); @@ -1207,54 +1207,54 @@ namespace Umbraco.Core.Persistence } } - - public IEnumerable Query(Sql sql) + + public IEnumerable Query(Sql sql) { return Query(sql.SQL, sql.Arguments); } - public bool Exists(object primaryKey) + public bool Exists(object primaryKey) { return FirstOrDefault(string.Format("WHERE {0}=@0", EscapeSqlIdentifier(PocoData.ForType(typeof(T)).TableInfo.PrimaryKey)), primaryKey) != null; } - public T Single(object primaryKey) + public T Single(object primaryKey) { return Single(string.Format("WHERE {0}=@0", EscapeSqlIdentifier(PocoData.ForType(typeof(T)).TableInfo.PrimaryKey)), primaryKey); } - public T SingleOrDefault(object primaryKey) + public T SingleOrDefault(object primaryKey) { return SingleOrDefault(string.Format("WHERE {0}=@0", EscapeSqlIdentifier(PocoData.ForType(typeof(T)).TableInfo.PrimaryKey)), primaryKey); } - public T Single(string sql, params object[] args) + public T Single(string sql, params object[] args) { return Query(sql, args).Single(); } - public T SingleOrDefault(string sql, params object[] args) + public T SingleOrDefault(string sql, params object[] args) { return Query(sql, args).SingleOrDefault(); } - public T First(string sql, params object[] args) + public T First(string sql, params object[] args) { return Query(sql, args).First(); } - public T FirstOrDefault(string sql, params object[] args) + public T FirstOrDefault(string sql, params object[] args) { return Query(sql, args).FirstOrDefault(); } - public T Single(Sql sql) + public T Single(Sql sql) { return Query(sql).Single(); } - public T SingleOrDefault(Sql sql) + public T SingleOrDefault(Sql sql) { return Query(sql).SingleOrDefault(); } - public T First(Sql sql) + public T First(Sql sql) { return Query(sql).First(); } - public T FirstOrDefault(Sql sql) + public T FirstOrDefault(Sql sql) { return Query(sql).FirstOrDefault(); } @@ -1285,7 +1285,7 @@ namespace Umbraco.Core.Persistence return Insert(tableName, primaryKeyName, true, poco); } - // Insert a poco into a table. If the poco has a property with the same name + // Insert a poco into a table. If the poco has a property with the same name // as the primary key the id of the new record is assigned to it. Either way, // the new id is returned. public object Insert(string tableName, string primaryKeyName, bool autoIncrement, object poco) @@ -1721,7 +1721,7 @@ namespace Umbraco.Core.Persistence { cmd.CommandTimeout = CommandTimeout; } - + // Call hook OnExecutingCommand(cmd); @@ -1779,8 +1779,8 @@ namespace Umbraco.Core.Persistence public class ExpandoColumn : PocoColumn { public override void SetValue(object target, object val) { (target as IDictionary)[ColumnName]=val; } - public override object GetValue(object target) - { + public override object GetValue(object target) + { object val=null; (target as IDictionary).TryGetValue(ColumnName, out val); return val; @@ -1803,7 +1803,7 @@ namespace Umbraco.Core.Persistence } static readonly ObjectCache ObjectCache = new MemoryCache("NPoco"); - + } public class PocoData @@ -1812,7 +1812,7 @@ namespace Umbraco.Core.Persistence internal static bool UseLongKeys = false; //USE ONLY FOR TESTING - default is one hr internal static int SlidingExpirationSeconds = 3600; - + public static PocoData ForObject(object o, string primaryKeyName) { var t = o.GetType(); @@ -1836,7 +1836,7 @@ namespace Umbraco.Core.Persistence #endif return ForType(t); } - + public static PocoData ForType(Type t) { #if !PETAPOCO_NO_DYNAMIC @@ -1856,7 +1856,7 @@ namespace Umbraco.Core.Persistence InnerLock.ExitReadLock(); } - + // Cache it InnerLock.EnterWriteLock(); try @@ -1959,7 +1959,7 @@ namespace Umbraco.Core.Persistence public Delegate GetFactory(string sql, string connString, bool ForceDateTimesToUtc, int firstColumn, int countColumns, IDataReader r) { - //TODO: It would be nice to remove the irrelevant SQL parts - for a mapping operation anything after the SELECT clause isn't required. + //TODO: It would be nice to remove the irrelevant SQL parts - for a mapping operation anything after the SELECT clause isn't required. // This would ensure less duplicate entries that get cached, currently both of these queries would be cached even though they are // returning the same structured data: // SELECT * FROM MyTable ORDER BY MyColumn @@ -1981,7 +1981,7 @@ namespace Umbraco.Core.Persistence combiner.AddInt(countColumns); key = combiner.GetCombinedHashCode(); } - + var objectCache = _managedCache.GetCache(); @@ -2029,7 +2029,7 @@ namespace Umbraco.Core.Persistence il.Emit(OpCodes.Brfalse_S, lblNotNull); // obj, obj, fieldname, converter?, value il.Emit(OpCodes.Pop); // obj, obj, fieldname, converter? if (converter != null) - il.Emit(OpCodes.Pop); // obj, obj, fieldname, + il.Emit(OpCodes.Pop); // obj, obj, fieldname, il.Emit(OpCodes.Ldnull); // obj, obj, fieldname, null if (converter != null) { @@ -2169,7 +2169,7 @@ namespace Umbraco.Core.Persistence // return it var del = m.CreateDelegate(Expression.GetFuncType(typeof(IDataReader), type)); - + return del; }; @@ -2178,7 +2178,7 @@ namespace Umbraco.Core.Persistence // the line belows returns existing item or adds the new value if it doesn't exist var value = (Lazy)objectCache.AddOrGetExisting(key, newValue, new CacheItemPolicy { - //sliding expiration of 1 hr, if the same key isn't used in this + //sliding expiration of 1 hr, if the same key isn't used in this // timeframe it will be removed from the cache SlidingExpiration = new TimeSpan(0, 0, SlidingExpirationSeconds) }); @@ -2272,7 +2272,7 @@ namespace Umbraco.Core.Persistence public TableInfo TableInfo { get; private set; } public Dictionary Columns { get; private set; } static System.Threading.ReaderWriterLockSlim InnerLock = new System.Threading.ReaderWriterLockSlim(); - + /// /// Returns a report of the current cache being utilized by PetaPoco /// @@ -2286,7 +2286,7 @@ namespace Umbraco.Core.Persistence foreach (var pocoData in m_PocoDatas) { sb.AppendFormat("\t{0}\n", pocoData.Key); - sb.AppendFormat("\t\tTable:{0} - Col count:{1}\n", pocoData.Value.TableInfo.TableName, pocoData.Value.QueryColumns.Length); + sb.AppendFormat("\t\tTable:{0} - Col count:{1}\n", pocoData.Value.TableInfo.TableName, pocoData.Value.QueryColumns.Length); } var cache = managedCache.GetCache(); @@ -2299,7 +2299,7 @@ namespace Umbraco.Core.Persistence totalBytes = Encoding.Unicode.GetByteCount(keys); sb.AppendFormat("\tTotal byte for keys:{0}\n", totalBytes); - + sb.AppendLine("\tAll Poco cache items:"); foreach (var item in cache) diff --git a/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs index 72fb03c498..cecb0e2982 100644 --- a/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs @@ -22,8 +22,7 @@ namespace Umbraco.Core.Persistence public static Sql From(this Sql sql, ISqlSyntaxProvider sqlSyntax) { var type = typeof(T); - var tableNameAttribute = type.FirstAttribute(); - string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value; + var tableName = type.GetTableName(); return sql.From(sqlSyntax.GetQuotedTableName(tableName)); } @@ -51,12 +50,10 @@ namespace Umbraco.Core.Persistence public static Sql OrderBy(this Sql sql, Expression> columnMember, ISqlSyntaxProvider sqlSyntax) { var column = ExpressionHelper.FindProperty(columnMember) as PropertyInfo; - var columnAttribute = column.FirstAttribute(); - var columnName = columnAttribute == null || string.IsNullOrEmpty(columnAttribute.Name) ? column.Name : columnAttribute.Name; + var columnName = column.GetColumnName(); var type = typeof(TColumn); - var tableNameAttribute = type.FirstAttribute(); - string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value; + var tableName = type.GetTableName(); //need to ensure the order by is in brackets, see: https://github.com/toptensoftware/PetaPoco/issues/177 var syntax = string.Format("({0}.{1})", @@ -75,12 +72,10 @@ namespace Umbraco.Core.Persistence public static Sql OrderByDescending(this Sql sql, Expression> columnMember, ISqlSyntaxProvider sqlSyntax) { var column = ExpressionHelper.FindProperty(columnMember) as PropertyInfo; - var columnAttribute = column.FirstAttribute(); - var columnName = columnAttribute == null || string.IsNullOrEmpty(columnAttribute.Name) ? column.Name : columnAttribute.Name; + var columnName = column.GetColumnName(); var type = typeof(TColumn); - var tableNameAttribute = type.FirstAttribute(); - string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value; + var tableName = type.GetTableName(); var syntax = string.Format("{0}.{1} DESC", sqlSyntax.GetQuotedTableName(tableName), @@ -98,8 +93,7 @@ namespace Umbraco.Core.Persistence public static Sql GroupBy(this Sql sql, Expression> columnMember, ISqlSyntaxProvider sqlProvider) { var column = ExpressionHelper.FindProperty(columnMember) as PropertyInfo; - var columnAttribute = column.FirstAttribute(); - var columnName = columnAttribute == null || string.IsNullOrEmpty(columnAttribute.Name) ? column.Name : columnAttribute.Name; + var columnName = column.GetColumnName(); return sql.GroupBy(sqlProvider.GetQuotedColumnName(columnName)); } @@ -113,8 +107,7 @@ namespace Umbraco.Core.Persistence public static Sql.SqlJoinClause InnerJoin(this Sql sql, ISqlSyntaxProvider sqlSyntax) { var type = typeof(T); - var tableNameAttribute = type.FirstAttribute(); - string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value; + var tableName = type.GetTableName(); return sql.InnerJoin(sqlSyntax.GetQuotedTableName(tableName)); } @@ -128,8 +121,7 @@ namespace Umbraco.Core.Persistence public static Sql.SqlJoinClause LeftJoin(this Sql sql, ISqlSyntaxProvider sqlSyntax) { var type = typeof(T); - var tableNameAttribute = type.FirstAttribute(); - string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value; + var tableName = type.GetTableName(); return sql.LeftJoin(sqlSyntax.GetQuotedTableName(tableName)); } @@ -143,8 +135,7 @@ namespace Umbraco.Core.Persistence public static Sql.SqlJoinClause LeftOuterJoin(this Sql sql, ISqlSyntaxProvider sqlSyntax) { var type = typeof(T); - var tableNameAttribute = type.FirstAttribute(); - string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value; + var tableName = type.GetTableName(); return sql.LeftOuterJoin(sqlSyntax.GetQuotedTableName(tableName)); } @@ -158,8 +149,7 @@ namespace Umbraco.Core.Persistence public static Sql.SqlJoinClause RightJoin(this Sql sql, ISqlSyntaxProvider sqlSyntax) { var type = typeof(T); - var tableNameAttribute = type.FirstAttribute(); - string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value; + var tableName = type.GetTableName(); return sql.RightJoin(sqlSyntax.GetQuotedTableName(tableName)); } @@ -176,16 +166,14 @@ namespace Umbraco.Core.Persistence { var leftType = typeof(TLeft); var rightType = typeof(TRight); - var leftTableName = leftType.FirstAttribute().Value; - var rightTableName = rightType.FirstAttribute().Value; + var leftTableName = leftType.GetTableName(); + var rightTableName = rightType.GetTableName(); - var left = ExpressionHelper.FindProperty(leftMember) as PropertyInfo; - var right = ExpressionHelper.FindProperty(rightMember) as PropertyInfo; + var leftColumn = ExpressionHelper.FindProperty(leftMember) as PropertyInfo; + var rightColumn = ExpressionHelper.FindProperty(rightMember) as PropertyInfo; - var leftColumnAttribute = left.FirstAttribute(); - var leftColumnName = leftColumnAttribute == null || string.IsNullOrEmpty(leftColumnAttribute.Name) ? left.Name : leftColumnAttribute.Name; - var rightColumnAttribute = right.FirstAttribute(); - var rightColumnName = rightColumnAttribute == null || string.IsNullOrEmpty(rightColumnAttribute.Name) ? right.Name : rightColumnAttribute.Name; + var leftColumnName = leftColumn.GetColumnName(); + var rightColumnName = rightColumn.GetColumnName(); string onClause = string.Format("{0}.{1} = {2}.{3}", sqlSyntax.GetQuotedTableName(leftTableName), @@ -199,5 +187,20 @@ namespace Umbraco.Core.Persistence { return sql.Append(new Sql("ORDER BY " + String.Join(", ", (from x in columns select x + " DESC").ToArray()))); } + + private static string GetTableName(this Type type) + { + // todo: returning string.Empty for now + // BUT the code bits that calls this method cannot deal with string.Empty so we + // should either throw, or fix these code bits... + var attr = type.FirstAttribute(); + return attr == null || string.IsNullOrWhiteSpace(attr.Value) ? string.Empty : attr.Value; + } + + private static string GetColumnName(this PropertyInfo column) + { + var attr = column.FirstAttribute(); + return attr == null || string.IsNullOrWhiteSpace(attr.Name) ? column.Name : attr.Name; + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs b/src/Umbraco.Core/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs index 2b8afcd3e8..449f5fb3b1 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs @@ -29,11 +29,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax public override string GetQuotedTableName(string tableName) { - if (tableName.Contains(".")) { - var tableNameParts = tableName.Split(new char[] { '.' }, 2); - return string.Format("[{0}].[{1}]", tableNameParts[0], tableNameParts[1]); - } else + if (tableName.Contains(".") == false) return string.Format("[{0}]", tableName); + + var tableNameParts = tableName.Split(new[] { '.' }, 2); + return string.Format("[{0}].[{1}]", tableNameParts[0], tableNameParts[1]); } public override string GetQuotedColumnName(string columnName)