Adds ability to use the query builder with string matches based on an NText column
This commit is contained in:
@@ -21,14 +21,18 @@ namespace Umbraco.Core.Persistence
|
||||
/// <summary>
|
||||
/// This will escape single @ symbols for peta poco values so it doesn't think it's a parameter
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string EscapeAtSymbols(this Database db, string value)
|
||||
public static string EscapeAtSymbols(string value)
|
||||
{
|
||||
//this fancy regex will only match a single @ not a double, etc...
|
||||
var regex = new Regex("(?<!@)@(?!@)");
|
||||
return regex.Replace(value, "@@");
|
||||
if (value.Contains("@"))
|
||||
{
|
||||
//this fancy regex will only match a single @ not a double, etc...
|
||||
var regex = new Regex("(?<!@)@(?!@)");
|
||||
return regex.Replace(value, "@@");
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
public static void CreateTable<T>(this Database db)
|
||||
|
||||
@@ -64,13 +64,7 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
|
||||
public virtual string EscapeAtArgument(string exp)
|
||||
{
|
||||
/*if (exp.StartsWith("@"))
|
||||
return string.Concat("@", exp);*/
|
||||
|
||||
if (exp.Contains("@"))
|
||||
return exp.Replace("@", "@@");
|
||||
|
||||
return exp;
|
||||
return PetaPocoExtensions.EscapeAtSymbols(exp);
|
||||
}
|
||||
|
||||
public virtual bool ShouldQuoteValue(Type fieldType)
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
@@ -226,6 +228,39 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
|
||||
}
|
||||
|
||||
private string HandleStringComparison(string col, string val, string verb, TextColumnType columnType)
|
||||
{
|
||||
switch (verb)
|
||||
{
|
||||
case "Equals":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
|
||||
case "StartsWith":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnStartsWithComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
|
||||
case "EndsWith":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEndsWithComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
|
||||
case "Contains":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnContainsComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
|
||||
case "InvariantEquals":
|
||||
case "SqlEquals":
|
||||
//recurse
|
||||
return HandleStringComparison(col, val, "Equals", columnType);
|
||||
case "InvariantStartsWith":
|
||||
case "SqlStartsWith":
|
||||
//recurse
|
||||
return HandleStringComparison(col, val, "StartsWith", columnType);
|
||||
case "InvariantEndsWith":
|
||||
case "SqlEndsWith":
|
||||
//recurse
|
||||
return HandleStringComparison(col, val, "EndsWith", columnType);
|
||||
case "InvariantContains":
|
||||
case "SqlContains":
|
||||
//recurse
|
||||
return HandleStringComparison(col, val, "Contains", columnType);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("verb");
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
List<Object> args = this.VisitExpressionList(m.Arguments);
|
||||
@@ -245,12 +280,31 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
return string.Format("upper({0})", r);
|
||||
case "ToLower":
|
||||
return string.Format("lower({0})", r);
|
||||
|
||||
case "StartsWith":
|
||||
return string.Format("upper({0}) like '{1}%'", r, EscapeAtArgument(RemoveQuote(args[0].ToString().ToUpper())));
|
||||
case "EndsWith":
|
||||
return string.Format("upper({0}) like '%{1}'", r, EscapeAtArgument(RemoveQuote(args[0].ToString()).ToUpper()));
|
||||
case "Contains":
|
||||
return string.Format("{0} like '%{1}%'", r, EscapeAtArgument(RemoveQuote(args[0].ToString()).ToUpper()));
|
||||
case "Equals":
|
||||
case "SqlStartsWith":
|
||||
case "SqlEndsWith":
|
||||
case "SqlContains":
|
||||
case "SqlEquals":
|
||||
case "InvariantStartsWith":
|
||||
case "InvariantEndsWith":
|
||||
case "InvariantContains":
|
||||
case "InvariantEquals":
|
||||
//default
|
||||
var colType = TextColumnType.NVarchar;
|
||||
//then check if this arg has been passed in
|
||||
if (m.Arguments.Count > 1)
|
||||
{
|
||||
var colTypeArg = m.Arguments.FirstOrDefault(x => x is ConstantExpression && x.Type == typeof(TextColumnType));
|
||||
if (colTypeArg != null)
|
||||
{
|
||||
colType = (TextColumnType) ((ConstantExpression) colTypeArg).Value;
|
||||
}
|
||||
}
|
||||
return HandleStringComparison(r.ToString(), args[0].ToString(), m.Method.Name, colType);
|
||||
case "Substring":
|
||||
var startIndex = Int32.Parse(args[0].ToString()) + 1;
|
||||
if (args.Count == 2)
|
||||
|
||||
30
src/Umbraco.Core/Persistence/Querying/SqlStringExtensions.cs
Normal file
30
src/Umbraco.Core/Persistence/Querying/SqlStringExtensions.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
/// <summary>
|
||||
/// String extension methods used specifically to translate into SQL
|
||||
/// </summary>
|
||||
internal static class SqlStringExtensions
|
||||
{
|
||||
public static bool SqlContains(this string str, string txt, TextColumnType columnType)
|
||||
{
|
||||
return str.InvariantContains(txt);
|
||||
}
|
||||
|
||||
public static bool SqlEquals(this string str, string txt, TextColumnType columnType)
|
||||
{
|
||||
return str.InvariantEquals(txt);
|
||||
}
|
||||
|
||||
public static bool SqlStartsWith(this string str, string txt, TextColumnType columnType)
|
||||
{
|
||||
return str.InvariantStartsWith(txt);
|
||||
}
|
||||
|
||||
public static bool SqlEndsWith(this string str, string txt, TextColumnType columnType)
|
||||
{
|
||||
return str.InvariantEndsWith(txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/Umbraco.Core/Persistence/Querying/TextColumnType.cs
Normal file
8
src/Umbraco.Core/Persistence/Querying/TextColumnType.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
public enum TextColumnType
|
||||
{
|
||||
NVarchar,
|
||||
NText
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
@@ -10,6 +11,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// </summary>
|
||||
public interface ISqlSyntaxProvider
|
||||
{
|
||||
string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType);
|
||||
string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType);
|
||||
string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType);
|
||||
string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType);
|
||||
|
||||
string GetQuotedTableName(string tableName);
|
||||
string GetQuotedColumnName(string columnName);
|
||||
string GetQuotedName(string name);
|
||||
|
||||
10
src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntax.cs
Normal file
10
src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntax.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the MySql SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class MySqlSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new MySqlSyntaxProvider(); } }
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,6 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the MySql SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class MySqlSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new MySqlSyntaxProvider(); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for MySql
|
||||
/// </summary>
|
||||
|
||||
10
src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntax.cs
Normal file
10
src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntax.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the Sql CE SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class SqlCeSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new SqlCeSyntaxProvider(); } }
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,10 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the Sql CE SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class SqlCeSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new SqlCeSyntaxProvider(); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for Sql Ce
|
||||
/// </summary>
|
||||
@@ -67,6 +60,62 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return indexType;
|
||||
}
|
||||
|
||||
public override string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnEqualComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for = comparison with NText columns but allows this syntax
|
||||
return string.Format("{0} LIKE '{1}'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnStartsWithComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '{1}%'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnEndsWithComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '%{1}'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnContainsComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '%{1}%'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("[{0}]", tableName);
|
||||
|
||||
10
src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntax.cs
Normal file
10
src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntax.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the Sql Server SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class SqlServerSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new SqlServerSyntaxProvider(); } }
|
||||
}
|
||||
}
|
||||
@@ -2,31 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the Sql Server SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class SqlServerSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new SqlServerSyntaxProvider(); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the version name of SQL server (i.e. the year 2008, 2005, etc...)
|
||||
/// </summary>
|
||||
internal enum SqlServerVersionName
|
||||
{
|
||||
Invalid = -1,
|
||||
V7 = 0,
|
||||
V2000 = 1,
|
||||
V2005 = 2,
|
||||
V2008 = 3,
|
||||
V2012 = 4,
|
||||
Other = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for Sql Server
|
||||
/// </summary>
|
||||
@@ -55,6 +34,62 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// </summary>
|
||||
internal Lazy<SqlServerVersionName> VersionName { get; set; }
|
||||
|
||||
public override string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnEqualComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for = comparison with NText columns but allows this syntax
|
||||
return string.Format("{0} LIKE '{1}'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnStartsWithComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '{1}%'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnEndsWithComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '%{1}'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnContainsComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '%{1}%'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("[{0}]", tableName);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the version name of SQL server (i.e. the year 2008, 2005, etc...)
|
||||
/// </summary>
|
||||
internal enum SqlServerVersionName
|
||||
{
|
||||
Invalid = -1,
|
||||
V7 = 0,
|
||||
V2000 = 1,
|
||||
V2005 = 2,
|
||||
V2008 = 3,
|
||||
V2012 = 4,
|
||||
Other = 5
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
@@ -102,6 +103,30 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
DbTypeMap.Set<byte[]>(DbType.Binary, BlobColumnDefinition);
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
||||
return string.Format("upper({0}) = '{1}'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
||||
return string.Format("upper({0}) like '{1}%'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
||||
return string.Format("upper({0}) like '%{1}'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
||||
return string.Format("upper({0}) like '%{1}%'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("\"{0}\"", tableName);
|
||||
|
||||
@@ -465,6 +465,11 @@ namespace Umbraco.Core
|
||||
return compare.StartsWith(compareTo, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool InvariantEndsWith(this string compare, string compareTo)
|
||||
{
|
||||
return compare.EndsWith(compareTo, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool InvariantContains(this string compare, string compareTo)
|
||||
{
|
||||
return compare.IndexOf(compareTo, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
|
||||
@@ -200,6 +200,12 @@
|
||||
<Compile Include="Models\PublishedContent\PublishedContentModel.cs" />
|
||||
<Compile Include="Models\PublishedContent\PublishedContentModelFactoryResolver.cs" />
|
||||
<Compile Include="Models\TemplateNode.cs" />
|
||||
<Compile Include="Persistence\Querying\SqlStringExtensions.cs" />
|
||||
<Compile Include="Persistence\Querying\TextColumnType.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\MySqlSyntax.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\SqlCeSyntax.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\SqlServerSyntax.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\SqlServerVersionName.cs" />
|
||||
<Compile Include="PropertyEditors\PropertyCacheValue.cs" />
|
||||
<Compile Include="PropertyEditors\PropertyValueCacheAttribute.cs" />
|
||||
<Compile Include="PropertyEditors\PropertyValueTypeAttribute.cs" />
|
||||
|
||||
Reference in New Issue
Block a user