From a40f87eb3699670eee3181e3a1373b462e1a2ec4 Mon Sep 17 00:00:00 2001 From: Jeremy Pyne Date: Thu, 14 Jul 2016 17:01:51 -0400 Subject: [PATCH 1/3] Fixed an issues with user generated PetaPoco's would not work if they included schema's. Fixed an issue where strong typed helper methods would not generate valid SQL for column names if the poco didn't explicitly set a [Column(Name="")] attribute. The PetaPoco format allows for this though and will default to the property name. Again this would cause issues for developers trying to use the DatabaseContext.Database class with their own Poco's. Both the above causes would happen for example if using the PetaPoco T4 templates to automatically generate Poco's. --- .../Persistence/PetaPocoSqlExtensions.cs | 16 +++++++++++----- .../SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs | 6 +++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs index 3cbd70803d..72fb03c498 100644 --- a/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs @@ -51,7 +51,8 @@ namespace Umbraco.Core.Persistence public static Sql OrderBy(this Sql sql, Expression> columnMember, ISqlSyntaxProvider sqlSyntax) { var column = ExpressionHelper.FindProperty(columnMember) as PropertyInfo; - var columnName = column.FirstAttribute().Name; + var columnAttribute = column.FirstAttribute(); + var columnName = columnAttribute == null || string.IsNullOrEmpty(columnAttribute.Name) ? column.Name : columnAttribute.Name; var type = typeof(TColumn); var tableNameAttribute = type.FirstAttribute(); @@ -74,7 +75,8 @@ namespace Umbraco.Core.Persistence public static Sql OrderByDescending(this Sql sql, Expression> columnMember, ISqlSyntaxProvider sqlSyntax) { var column = ExpressionHelper.FindProperty(columnMember) as PropertyInfo; - var columnName = column.FirstAttribute().Name; + var columnAttribute = column.FirstAttribute(); + var columnName = columnAttribute == null || string.IsNullOrEmpty(columnAttribute.Name) ? column.Name : columnAttribute.Name; var type = typeof(TColumn); var tableNameAttribute = type.FirstAttribute(); @@ -96,7 +98,8 @@ namespace Umbraco.Core.Persistence public static Sql GroupBy(this Sql sql, Expression> columnMember, ISqlSyntaxProvider sqlProvider) { var column = ExpressionHelper.FindProperty(columnMember) as PropertyInfo; - var columnName = column.FirstAttribute().Name; + var columnAttribute = column.FirstAttribute(); + var columnName = columnAttribute == null || string.IsNullOrEmpty(columnAttribute.Name) ? column.Name : columnAttribute.Name; return sql.GroupBy(sqlProvider.GetQuotedColumnName(columnName)); } @@ -178,8 +181,11 @@ namespace Umbraco.Core.Persistence var left = ExpressionHelper.FindProperty(leftMember) as PropertyInfo; var right = ExpressionHelper.FindProperty(rightMember) as PropertyInfo; - var leftColumnName = left.FirstAttribute().Name; - var rightColumnName = right.FirstAttribute().Name; + + 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; string onClause = string.Format("{0}.{1} = {2}.{3}", sqlSyntax.GetQuotedTableName(leftTableName), diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs b/src/Umbraco.Core/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs index a6d1d690ba..2b8afcd3e8 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs @@ -29,7 +29,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax public override string GetQuotedTableName(string tableName) { - return string.Format("[{0}]", tableName); + if (tableName.Contains(".")) { + var tableNameParts = tableName.Split(new char[] { '.' }, 2); + return string.Format("[{0}].[{1}]", tableNameParts[0], tableNameParts[1]); + } else + return string.Format("[{0}]", tableName); } public override string GetQuotedColumnName(string columnName) From 2e24923cc400ec63df4dbb8afa5f21518d8cc34d Mon Sep 17 00:00:00 2001 From: Jeremy Pyne Date: Mon, 18 Jul 2016 09:00:23 -0400 Subject: [PATCH 2/3] Update PetaPoco.cs Sql() class should reset build cache when new Append operations are called. If not then stepping through with the debugger or doing internal logging can cause invalid SQL and unexpected results. --- src/Umbraco.Core/Persistence/PetaPoco.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Core/Persistence/PetaPoco.cs b/src/Umbraco.Core/Persistence/PetaPoco.cs index 88f90639d1..32f9024d49 100644 --- a/src/Umbraco.Core/Persistence/PetaPoco.cs +++ b/src/Umbraco.Core/Persistence/PetaPoco.cs @@ -2417,6 +2417,7 @@ namespace Umbraco.Core.Persistence else _rhs = sql; + _sqlFinal = null; return this; } From 2481b77f038b913e2c0c6c9267dac15322b10b7a Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 19 Jul 2016 11:13:49 +0200 Subject: [PATCH 3/3] U4-8729 - reviewing PR --- src/Umbraco.Core/Persistence/PetaPoco.cs | 110 +++++++++--------- .../Persistence/PetaPocoSqlExtensions.cs | 59 +++++----- .../MicrosoftSqlSyntaxProviderBase.cs | 8 +- 3 files changed, 90 insertions(+), 87 deletions(-) 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)