Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1eab26c0f6 | |||
| 0543c620eb | |||
| 646e5f173d | |||
| b5594517bd | |||
| 246dfba8ac | |||
| 7d189a6fb8 | |||
| 71242430da | |||
| 4ee4f296fc | |||
| b9e4950e36 | |||
| ba52f9235e |
+1
-1
@@ -1,5 +1,5 @@
|
||||
@ECHO OFF
|
||||
SET release=6.2.2
|
||||
SET release=6.2.3
|
||||
SET comment=
|
||||
SET version=%release%
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoCms.Core</id>
|
||||
<version>6.2.2</version>
|
||||
<version>6.2.3</version>
|
||||
<title>Umbraco Cms Core Binaries</title>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoCms</id>
|
||||
<version>6.2.2</version>
|
||||
<version>6.2.3</version>
|
||||
<title>Umbraco Cms</title>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<UmbracoVersion>6.2.2</UmbracoVersion>
|
||||
<UmbracoVersion>6.2.4</UmbracoVersion>
|
||||
</PropertyGroup>
|
||||
<Target Name="CopyUmbracoFilesToWebRoot" BeforeTargets="AfterBuild">
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("6.2.2");
|
||||
private static readonly Version Version = new Version("6.2.4");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -34,6 +34,12 @@ namespace Umbraco.Core
|
||||
AddInt(d.GetHashCode());
|
||||
}
|
||||
|
||||
internal void AddString(string s)
|
||||
{
|
||||
if (s != null)
|
||||
AddInt((StringComparer.InvariantCulture).GetHashCode(s));
|
||||
}
|
||||
|
||||
internal void AddCaseInsensitiveString(string s)
|
||||
{
|
||||
if (s != null)
|
||||
|
||||
@@ -99,11 +99,13 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
foreach (var propertyDto in dto.UmbracoPropertyDtos)
|
||||
{
|
||||
entity.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty
|
||||
{
|
||||
DataTypeControlId =
|
||||
propertyDto.DataTypeControlId,
|
||||
Value = propertyDto.UmbracoFile
|
||||
});
|
||||
{
|
||||
DataTypeControlId =
|
||||
propertyDto.DataTypeControlId,
|
||||
Value = propertyDto.NTextValue.IsNullOrWhiteSpace()
|
||||
? propertyDto.NVarcharValue
|
||||
: propertyDto.NTextValue
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Caching;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
@@ -1709,8 +1710,32 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
public override object ChangeType(object val) { return val; }
|
||||
}
|
||||
public class PocoData
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Container for a Memory cache object
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Better to have one memory cache instance than many so it's memory management can be handled more effectively
|
||||
/// http://stackoverflow.com/questions/8463962/using-multiple-instances-of-memorycache
|
||||
/// </remarks>
|
||||
internal class ManagedCache
|
||||
{
|
||||
public ObjectCache GetCache()
|
||||
{
|
||||
return ObjectCache;
|
||||
}
|
||||
|
||||
static readonly ObjectCache ObjectCache = new MemoryCache("NPoco");
|
||||
|
||||
}
|
||||
|
||||
public class PocoData
|
||||
{
|
||||
//USE ONLY FOR TESTING
|
||||
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();
|
||||
@@ -1734,7 +1759,7 @@ namespace Umbraco.Core.Persistence
|
||||
#endif
|
||||
return ForType(t);
|
||||
}
|
||||
static System.Threading.ReaderWriterLockSlim RWLock = new System.Threading.ReaderWriterLockSlim();
|
||||
|
||||
public static PocoData ForType(Type t)
|
||||
{
|
||||
#if !PETAPOCO_NO_DYNAMIC
|
||||
@@ -1742,7 +1767,7 @@ namespace Umbraco.Core.Persistence
|
||||
throw new InvalidOperationException("Can't use dynamic types with this method");
|
||||
#endif
|
||||
// Check cache
|
||||
RWLock.EnterReadLock();
|
||||
InnerLock.EnterReadLock();
|
||||
PocoData pd;
|
||||
try
|
||||
{
|
||||
@@ -1751,12 +1776,12 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock.ExitReadLock();
|
||||
InnerLock.ExitReadLock();
|
||||
}
|
||||
|
||||
|
||||
// Cache it
|
||||
RWLock.EnterWriteLock();
|
||||
InnerLock.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
// Check again
|
||||
@@ -1770,7 +1795,7 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock.ExitWriteLock();
|
||||
InnerLock.ExitWriteLock();
|
||||
}
|
||||
|
||||
return pd;
|
||||
@@ -1851,224 +1876,237 @@ namespace Umbraco.Core.Persistence
|
||||
return tc >= TypeCode.SByte && tc <= TypeCode.UInt64;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Create factory function that can convert a IDataReader record into a POCO
|
||||
public Delegate GetFactory(string sql, string connString, bool ForceDateTimesToUtc, int firstColumn, int countColumns, IDataReader r)
|
||||
{
|
||||
// Check cache
|
||||
var key = string.Format("{0}:{1}:{2}:{3}:{4}", sql, connString, ForceDateTimesToUtc, firstColumn, countColumns);
|
||||
RWLock.EnterReadLock();
|
||||
try
|
||||
{
|
||||
// Have we already created it?
|
||||
Delegate factory;
|
||||
if (PocoFactories.TryGetValue(key, out factory))
|
||||
return factory;
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock.ExitReadLock();
|
||||
}
|
||||
|
||||
// Take the writer lock
|
||||
RWLock.EnterWriteLock();
|
||||
//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
|
||||
// SELECT * FROM MyTable ORDER BY MyColumn DESC
|
||||
|
||||
try
|
||||
{
|
||||
string key;
|
||||
if (UseLongKeys)
|
||||
{
|
||||
key = string.Format("{0}:{1}:{2}:{3}:{4}", sql, connString, ForceDateTimesToUtc, firstColumn, countColumns);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Create a hashed key, we don't want to store so much string data in memory
|
||||
var combiner = new HashCodeCombiner();
|
||||
combiner.AddCaseInsensitiveString(sql);
|
||||
combiner.AddCaseInsensitiveString(connString);
|
||||
combiner.AddObject(ForceDateTimesToUtc);
|
||||
combiner.AddInt(firstColumn);
|
||||
combiner.AddInt(countColumns);
|
||||
key = combiner.GetCombinedHashCode();
|
||||
}
|
||||
|
||||
|
||||
// Check again, just in case
|
||||
Delegate factory;
|
||||
if (PocoFactories.TryGetValue(key, out factory))
|
||||
return factory;
|
||||
var objectCache = _managedCache.GetCache();
|
||||
|
||||
// Create the method
|
||||
var m = new DynamicMethod("petapoco_factory_" + PocoFactories.Count.ToString(), type, new Type[] { typeof(IDataReader) }, true);
|
||||
var il = m.GetILGenerator();
|
||||
Func<Delegate> factory = () =>
|
||||
{
|
||||
// Create the method
|
||||
var m = new DynamicMethod("petapoco_factory_" + objectCache.GetCount(), type, new Type[] { typeof(IDataReader) }, true);
|
||||
var il = m.GetILGenerator();
|
||||
|
||||
#if !PETAPOCO_NO_DYNAMIC
|
||||
if (type == typeof(object))
|
||||
{
|
||||
// var poco=new T()
|
||||
il.Emit(OpCodes.Newobj, typeof(System.Dynamic.ExpandoObject).GetConstructor(Type.EmptyTypes)); // obj
|
||||
if (type == typeof(object))
|
||||
{
|
||||
// var poco=new T()
|
||||
il.Emit(OpCodes.Newobj, typeof(System.Dynamic.ExpandoObject).GetConstructor(Type.EmptyTypes)); // obj
|
||||
|
||||
MethodInfo fnAdd = typeof(IDictionary<string, object>).GetMethod("Add");
|
||||
MethodInfo fnAdd = typeof(IDictionary<string, object>).GetMethod("Add");
|
||||
|
||||
// Enumerate all fields generating a set assignment for the column
|
||||
for (int i = firstColumn; i < firstColumn + countColumns; i++)
|
||||
{
|
||||
var srcType = r.GetFieldType(i);
|
||||
// Enumerate all fields generating a set assignment for the column
|
||||
for (int i = firstColumn; i < firstColumn + countColumns; i++)
|
||||
{
|
||||
var srcType = r.GetFieldType(i);
|
||||
|
||||
il.Emit(OpCodes.Dup); // obj, obj
|
||||
il.Emit(OpCodes.Ldstr, r.GetName(i)); // obj, obj, fieldname
|
||||
il.Emit(OpCodes.Dup); // obj, obj
|
||||
il.Emit(OpCodes.Ldstr, r.GetName(i)); // obj, obj, fieldname
|
||||
|
||||
// Get the converter
|
||||
Func<object, object> converter = null;
|
||||
if (Database.Mapper != null)
|
||||
converter = Database.Mapper.GetFromDbConverter(null, srcType);
|
||||
if (ForceDateTimesToUtc && converter == null && srcType == typeof(DateTime))
|
||||
converter = delegate(object src) { return new DateTime(((DateTime)src).Ticks, DateTimeKind.Utc); };
|
||||
// Get the converter
|
||||
Func<object, object> converter = null;
|
||||
if (Database.Mapper != null)
|
||||
converter = Database.Mapper.GetFromDbConverter(null, srcType);
|
||||
if (ForceDateTimesToUtc && converter == null && srcType == typeof(DateTime))
|
||||
converter = delegate(object src) { return new DateTime(((DateTime)src).Ticks, DateTimeKind.Utc); };
|
||||
|
||||
// Setup stack for call to converter
|
||||
AddConverterToStack(il, converter);
|
||||
// Setup stack for call to converter
|
||||
AddConverterToStack(il, converter);
|
||||
|
||||
// r[i]
|
||||
il.Emit(OpCodes.Ldarg_0); // obj, obj, fieldname, converter?, rdr
|
||||
il.Emit(OpCodes.Ldc_I4, i); // obj, obj, fieldname, converter?, rdr,i
|
||||
il.Emit(OpCodes.Callvirt, fnGetValue); // obj, obj, fieldname, converter?, value
|
||||
// r[i]
|
||||
il.Emit(OpCodes.Ldarg_0); // obj, obj, fieldname, converter?, rdr
|
||||
il.Emit(OpCodes.Ldc_I4, i); // obj, obj, fieldname, converter?, rdr,i
|
||||
il.Emit(OpCodes.Callvirt, fnGetValue); // obj, obj, fieldname, converter?, value
|
||||
|
||||
// Convert DBNull to null
|
||||
il.Emit(OpCodes.Dup); // obj, obj, fieldname, converter?, value, value
|
||||
il.Emit(OpCodes.Isinst, typeof(DBNull)); // obj, obj, fieldname, converter?, value, (value or null)
|
||||
var lblNotNull = il.DefineLabel();
|
||||
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.Ldnull); // obj, obj, fieldname, null
|
||||
if (converter != null)
|
||||
{
|
||||
var lblReady = il.DefineLabel();
|
||||
il.Emit(OpCodes.Br_S, lblReady);
|
||||
il.MarkLabel(lblNotNull);
|
||||
il.Emit(OpCodes.Callvirt, fnInvoke);
|
||||
il.MarkLabel(lblReady);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.MarkLabel(lblNotNull);
|
||||
}
|
||||
// Convert DBNull to null
|
||||
il.Emit(OpCodes.Dup); // obj, obj, fieldname, converter?, value, value
|
||||
il.Emit(OpCodes.Isinst, typeof(DBNull)); // obj, obj, fieldname, converter?, value, (value or null)
|
||||
var lblNotNull = il.DefineLabel();
|
||||
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.Ldnull); // obj, obj, fieldname, null
|
||||
if (converter != null)
|
||||
{
|
||||
var lblReady = il.DefineLabel();
|
||||
il.Emit(OpCodes.Br_S, lblReady);
|
||||
il.MarkLabel(lblNotNull);
|
||||
il.Emit(OpCodes.Callvirt, fnInvoke);
|
||||
il.MarkLabel(lblReady);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.MarkLabel(lblNotNull);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Callvirt, fnAdd);
|
||||
}
|
||||
}
|
||||
else
|
||||
il.Emit(OpCodes.Callvirt, fnAdd);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (type.IsValueType || type == typeof(string) || type == typeof(byte[]))
|
||||
{
|
||||
// Do we need to install a converter?
|
||||
var srcType = r.GetFieldType(0);
|
||||
var converter = GetConverter(ForceDateTimesToUtc, null, srcType, type);
|
||||
if (type.IsValueType || type == typeof(string) || type == typeof(byte[]))
|
||||
{
|
||||
// Do we need to install a converter?
|
||||
var srcType = r.GetFieldType(0);
|
||||
var converter = GetConverter(ForceDateTimesToUtc, null, srcType, type);
|
||||
|
||||
// "if (!rdr.IsDBNull(i))"
|
||||
il.Emit(OpCodes.Ldarg_0); // rdr
|
||||
il.Emit(OpCodes.Ldc_I4_0); // rdr,0
|
||||
il.Emit(OpCodes.Callvirt, fnIsDBNull); // bool
|
||||
var lblCont = il.DefineLabel();
|
||||
il.Emit(OpCodes.Brfalse_S, lblCont);
|
||||
il.Emit(OpCodes.Ldnull); // null
|
||||
var lblFin = il.DefineLabel();
|
||||
il.Emit(OpCodes.Br_S, lblFin);
|
||||
// "if (!rdr.IsDBNull(i))"
|
||||
il.Emit(OpCodes.Ldarg_0); // rdr
|
||||
il.Emit(OpCodes.Ldc_I4_0); // rdr,0
|
||||
il.Emit(OpCodes.Callvirt, fnIsDBNull); // bool
|
||||
var lblCont = il.DefineLabel();
|
||||
il.Emit(OpCodes.Brfalse_S, lblCont);
|
||||
il.Emit(OpCodes.Ldnull); // null
|
||||
var lblFin = il.DefineLabel();
|
||||
il.Emit(OpCodes.Br_S, lblFin);
|
||||
|
||||
il.MarkLabel(lblCont);
|
||||
il.MarkLabel(lblCont);
|
||||
|
||||
// Setup stack for call to converter
|
||||
AddConverterToStack(il, converter);
|
||||
// Setup stack for call to converter
|
||||
AddConverterToStack(il, converter);
|
||||
|
||||
il.Emit(OpCodes.Ldarg_0); // rdr
|
||||
il.Emit(OpCodes.Ldc_I4_0); // rdr,0
|
||||
il.Emit(OpCodes.Callvirt, fnGetValue); // value
|
||||
il.Emit(OpCodes.Ldarg_0); // rdr
|
||||
il.Emit(OpCodes.Ldc_I4_0); // rdr,0
|
||||
il.Emit(OpCodes.Callvirt, fnGetValue); // value
|
||||
|
||||
// Call the converter
|
||||
if (converter != null)
|
||||
il.Emit(OpCodes.Callvirt, fnInvoke);
|
||||
// Call the converter
|
||||
if (converter != null)
|
||||
il.Emit(OpCodes.Callvirt, fnInvoke);
|
||||
|
||||
il.MarkLabel(lblFin);
|
||||
il.Emit(OpCodes.Unbox_Any, type); // value converted
|
||||
}
|
||||
else
|
||||
{
|
||||
// var poco=new T()
|
||||
il.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null));
|
||||
il.MarkLabel(lblFin);
|
||||
il.Emit(OpCodes.Unbox_Any, type); // value converted
|
||||
}
|
||||
else
|
||||
{
|
||||
// var poco=new T()
|
||||
il.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null));
|
||||
|
||||
// Enumerate all fields generating a set assignment for the column
|
||||
for (int i = firstColumn; i < firstColumn + countColumns; i++)
|
||||
{
|
||||
// Get the PocoColumn for this db column, ignore if not known
|
||||
PocoColumn pc;
|
||||
if (!Columns.TryGetValue(r.GetName(i), out pc))
|
||||
continue;
|
||||
// Enumerate all fields generating a set assignment for the column
|
||||
for (int i = firstColumn; i < firstColumn + countColumns; i++)
|
||||
{
|
||||
// Get the PocoColumn for this db column, ignore if not known
|
||||
PocoColumn pc;
|
||||
if (!Columns.TryGetValue(r.GetName(i), out pc))
|
||||
continue;
|
||||
|
||||
// Get the source type for this column
|
||||
var srcType = r.GetFieldType(i);
|
||||
var dstType = pc.PropertyInfo.PropertyType;
|
||||
// Get the source type for this column
|
||||
var srcType = r.GetFieldType(i);
|
||||
var dstType = pc.PropertyInfo.PropertyType;
|
||||
|
||||
// "if (!rdr.IsDBNull(i))"
|
||||
il.Emit(OpCodes.Ldarg_0); // poco,rdr
|
||||
il.Emit(OpCodes.Ldc_I4, i); // poco,rdr,i
|
||||
il.Emit(OpCodes.Callvirt, fnIsDBNull); // poco,bool
|
||||
var lblNext = il.DefineLabel();
|
||||
il.Emit(OpCodes.Brtrue_S, lblNext); // poco
|
||||
// "if (!rdr.IsDBNull(i))"
|
||||
il.Emit(OpCodes.Ldarg_0); // poco,rdr
|
||||
il.Emit(OpCodes.Ldc_I4, i); // poco,rdr,i
|
||||
il.Emit(OpCodes.Callvirt, fnIsDBNull); // poco,bool
|
||||
var lblNext = il.DefineLabel();
|
||||
il.Emit(OpCodes.Brtrue_S, lblNext); // poco
|
||||
|
||||
il.Emit(OpCodes.Dup); // poco,poco
|
||||
il.Emit(OpCodes.Dup); // poco,poco
|
||||
|
||||
// Do we need to install a converter?
|
||||
var converter = GetConverter(ForceDateTimesToUtc, pc, srcType, dstType);
|
||||
// Do we need to install a converter?
|
||||
var converter = GetConverter(ForceDateTimesToUtc, pc, srcType, dstType);
|
||||
|
||||
// Fast
|
||||
bool Handled = false;
|
||||
if (converter == null)
|
||||
{
|
||||
var valuegetter = typeof(IDataRecord).GetMethod("Get" + srcType.Name, new Type[] { typeof(int) });
|
||||
if (valuegetter != null
|
||||
&& valuegetter.ReturnType == srcType
|
||||
&& (valuegetter.ReturnType == dstType || valuegetter.ReturnType == Nullable.GetUnderlyingType(dstType)))
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_0); // *,rdr
|
||||
il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i
|
||||
il.Emit(OpCodes.Callvirt, valuegetter); // *,value
|
||||
// Fast
|
||||
bool Handled = false;
|
||||
if (converter == null)
|
||||
{
|
||||
var valuegetter = typeof(IDataRecord).GetMethod("Get" + srcType.Name, new Type[] { typeof(int) });
|
||||
if (valuegetter != null
|
||||
&& valuegetter.ReturnType == srcType
|
||||
&& (valuegetter.ReturnType == dstType || valuegetter.ReturnType == Nullable.GetUnderlyingType(dstType)))
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_0); // *,rdr
|
||||
il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i
|
||||
il.Emit(OpCodes.Callvirt, valuegetter); // *,value
|
||||
|
||||
// Convert to Nullable
|
||||
if (Nullable.GetUnderlyingType(dstType) != null)
|
||||
{
|
||||
il.Emit(OpCodes.Newobj, dstType.GetConstructor(new Type[] { Nullable.GetUnderlyingType(dstType) }));
|
||||
}
|
||||
// Convert to Nullable
|
||||
if (Nullable.GetUnderlyingType(dstType) != null)
|
||||
{
|
||||
il.Emit(OpCodes.Newobj, dstType.GetConstructor(new Type[] { Nullable.GetUnderlyingType(dstType) }));
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod(true)); // poco
|
||||
Handled = true;
|
||||
}
|
||||
}
|
||||
il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod(true)); // poco
|
||||
Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Not so fast
|
||||
if (!Handled)
|
||||
{
|
||||
// Setup stack for call to converter
|
||||
AddConverterToStack(il, converter);
|
||||
// Not so fast
|
||||
if (!Handled)
|
||||
{
|
||||
// Setup stack for call to converter
|
||||
AddConverterToStack(il, converter);
|
||||
|
||||
// "value = rdr.GetValue(i)"
|
||||
il.Emit(OpCodes.Ldarg_0); // *,rdr
|
||||
il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i
|
||||
il.Emit(OpCodes.Callvirt, fnGetValue); // *,value
|
||||
// "value = rdr.GetValue(i)"
|
||||
il.Emit(OpCodes.Ldarg_0); // *,rdr
|
||||
il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i
|
||||
il.Emit(OpCodes.Callvirt, fnGetValue); // *,value
|
||||
|
||||
// Call the converter
|
||||
if (converter != null)
|
||||
il.Emit(OpCodes.Callvirt, fnInvoke);
|
||||
// Call the converter
|
||||
if (converter != null)
|
||||
il.Emit(OpCodes.Callvirt, fnInvoke);
|
||||
|
||||
// Assign it
|
||||
il.Emit(OpCodes.Unbox_Any, pc.PropertyInfo.PropertyType); // poco,poco,value
|
||||
il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod(true)); // poco
|
||||
}
|
||||
// Assign it
|
||||
il.Emit(OpCodes.Unbox_Any, pc.PropertyInfo.PropertyType); // poco,poco,value
|
||||
il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod(true)); // poco
|
||||
}
|
||||
|
||||
il.MarkLabel(lblNext);
|
||||
}
|
||||
il.MarkLabel(lblNext);
|
||||
}
|
||||
|
||||
var fnOnLoaded = RecurseInheritedTypes<MethodInfo>(type, (x) => x.GetMethod("OnLoaded", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null));
|
||||
if (fnOnLoaded != null)
|
||||
{
|
||||
il.Emit(OpCodes.Dup);
|
||||
il.Emit(OpCodes.Callvirt, fnOnLoaded);
|
||||
}
|
||||
}
|
||||
var fnOnLoaded = RecurseInheritedTypes<MethodInfo>(type, (x) => x.GetMethod("OnLoaded", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null));
|
||||
if (fnOnLoaded != null)
|
||||
{
|
||||
il.Emit(OpCodes.Dup);
|
||||
il.Emit(OpCodes.Callvirt, fnOnLoaded);
|
||||
}
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Ret);
|
||||
il.Emit(OpCodes.Ret);
|
||||
|
||||
// return it
|
||||
var del = m.CreateDelegate(Expression.GetFuncType(typeof(IDataReader), type));
|
||||
|
||||
return del;
|
||||
};
|
||||
|
||||
//lazy usage of AddOrGetExisting ref: http://stackoverflow.com/questions/10559279/how-to-deal-with-costly-building-operations-using-memorycache/15894928#15894928
|
||||
var newValue = new Lazy<Delegate>(factory);
|
||||
// the line belows returns existing item or adds the new value if it doesn't exist
|
||||
var value = (Lazy<Delegate>)objectCache.AddOrGetExisting(key, newValue, new CacheItemPolicy
|
||||
{
|
||||
//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)
|
||||
});
|
||||
return (value ?? newValue).Value; // Lazy<T> handles the locking itself
|
||||
|
||||
// Cache it, return it
|
||||
var del = m.CreateDelegate(Expression.GetFuncType(typeof(IDataReader), type));
|
||||
PocoFactories.Add(key, del);
|
||||
return del;
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddConverterToStack(ILGenerator il, Func<object, object> converter)
|
||||
@@ -2144,7 +2182,7 @@ namespace Umbraco.Core.Persistence
|
||||
return default(T);
|
||||
}
|
||||
|
||||
|
||||
ManagedCache _managedCache = new ManagedCache();
|
||||
static Dictionary<Type, PocoData> m_PocoDatas = new Dictionary<Type, PocoData>();
|
||||
static List<Func<object, object>> m_Converters = new List<Func<object, object>>();
|
||||
static MethodInfo fnGetValue = typeof(IDataRecord).GetMethod("GetValue", new Type[] { typeof(int) });
|
||||
@@ -2156,7 +2194,46 @@ namespace Umbraco.Core.Persistence
|
||||
public string[] QueryColumns { get; private set; }
|
||||
public TableInfo TableInfo { get; private set; }
|
||||
public Dictionary<string, PocoColumn> Columns { get; private set; }
|
||||
Dictionary<string, Delegate> PocoFactories = new Dictionary<string, Delegate>();
|
||||
static System.Threading.ReaderWriterLockSlim InnerLock = new System.Threading.ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a report of the current cache being utilized by PetaPoco
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string PrintDebugCacheReport(out double totalBytes, out IEnumerable<string> allKeys)
|
||||
{
|
||||
var managedCache = new ManagedCache();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("m_PocoDatas:");
|
||||
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);
|
||||
}
|
||||
|
||||
var cache = managedCache.GetCache();
|
||||
allKeys = cache.Select(x => x.Key).ToArray();
|
||||
|
||||
sb.AppendFormat("\tTotal Poco data count:{0}\n", allKeys.Count());
|
||||
|
||||
var keys = string.Join("", cache.Select(x => x.Key));
|
||||
//Bytes in .Net are stored as utf-16 = unicode little endian
|
||||
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)
|
||||
{
|
||||
sb.AppendFormat("\t\t Key -> {0}\n", item.Key);
|
||||
sb.AppendFormat("\t\t Value -> {0}\n", item.Value);
|
||||
}
|
||||
|
||||
sb.AppendLine("-------------------END REPORT------------------------");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Umbraco.Core.Persistence
|
||||
var expresionist = new PocoToSqlExpressionHelper<T>();
|
||||
string whereExpression = expresionist.Visit(predicate);
|
||||
|
||||
return sql.Where(whereExpression);
|
||||
return sql.Where(whereExpression, expresionist.GetSqlParameters());
|
||||
}
|
||||
|
||||
public static Sql OrderBy<TColumn>(this Sql sql, Expression<Func<TColumn, object>> columnMember)
|
||||
|
||||
@@ -1,28 +1,562 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
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.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
internal abstract class BaseExpressionHelper<T> : BaseExpressionHelper
|
||||
{
|
||||
protected abstract string VisitMemberAccess(MemberExpression m);
|
||||
|
||||
protected internal virtual string Visit(Expression exp)
|
||||
{
|
||||
|
||||
if (exp == null) return string.Empty;
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.Lambda:
|
||||
return VisitLambda(exp as LambdaExpression);
|
||||
case ExpressionType.MemberAccess:
|
||||
return VisitMemberAccess(exp as MemberExpression);
|
||||
case ExpressionType.Constant:
|
||||
return VisitConstant(exp as ConstantExpression);
|
||||
case ExpressionType.Add:
|
||||
case ExpressionType.AddChecked:
|
||||
case ExpressionType.Subtract:
|
||||
case ExpressionType.SubtractChecked:
|
||||
case ExpressionType.Multiply:
|
||||
case ExpressionType.MultiplyChecked:
|
||||
case ExpressionType.Divide:
|
||||
case ExpressionType.Modulo:
|
||||
case ExpressionType.And:
|
||||
case ExpressionType.AndAlso:
|
||||
case ExpressionType.Or:
|
||||
case ExpressionType.OrElse:
|
||||
case ExpressionType.LessThan:
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
case ExpressionType.GreaterThan:
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
case ExpressionType.Equal:
|
||||
case ExpressionType.NotEqual:
|
||||
case ExpressionType.Coalesce:
|
||||
case ExpressionType.ArrayIndex:
|
||||
case ExpressionType.RightShift:
|
||||
case ExpressionType.LeftShift:
|
||||
case ExpressionType.ExclusiveOr:
|
||||
return VisitBinary(exp as BinaryExpression);
|
||||
case ExpressionType.Negate:
|
||||
case ExpressionType.NegateChecked:
|
||||
case ExpressionType.Not:
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
case ExpressionType.ArrayLength:
|
||||
case ExpressionType.Quote:
|
||||
case ExpressionType.TypeAs:
|
||||
return VisitUnary(exp as UnaryExpression);
|
||||
case ExpressionType.Parameter:
|
||||
return VisitParameter(exp as ParameterExpression);
|
||||
case ExpressionType.Call:
|
||||
return VisitMethodCall(exp as MethodCallExpression);
|
||||
case ExpressionType.New:
|
||||
return VisitNew(exp as NewExpression);
|
||||
case ExpressionType.NewArrayInit:
|
||||
case ExpressionType.NewArrayBounds:
|
||||
return VisitNewArray(exp as NewArrayExpression);
|
||||
default:
|
||||
return exp.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitLambda(LambdaExpression lambda)
|
||||
{
|
||||
if (lambda.Body.NodeType == ExpressionType.MemberAccess)
|
||||
{
|
||||
var m = lambda.Body as MemberExpression;
|
||||
|
||||
if (m.Expression != null)
|
||||
{
|
||||
//This deals with members that are boolean (i.e. x => IsTrashed )
|
||||
string r = VisitMemberAccess(m);
|
||||
SqlParameters.Add(true);
|
||||
return string.Format("{0} = @{1}", r, SqlParameters.Count - 1);
|
||||
|
||||
//return string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
|
||||
}
|
||||
return Visit(lambda.Body);
|
||||
}
|
||||
|
||||
protected virtual string VisitBinary(BinaryExpression b)
|
||||
{
|
||||
string left, right;
|
||||
var operand = BindOperant(b.NodeType);
|
||||
if (operand == "AND" || operand == "OR")
|
||||
{
|
||||
MemberExpression m = b.Left as MemberExpression;
|
||||
if (m != null && m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
|
||||
SqlParameters.Add(1);
|
||||
left = string.Format("{0} = @{1}", r, SqlParameters.Count - 1);
|
||||
|
||||
//left = string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
}
|
||||
m = b.Right as MemberExpression;
|
||||
if (m != null && m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
|
||||
SqlParameters.Add(1);
|
||||
right = string.Format("{0} = @{1}", r, SqlParameters.Count - 1);
|
||||
|
||||
//right = string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
|
||||
if (operand == "=" && right == "null") operand = "is";
|
||||
else if (operand == "<>" && right == "null") operand = "is not";
|
||||
else if (operand == "=" || operand == "<>")
|
||||
{
|
||||
//if (IsTrueExpression(right)) right = GetQuotedTrueValue();
|
||||
//else if (IsFalseExpression(right)) right = GetQuotedFalseValue();
|
||||
|
||||
//if (IsTrueExpression(left)) left = GetQuotedTrueValue();
|
||||
//else if (IsFalseExpression(left)) left = GetQuotedFalseValue();
|
||||
|
||||
}
|
||||
|
||||
switch (operand)
|
||||
{
|
||||
case "MOD":
|
||||
case "COALESCE":
|
||||
return string.Format("{0}({1},{2})", operand, left, right);
|
||||
default:
|
||||
return left + " " + operand + " " + right;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual List<Object> VisitExpressionList(ReadOnlyCollection<Expression> original)
|
||||
{
|
||||
var list = new List<Object>();
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
if (original[i].NodeType == ExpressionType.NewArrayInit ||
|
||||
original[i].NodeType == ExpressionType.NewArrayBounds)
|
||||
{
|
||||
|
||||
list.AddRange(VisitNewArrayFromExpressionList(original[i] as NewArrayExpression));
|
||||
}
|
||||
else
|
||||
list.Add(Visit(original[i]));
|
||||
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected virtual string VisitNew(NewExpression nex)
|
||||
{
|
||||
// TODO : check !
|
||||
var member = Expression.Convert(nex, typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
try
|
||||
{
|
||||
var getter = lambda.Compile();
|
||||
object o = getter();
|
||||
|
||||
SqlParameters.Add(o);
|
||||
return string.Format("@{0}", SqlParameters.Count - 1);
|
||||
|
||||
//return GetQuotedValue(o, o.GetType());
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// FieldName ?
|
||||
List<Object> exprs = VisitExpressionList(nex.Arguments);
|
||||
var r = new StringBuilder();
|
||||
foreach (Object e in exprs)
|
||||
{
|
||||
r.AppendFormat("{0}{1}",
|
||||
r.Length > 0 ? "," : "",
|
||||
e);
|
||||
}
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitParameter(ParameterExpression p)
|
||||
{
|
||||
return p.Name;
|
||||
}
|
||||
|
||||
protected virtual string VisitConstant(ConstantExpression c)
|
||||
{
|
||||
if (c.Value == null)
|
||||
return "null";
|
||||
|
||||
SqlParameters.Add(c.Value);
|
||||
return string.Format("@{0}", SqlParameters.Count - 1);
|
||||
|
||||
//if (c.Value is bool)
|
||||
//{
|
||||
// object o = GetQuotedValue(c.Value, c.Value.GetType());
|
||||
// return string.Format("({0}={1})", GetQuotedTrueValue(), o);
|
||||
//}
|
||||
//return GetQuotedValue(c.Value, c.Value.GetType());
|
||||
}
|
||||
|
||||
protected virtual string VisitUnary(UnaryExpression u)
|
||||
{
|
||||
switch (u.NodeType)
|
||||
{
|
||||
case ExpressionType.Not:
|
||||
var o = Visit(u.Operand);
|
||||
|
||||
//use a Not equal operator instead of <> since we don't know that <> works in all sql servers
|
||||
|
||||
switch (u.Operand.NodeType)
|
||||
{
|
||||
case ExpressionType.MemberAccess:
|
||||
//In this case it wil be a false property , i.e. x => !Trashed
|
||||
SqlParameters.Add(true);
|
||||
return string.Format("NOT ({0} = @0)", o);
|
||||
default:
|
||||
//In this case it could be anything else, such as: x => !x.Path.StartsWith("-20")
|
||||
return string.Format("NOT ({0})", o);
|
||||
}
|
||||
default:
|
||||
return Visit(u.Operand);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitNewArray(NewArrayExpression na)
|
||||
{
|
||||
|
||||
List<Object> exprs = VisitExpressionList(na.Expressions);
|
||||
var r = new StringBuilder();
|
||||
foreach (Object e in exprs)
|
||||
{
|
||||
r.Append(r.Length > 0 ? "," + e : e);
|
||||
}
|
||||
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
protected virtual List<Object> VisitNewArrayFromExpressionList(NewArrayExpression na)
|
||||
{
|
||||
|
||||
List<Object> exprs = VisitExpressionList(na.Expressions);
|
||||
return exprs;
|
||||
}
|
||||
|
||||
protected virtual string BindOperant(ExpressionType e)
|
||||
{
|
||||
|
||||
switch (e)
|
||||
{
|
||||
case ExpressionType.Equal:
|
||||
return "=";
|
||||
case ExpressionType.NotEqual:
|
||||
return "<>";
|
||||
case ExpressionType.GreaterThan:
|
||||
return ">";
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
return ">=";
|
||||
case ExpressionType.LessThan:
|
||||
return "<";
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
return "<=";
|
||||
case ExpressionType.AndAlso:
|
||||
return "AND";
|
||||
case ExpressionType.OrElse:
|
||||
return "OR";
|
||||
case ExpressionType.Add:
|
||||
return "+";
|
||||
case ExpressionType.Subtract:
|
||||
return "-";
|
||||
case ExpressionType.Multiply:
|
||||
return "*";
|
||||
case ExpressionType.Divide:
|
||||
return "/";
|
||||
case ExpressionType.Modulo:
|
||||
return "MOD";
|
||||
case ExpressionType.Coalesce:
|
||||
return "COALESCE";
|
||||
default:
|
||||
return e.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
//Here's what happens with a MethodCallExpression:
|
||||
// If a method is called that contains a single argument,
|
||||
// then m.Object is the object on the left hand side of the method call, example:
|
||||
// x.Path.StartsWith(content.Path)
|
||||
// m.Object = x.Path
|
||||
// and m.Arguments.Length == 1, therefor m.Arguments[0] == content.Path
|
||||
// If a method is called that contains multiple arguments, then m.Object == null and the
|
||||
// m.Arguments collection contains the left hand side of the method call, example:
|
||||
// x.Path.SqlStartsWith(content.Path, TextColumnType.NVarchar)
|
||||
// m.Object == null
|
||||
// m.Arguments.Length == 3, therefor, m.Arguments[0] == x.Path, m.Arguments[1] == content.Path, m.Arguments[2] == TextColumnType.NVarchar
|
||||
// So, we need to cater for these scenarios.
|
||||
|
||||
var objectForMethod = m.Object ?? m.Arguments[0];
|
||||
var visitedObjectForMethod = Visit(objectForMethod);
|
||||
var methodArgs = m.Object == null
|
||||
? m.Arguments.Skip(1).ToArray()
|
||||
: m.Arguments.ToArray();
|
||||
|
||||
switch (m.Method.Name)
|
||||
{
|
||||
case "ToString":
|
||||
SqlParameters.Add(objectForMethod.ToString());
|
||||
return string.Format("@{0}", SqlParameters.Count - 1);
|
||||
case "ToUpper":
|
||||
return string.Format("upper({0})", visitedObjectForMethod);
|
||||
case "ToLower":
|
||||
return string.Format("lower({0})", visitedObjectForMethod);
|
||||
case "SqlWildcard":
|
||||
case "StartsWith":
|
||||
case "EndsWith":
|
||||
case "Contains":
|
||||
case "Equals":
|
||||
case "SqlStartsWith":
|
||||
case "SqlEndsWith":
|
||||
case "SqlContains":
|
||||
case "SqlEquals":
|
||||
case "InvariantStartsWith":
|
||||
case "InvariantEndsWith":
|
||||
case "InvariantContains":
|
||||
case "InvariantEquals":
|
||||
|
||||
string compareValue;
|
||||
|
||||
if (methodArgs[0].NodeType != ExpressionType.Constant)
|
||||
{
|
||||
//This occurs when we are getting a value from a non constant such as: x => x.Path.StartsWith(content.Path)
|
||||
// So we'll go get the value:
|
||||
var member = Expression.Convert(methodArgs[0], typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
compareValue = getter().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
compareValue = methodArgs[0].ToString();
|
||||
}
|
||||
|
||||
//special case, if it is 'Contains' and the member that Contains is being called on is not a string, then
|
||||
// we should be doing an 'In' clause - but we currently do not support this
|
||||
if (methodArgs[0].Type != typeof(string) && TypeHelper.IsTypeAssignableFrom<IEnumerable>(methodArgs[0].Type))
|
||||
{
|
||||
throw new NotSupportedException("An array Contains method is not supported");
|
||||
}
|
||||
|
||||
//default column type
|
||||
var colType = TextColumnType.NVarchar;
|
||||
|
||||
//then check if the col type argument has been passed to the current method (this will be the case for methods like
|
||||
// SqlContains and other Sql methods)
|
||||
if (methodArgs.Length > 1)
|
||||
{
|
||||
var colTypeArg = methodArgs.FirstOrDefault(x => x is ConstantExpression && x.Type == typeof(TextColumnType));
|
||||
if (colTypeArg != null)
|
||||
{
|
||||
colType = (TextColumnType)((ConstantExpression)colTypeArg).Value;
|
||||
}
|
||||
}
|
||||
|
||||
return HandleStringComparison(visitedObjectForMethod, compareValue, m.Method.Name, colType);
|
||||
//case "Substring":
|
||||
// var startIndex = Int32.Parse(args[0].ToString()) + 1;
|
||||
// if (args.Count == 2)
|
||||
// {
|
||||
// var length = Int32.Parse(args[1].ToString());
|
||||
// return string.Format("substring({0} from {1} for {2})",
|
||||
// r,
|
||||
// startIndex,
|
||||
// length);
|
||||
// }
|
||||
// else
|
||||
// return string.Format("substring({0} from {1})",
|
||||
// r,
|
||||
// startIndex);
|
||||
//case "Round":
|
||||
//case "Floor":
|
||||
//case "Ceiling":
|
||||
//case "Coalesce":
|
||||
//case "Abs":
|
||||
//case "Sum":
|
||||
// return string.Format("{0}({1}{2})",
|
||||
// m.Method.Name,
|
||||
// r,
|
||||
// args.Count == 1 ? string.Format(",{0}", args[0]) : "");
|
||||
//case "Concat":
|
||||
// var s = new StringBuilder();
|
||||
// foreach (Object e in args)
|
||||
// {
|
||||
// s.AppendFormat(" || {0}", e);
|
||||
// }
|
||||
// return string.Format("{0}{1}", r, s);
|
||||
|
||||
//case "In":
|
||||
|
||||
// var member = Expression.Convert(m.Arguments[0], typeof(object));
|
||||
// var lambda = Expression.Lambda<Func<object>>(member);
|
||||
// var getter = lambda.Compile();
|
||||
|
||||
// var inArgs = (object[])getter();
|
||||
|
||||
// var sIn = new StringBuilder();
|
||||
// foreach (var e in inArgs)
|
||||
// {
|
||||
// SqlParameters.Add(e);
|
||||
|
||||
// sIn.AppendFormat("{0}{1}",
|
||||
// sIn.Length > 0 ? "," : "",
|
||||
// string.Format("@{0}", SqlParameters.Count - 1));
|
||||
|
||||
// //sIn.AppendFormat("{0}{1}",
|
||||
// // sIn.Length > 0 ? "," : "",
|
||||
// // GetQuotedValue(e, e.GetType()));
|
||||
// }
|
||||
|
||||
// return string.Format("{0} {1} ({2})", r, m.Method.Name, sIn.ToString());
|
||||
//case "Desc":
|
||||
// return string.Format("{0} DESC", r);
|
||||
//case "Alias":
|
||||
//case "As":
|
||||
// return string.Format("{0} As {1}", r,
|
||||
// GetQuotedColumnName(RemoveQuoteFromAlias(RemoveQuote(args[0].ToString()))));
|
||||
|
||||
default:
|
||||
|
||||
throw new ArgumentOutOfRangeException("No logic supported for " + m.Method.Name);
|
||||
|
||||
//var s2 = new StringBuilder();
|
||||
//foreach (Object e in args)
|
||||
//{
|
||||
// s2.AppendFormat(",{0}", GetQuotedValue(e, e.GetType()));
|
||||
//}
|
||||
//return string.Format("{0}({1}{2})", m.Method.Name, r, s2.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("\"{0}\"", tableName);
|
||||
}
|
||||
|
||||
public virtual string GetQuotedColumnName(string columnName)
|
||||
{
|
||||
return string.Format("\"{0}\"", columnName);
|
||||
}
|
||||
|
||||
public virtual string GetQuotedName(string name)
|
||||
{
|
||||
return string.Format("\"{0}\"", name);
|
||||
}
|
||||
|
||||
//private string GetQuotedTrueValue()
|
||||
//{
|
||||
// return GetQuotedValue(true, typeof(bool));
|
||||
//}
|
||||
|
||||
//private string GetQuotedFalseValue()
|
||||
//{
|
||||
// return GetQuotedValue(false, typeof(bool));
|
||||
//}
|
||||
|
||||
//public virtual string GetQuotedValue(object value, Type fieldType)
|
||||
//{
|
||||
// return GetQuotedValue(value, fieldType, EscapeParam, ShouldQuoteValue);
|
||||
//}
|
||||
|
||||
//private string GetTrueExpression()
|
||||
//{
|
||||
// object o = GetQuotedTrueValue();
|
||||
// return string.Format("({0}={1})", o, o);
|
||||
//}
|
||||
|
||||
//private string GetFalseExpression()
|
||||
//{
|
||||
|
||||
// return string.Format("({0}={1})",
|
||||
// GetQuotedTrueValue(),
|
||||
// GetQuotedFalseValue());
|
||||
//}
|
||||
|
||||
//private bool IsTrueExpression(string exp)
|
||||
//{
|
||||
// return (exp == GetTrueExpression());
|
||||
//}
|
||||
|
||||
//private bool IsFalseExpression(string exp)
|
||||
//{
|
||||
// return (exp == GetFalseExpression());
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logic that is shared with the expression helpers
|
||||
/// </summary>
|
||||
internal class BaseExpressionHelper
|
||||
internal class BaseExpressionHelper
|
||||
{
|
||||
protected List<object> SqlParameters = new List<object>();
|
||||
|
||||
public object[] GetSqlParameters()
|
||||
{
|
||||
return SqlParameters.ToArray();
|
||||
}
|
||||
|
||||
protected string HandleStringComparison(string col, string val, string verb, TextColumnType columnType)
|
||||
{
|
||||
switch (verb)
|
||||
{
|
||||
case "SqlWildcard":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, RemoveQuote(val), columnType);
|
||||
SqlParameters.Add(RemoveQuote(val));
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, SqlParameters.Count - 1, columnType);
|
||||
case "Equals":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, RemoveQuote(val), columnType);
|
||||
SqlParameters.Add(RemoveQuote(val));
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, SqlParameters.Count - 1, columnType);
|
||||
case "StartsWith":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnStartsWithComparison(col, RemoveQuote(val), columnType);
|
||||
SqlParameters.Add(string.Format("{0}{1}",
|
||||
RemoveQuote(val),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetWildcardPlaceholder()));
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, SqlParameters.Count - 1, columnType);
|
||||
case "EndsWith":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEndsWithComparison(col, RemoveQuote(val), columnType);
|
||||
SqlParameters.Add(string.Format("{0}{1}",
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetWildcardPlaceholder(),
|
||||
RemoveQuote(val)));
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, SqlParameters.Count - 1, columnType);
|
||||
case "Contains":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnContainsComparison(col, RemoveQuote(val), columnType);
|
||||
SqlParameters.Add(string.Format("{0}{1}{0}",
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetWildcardPlaceholder(),
|
||||
RemoveQuote(val)));
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, SqlParameters.Count - 1, columnType);
|
||||
case "InvariantEquals":
|
||||
case "SqlEquals":
|
||||
//recurse
|
||||
@@ -44,61 +578,54 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string GetQuotedValue(object value, Type fieldType, Func<object, string> escapeCallback = null, Func<Type, bool> shouldQuoteCallback = null)
|
||||
{
|
||||
if (value == null) return "NULL";
|
||||
//public virtual string GetQuotedValue(object value, Type fieldType, Func<object, string> escapeCallback = null, Func<Type, bool> shouldQuoteCallback = null)
|
||||
//{
|
||||
// if (value == null) return "NULL";
|
||||
|
||||
if (escapeCallback == null)
|
||||
{
|
||||
escapeCallback = EscapeParam;
|
||||
}
|
||||
if (shouldQuoteCallback == null)
|
||||
{
|
||||
shouldQuoteCallback = ShouldQuoteValue;
|
||||
}
|
||||
// if (escapeCallback == null)
|
||||
// {
|
||||
// escapeCallback = EscapeParam;
|
||||
// }
|
||||
// if (shouldQuoteCallback == null)
|
||||
// {
|
||||
// shouldQuoteCallback = ShouldQuoteValue;
|
||||
// }
|
||||
|
||||
if (!fieldType.UnderlyingSystemType.IsValueType && fieldType != typeof(string))
|
||||
{
|
||||
//if (TypeSerializer.CanCreateFromString(fieldType))
|
||||
//{
|
||||
// return "'" + escapeCallback(TypeSerializer.SerializeToString(value)) + "'";
|
||||
//}
|
||||
// if (!fieldType.UnderlyingSystemType.IsValueType && fieldType != typeof(string))
|
||||
// {
|
||||
// //if (TypeSerializer.CanCreateFromString(fieldType))
|
||||
// //{
|
||||
// // return "'" + escapeCallback(TypeSerializer.SerializeToString(value)) + "'";
|
||||
// //}
|
||||
|
||||
throw new NotSupportedException(
|
||||
string.Format("Property of type: {0} is not supported", fieldType.FullName));
|
||||
}
|
||||
// throw new NotSupportedException(
|
||||
// string.Format("Property of type: {0} is not supported", fieldType.FullName));
|
||||
// }
|
||||
|
||||
if (fieldType == typeof(int))
|
||||
return ((int)value).ToString(CultureInfo.InvariantCulture);
|
||||
// if (fieldType == typeof(int))
|
||||
// return ((int)value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (fieldType == typeof(float))
|
||||
return ((float)value).ToString(CultureInfo.InvariantCulture);
|
||||
// if (fieldType == typeof(float))
|
||||
// return ((float)value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (fieldType == typeof(double))
|
||||
return ((double)value).ToString(CultureInfo.InvariantCulture);
|
||||
// if (fieldType == typeof(double))
|
||||
// return ((double)value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (fieldType == typeof(decimal))
|
||||
return ((decimal)value).ToString(CultureInfo.InvariantCulture);
|
||||
// if (fieldType == typeof(decimal))
|
||||
// return ((decimal)value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (fieldType == typeof(DateTime))
|
||||
{
|
||||
return "'" + escapeCallback(((DateTime)value).ToIsoString()) + "'";
|
||||
}
|
||||
// if (fieldType == typeof(DateTime))
|
||||
// {
|
||||
// return "'" + escapeCallback(((DateTime)value).ToIsoString()) + "'";
|
||||
// }
|
||||
|
||||
if (fieldType == typeof(bool))
|
||||
return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture);
|
||||
// if (fieldType == typeof(bool))
|
||||
// return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture);
|
||||
|
||||
return shouldQuoteCallback(fieldType)
|
||||
? "'" + escapeCallback(value) + "'"
|
||||
: value.ToString();
|
||||
}
|
||||
|
||||
public virtual string EscapeParam(object paramValue)
|
||||
{
|
||||
return paramValue == null
|
||||
? string.Empty
|
||||
: SqlSyntaxContext.SqlSyntaxProvider.EscapeString(paramValue.ToString());
|
||||
}
|
||||
// return shouldQuoteCallback(fieldType)
|
||||
// ? "'" + escapeCallback(value) + "'"
|
||||
// : value.ToString();
|
||||
//}
|
||||
|
||||
public virtual bool ShouldQuoteValue(Type fieldType)
|
||||
{
|
||||
@@ -107,16 +634,12 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
|
||||
protected virtual string RemoveQuote(string exp)
|
||||
{
|
||||
if (exp.StartsWith("'") && exp.EndsWith("'"))
|
||||
{
|
||||
exp = exp.Remove(0, 1);
|
||||
exp = exp.Remove(exp.Length - 1, 1);
|
||||
}
|
||||
return exp;
|
||||
}
|
||||
|
||||
protected virtual string RemoveQuoteFromAlias(string exp)
|
||||
{
|
||||
//if (exp.StartsWith("'") && exp.EndsWith("'"))
|
||||
//{
|
||||
// exp = exp.Remove(0, 1);
|
||||
// exp = exp.Remove(exp.Length - 1, 1);
|
||||
//}
|
||||
//return exp;
|
||||
|
||||
if ((exp.StartsWith("\"") || exp.StartsWith("`") || exp.StartsWith("'"))
|
||||
&&
|
||||
@@ -127,5 +650,18 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
}
|
||||
return exp;
|
||||
}
|
||||
|
||||
//protected virtual string RemoveQuoteFromAlias(string exp)
|
||||
//{
|
||||
|
||||
// if ((exp.StartsWith("\"") || exp.StartsWith("`") || exp.StartsWith("'"))
|
||||
// &&
|
||||
// (exp.EndsWith("\"") || exp.EndsWith("`") || exp.EndsWith("'")))
|
||||
// {
|
||||
// exp = exp.Remove(0, 1);
|
||||
// exp = exp.Remove(exp.Length - 1, 1);
|
||||
// }
|
||||
// return exp;
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
/// <summary>
|
||||
/// SD: This is a horrible hack but unless we break compatibility with anyone who's actually implemented IQuery{T} there's not much we can do.
|
||||
/// The IQuery{T} interface is useless without having a GetWhereClauses method and cannot be used for tests.
|
||||
/// We have to wait till v8 to make this change I suppose.
|
||||
/// </summary>
|
||||
internal static class QueryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns all translated where clauses and their sql parameters
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Tuple<string, object[]>> GetWhereClauses<T>(this IQuery<T> query)
|
||||
{
|
||||
var q = query as Query<T>;
|
||||
if (q == null)
|
||||
{
|
||||
throw new NotSupportedException(typeof(IQuery<T>) + " cannot be cast to " + typeof(Query<T>));
|
||||
}
|
||||
return q.GetWhereClauses();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a query for building Linq translatable SQL queries
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public interface IQuery<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a where clause to the query
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <returns>This instance so calls to this method are chainable</returns>
|
||||
IQuery<T> Where(Expression<Func<T, bool>> predicate);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -10,149 +10,21 @@ using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
internal class ModelToSqlExpressionHelper<T> : BaseExpressionHelper
|
||||
internal class ModelToSqlExpressionHelper<T> : BaseExpressionHelper<T>
|
||||
{
|
||||
private string sep = " ";
|
||||
private BaseMapper _mapper;
|
||||
|
||||
private readonly BaseMapper _mapper;
|
||||
|
||||
public ModelToSqlExpressionHelper()
|
||||
{
|
||||
_mapper = MappingResolver.Current.ResolveMapperByType(typeof(T));
|
||||
}
|
||||
|
||||
protected internal virtual string Visit(Expression exp)
|
||||
|
||||
protected override string VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
|
||||
if (exp == null) return string.Empty;
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.Lambda:
|
||||
return VisitLambda(exp as LambdaExpression);
|
||||
case ExpressionType.MemberAccess:
|
||||
return VisitMemberAccess(exp as MemberExpression);
|
||||
case ExpressionType.Constant:
|
||||
return VisitConstant(exp as ConstantExpression);
|
||||
case ExpressionType.Add:
|
||||
case ExpressionType.AddChecked:
|
||||
case ExpressionType.Subtract:
|
||||
case ExpressionType.SubtractChecked:
|
||||
case ExpressionType.Multiply:
|
||||
case ExpressionType.MultiplyChecked:
|
||||
case ExpressionType.Divide:
|
||||
case ExpressionType.Modulo:
|
||||
case ExpressionType.And:
|
||||
case ExpressionType.AndAlso:
|
||||
case ExpressionType.Or:
|
||||
case ExpressionType.OrElse:
|
||||
case ExpressionType.LessThan:
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
case ExpressionType.GreaterThan:
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
case ExpressionType.Equal:
|
||||
case ExpressionType.NotEqual:
|
||||
case ExpressionType.Coalesce:
|
||||
case ExpressionType.ArrayIndex:
|
||||
case ExpressionType.RightShift:
|
||||
case ExpressionType.LeftShift:
|
||||
case ExpressionType.ExclusiveOr:
|
||||
return VisitBinary(exp as BinaryExpression);
|
||||
case ExpressionType.Negate:
|
||||
case ExpressionType.NegateChecked:
|
||||
case ExpressionType.Not:
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
case ExpressionType.ArrayLength:
|
||||
case ExpressionType.Quote:
|
||||
case ExpressionType.TypeAs:
|
||||
return VisitUnary(exp as UnaryExpression);
|
||||
case ExpressionType.Parameter:
|
||||
return VisitParameter(exp as ParameterExpression);
|
||||
case ExpressionType.Call:
|
||||
return VisitMethodCall(exp as MethodCallExpression);
|
||||
case ExpressionType.New:
|
||||
return VisitNew(exp as NewExpression);
|
||||
case ExpressionType.NewArrayInit:
|
||||
case ExpressionType.NewArrayBounds:
|
||||
return VisitNewArray(exp as NewArrayExpression);
|
||||
default:
|
||||
return exp.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitLambda(LambdaExpression lambda)
|
||||
{
|
||||
if (lambda.Body.NodeType == ExpressionType.MemberAccess && sep == " ")
|
||||
{
|
||||
MemberExpression m = lambda.Body as MemberExpression;
|
||||
|
||||
if (m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
return string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
|
||||
}
|
||||
return Visit(lambda.Body);
|
||||
}
|
||||
|
||||
protected virtual string VisitBinary(BinaryExpression b)
|
||||
{
|
||||
string left, right;
|
||||
var operand = BindOperant(b.NodeType); //sep= " " ??
|
||||
if (operand == "AND" || operand == "OR")
|
||||
{
|
||||
MemberExpression m = b.Left as MemberExpression;
|
||||
if (m != null && m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
left = string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
}
|
||||
m = b.Right as MemberExpression;
|
||||
if (m != null && m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
right = string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
|
||||
if (operand == "=" && right == "null") operand = "is";
|
||||
else if (operand == "<>" && right == "null") operand = "is not";
|
||||
else if (operand == "=" || operand == "<>")
|
||||
{
|
||||
if (IsTrueExpression(right)) right = GetQuotedTrueValue();
|
||||
else if (IsFalseExpression(right)) right = GetQuotedFalseValue();
|
||||
|
||||
if (IsTrueExpression(left)) left = GetQuotedTrueValue();
|
||||
else if (IsFalseExpression(left)) left = GetQuotedFalseValue();
|
||||
|
||||
}
|
||||
|
||||
switch (operand)
|
||||
{
|
||||
case "MOD":
|
||||
case "COALESCE":
|
||||
return string.Format("{0}({1},{2})", operand, left, right);
|
||||
default:
|
||||
return left + sep + operand + sep + right;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter && m.Expression.Type == typeof(T))
|
||||
if (m.Expression != null &&
|
||||
m.Expression.NodeType == ExpressionType.Parameter
|
||||
&& m.Expression.Type == typeof(T))
|
||||
{
|
||||
var field = _mapper.Map(m.Member.Name);
|
||||
return field;
|
||||
@@ -168,324 +40,18 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
object o = getter();
|
||||
return GetQuotedValue(o, o != null ? o.GetType() : null);
|
||||
|
||||
SqlParameters.Add(o);
|
||||
return string.Format("@{0}", SqlParameters.Count - 1);
|
||||
|
||||
//return GetQuotedValue(o, o != null ? o.GetType() : null);
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitNew(NewExpression nex)
|
||||
{
|
||||
// TODO : check !
|
||||
var member = Expression.Convert(nex, typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
try
|
||||
{
|
||||
var getter = lambda.Compile();
|
||||
object o = getter();
|
||||
return GetQuotedValue(o, o.GetType());
|
||||
}
|
||||
catch (System.InvalidOperationException)
|
||||
{ // FieldName ?
|
||||
List<Object> exprs = VisitExpressionList(nex.Arguments);
|
||||
var r = new StringBuilder();
|
||||
foreach (Object e in exprs)
|
||||
{
|
||||
r.AppendFormat("{0}{1}", r.Length > 0 ? "," : "", e);
|
||||
}
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitParameter(ParameterExpression p)
|
||||
{
|
||||
return p.Name;
|
||||
}
|
||||
|
||||
protected virtual string VisitConstant(ConstantExpression c)
|
||||
{
|
||||
if (c.Value == null)
|
||||
return "null";
|
||||
if (c.Value is bool)
|
||||
{
|
||||
object o = GetQuotedValue(c.Value, c.Value.GetType());
|
||||
return string.Format("({0}={1})", GetQuotedTrueValue(), o);
|
||||
}
|
||||
return GetQuotedValue(c.Value, c.Value.GetType());
|
||||
}
|
||||
|
||||
protected virtual string VisitUnary(UnaryExpression u)
|
||||
{
|
||||
switch (u.NodeType)
|
||||
{
|
||||
case ExpressionType.Not:
|
||||
string o = Visit(u.Operand);
|
||||
if (IsFieldName(o)) o = o + "=" + GetQuotedValue(true, typeof(bool));
|
||||
return "NOT (" + o + ")";
|
||||
default:
|
||||
return Visit(u.Operand);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
List<Object> args = this.VisitExpressionList(m.Arguments);
|
||||
|
||||
Object r;
|
||||
if (m.Object != null)
|
||||
r = Visit(m.Object);
|
||||
else
|
||||
{
|
||||
r = args[0];
|
||||
args.RemoveAt(0);
|
||||
}
|
||||
|
||||
switch (m.Method.Name)
|
||||
{
|
||||
case "ToUpper":
|
||||
return string.Format("upper({0})", r);
|
||||
case "ToLower":
|
||||
return string.Format("lower({0})", r);
|
||||
case "SqlWildcard":
|
||||
case "StartsWith":
|
||||
case "EndsWith":
|
||||
case "Contains":
|
||||
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)
|
||||
{
|
||||
var length = Int32.Parse(args[1].ToString());
|
||||
return string.Format("substring({0} from {1} for {2})",
|
||||
r,
|
||||
startIndex,
|
||||
length);
|
||||
}
|
||||
else
|
||||
return string.Format("substring({0} from {1})",
|
||||
r,
|
||||
startIndex);
|
||||
case "Round":
|
||||
case "Floor":
|
||||
case "Ceiling":
|
||||
case "Coalesce":
|
||||
case "Abs":
|
||||
case "Sum":
|
||||
return string.Format("{0}({1}{2})",
|
||||
m.Method.Name,
|
||||
r,
|
||||
args.Count == 1 ? string.Format(",{0}", args[0]) : "");
|
||||
case "Concat":
|
||||
var s = new StringBuilder();
|
||||
foreach (Object e in args)
|
||||
{
|
||||
s.AppendFormat(" || {0}", e);
|
||||
}
|
||||
return string.Format("{0}{1}", r, s.ToString());
|
||||
|
||||
case "In":
|
||||
|
||||
var member = Expression.Convert(m.Arguments[1], typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
|
||||
var inArgs = getter() as object[];
|
||||
|
||||
var sIn = new StringBuilder();
|
||||
foreach (Object e in inArgs)
|
||||
{
|
||||
if (e.GetType().ToString() != "System.Collections.Generic.List`1[System.Object]")
|
||||
{
|
||||
sIn.AppendFormat("{0}{1}",
|
||||
sIn.Length > 0 ? "," : "",
|
||||
GetQuotedValue(e, e.GetType()));
|
||||
}
|
||||
else
|
||||
{
|
||||
var listArgs = e as IList<Object>;
|
||||
foreach (Object el in listArgs)
|
||||
{
|
||||
sIn.AppendFormat("{0}{1}",
|
||||
sIn.Length > 0 ? "," : "",
|
||||
GetQuotedValue(el, el.GetType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Format("{0} {1} ({2})", r, m.Method.Name, sIn.ToString());
|
||||
case "Desc":
|
||||
return string.Format("{0} DESC", r);
|
||||
case "Alias":
|
||||
case "As":
|
||||
return string.Format("{0} As {1}", r,
|
||||
GetQuotedColumnName(RemoveQuoteFromAlias(RemoveQuote(args[0].ToString()))));
|
||||
case "ToString":
|
||||
return r.ToString();
|
||||
default:
|
||||
var s2 = new StringBuilder();
|
||||
foreach (Object e in args)
|
||||
{
|
||||
s2.AppendFormat(",{0}", GetQuotedValue(e, e.GetType()));
|
||||
}
|
||||
return string.Format("{0}({1}{2})", m.Method.Name, r, s2.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual List<Object> VisitExpressionList(ReadOnlyCollection<Expression> original)
|
||||
{
|
||||
var list = new List<Object>();
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
if (original[i].NodeType == ExpressionType.NewArrayInit ||
|
||||
original[i].NodeType == ExpressionType.NewArrayBounds)
|
||||
{
|
||||
|
||||
list.AddRange(VisitNewArrayFromExpressionList(original[i] as NewArrayExpression));
|
||||
}
|
||||
else
|
||||
list.Add(Visit(original[i]));
|
||||
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected virtual string VisitNewArray(NewArrayExpression na)
|
||||
{
|
||||
|
||||
List<Object> exprs = VisitExpressionList(na.Expressions);
|
||||
var r = new StringBuilder();
|
||||
foreach (Object e in exprs)
|
||||
{
|
||||
r.Append(r.Length > 0 ? "," + e : e);
|
||||
}
|
||||
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
protected virtual List<Object> VisitNewArrayFromExpressionList(NewArrayExpression na)
|
||||
{
|
||||
|
||||
List<Object> exprs = VisitExpressionList(na.Expressions);
|
||||
return exprs;
|
||||
}
|
||||
|
||||
|
||||
protected virtual string BindOperant(ExpressionType e)
|
||||
{
|
||||
|
||||
switch (e)
|
||||
{
|
||||
case ExpressionType.Equal:
|
||||
return "=";
|
||||
case ExpressionType.NotEqual:
|
||||
return "<>";
|
||||
case ExpressionType.GreaterThan:
|
||||
return ">";
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
return ">=";
|
||||
case ExpressionType.LessThan:
|
||||
return "<";
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
return "<=";
|
||||
case ExpressionType.AndAlso:
|
||||
return "AND";
|
||||
case ExpressionType.OrElse:
|
||||
return "OR";
|
||||
case ExpressionType.Add:
|
||||
return "+";
|
||||
case ExpressionType.Subtract:
|
||||
return "-";
|
||||
case ExpressionType.Multiply:
|
||||
return "*";
|
||||
case ExpressionType.Divide:
|
||||
return "/";
|
||||
case ExpressionType.Modulo:
|
||||
return "MOD";
|
||||
case ExpressionType.Coalesce:
|
||||
return "COALESCE";
|
||||
default:
|
||||
return e.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("\"{0}\"", tableName);
|
||||
}
|
||||
|
||||
public virtual string GetQuotedColumnName(string columnName)
|
||||
{
|
||||
return string.Format("\"{0}\"", columnName);
|
||||
}
|
||||
|
||||
public virtual string GetQuotedName(string name)
|
||||
{
|
||||
return string.Format("\"{0}\"", name);
|
||||
}
|
||||
|
||||
private string GetQuotedTrueValue()
|
||||
{
|
||||
return GetQuotedValue(true, typeof(bool));
|
||||
}
|
||||
|
||||
private string GetQuotedFalseValue()
|
||||
{
|
||||
return GetQuotedValue(false, typeof(bool));
|
||||
}
|
||||
|
||||
public virtual string GetQuotedValue(object value, Type fieldType)
|
||||
{
|
||||
return GetQuotedValue(value, fieldType, EscapeParam, ShouldQuoteValue);
|
||||
}
|
||||
|
||||
private string GetTrueExpression()
|
||||
{
|
||||
object o = GetQuotedTrueValue();
|
||||
return string.Format("({0}={1})", o, o);
|
||||
}
|
||||
|
||||
private string GetFalseExpression()
|
||||
{
|
||||
|
||||
return string.Format("({0}={1})",
|
||||
GetQuotedTrueValue(),
|
||||
GetQuotedFalseValue());
|
||||
}
|
||||
|
||||
private bool IsTrueExpression(string exp)
|
||||
{
|
||||
return (exp == GetTrueExpression());
|
||||
}
|
||||
|
||||
private bool IsFalseExpression(string exp)
|
||||
{
|
||||
return (exp == GetFalseExpression());
|
||||
}
|
||||
|
||||
protected bool IsFieldName(string quotedExp)
|
||||
{
|
||||
//Not entirely sure this is reliable, but its better then simply returning true
|
||||
return quotedExp.LastIndexOf("'", StringComparison.InvariantCultureIgnoreCase) + 1 != quotedExp.Length;
|
||||
}
|
||||
|
||||
//protected bool IsFieldName(string quotedExp)
|
||||
//{
|
||||
// //Not entirely sure this is reliable, but its better then simply returning true
|
||||
// return quotedExp.LastIndexOf("'", StringComparison.InvariantCultureIgnoreCase) + 1 != quotedExp.Length;
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
@@ -8,159 +9,28 @@ using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
internal class PocoToSqlExpressionHelper<T> : BaseExpressionHelper
|
||||
internal class PocoToSqlExpressionHelper<T> : BaseExpressionHelper<T>
|
||||
{
|
||||
private string sep = " ";
|
||||
private Database.PocoData pd;
|
||||
private readonly Database.PocoData _pd;
|
||||
|
||||
public PocoToSqlExpressionHelper()
|
||||
{
|
||||
pd = new Database.PocoData(typeof(T));
|
||||
_pd = new Database.PocoData(typeof(T));
|
||||
}
|
||||
|
||||
protected internal virtual string Visit(Expression exp)
|
||||
{
|
||||
|
||||
if (exp == null) return string.Empty;
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.Lambda:
|
||||
return VisitLambda(exp as LambdaExpression);
|
||||
case ExpressionType.MemberAccess:
|
||||
return VisitMemberAccess(exp as MemberExpression);
|
||||
case ExpressionType.Constant:
|
||||
return VisitConstant(exp as ConstantExpression);
|
||||
case ExpressionType.Add:
|
||||
case ExpressionType.AddChecked:
|
||||
case ExpressionType.Subtract:
|
||||
case ExpressionType.SubtractChecked:
|
||||
case ExpressionType.Multiply:
|
||||
case ExpressionType.MultiplyChecked:
|
||||
case ExpressionType.Divide:
|
||||
case ExpressionType.Modulo:
|
||||
case ExpressionType.And:
|
||||
case ExpressionType.AndAlso:
|
||||
case ExpressionType.Or:
|
||||
case ExpressionType.OrElse:
|
||||
case ExpressionType.LessThan:
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
case ExpressionType.GreaterThan:
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
case ExpressionType.Equal:
|
||||
case ExpressionType.NotEqual:
|
||||
case ExpressionType.Coalesce:
|
||||
case ExpressionType.ArrayIndex:
|
||||
case ExpressionType.RightShift:
|
||||
case ExpressionType.LeftShift:
|
||||
case ExpressionType.ExclusiveOr:
|
||||
return VisitBinary(exp as BinaryExpression);
|
||||
case ExpressionType.Negate:
|
||||
case ExpressionType.NegateChecked:
|
||||
case ExpressionType.Not:
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
case ExpressionType.ArrayLength:
|
||||
case ExpressionType.Quote:
|
||||
case ExpressionType.TypeAs:
|
||||
return VisitUnary(exp as UnaryExpression);
|
||||
case ExpressionType.Parameter:
|
||||
return VisitParameter(exp as ParameterExpression);
|
||||
case ExpressionType.Call:
|
||||
return VisitMethodCall(exp as MethodCallExpression);
|
||||
case ExpressionType.New:
|
||||
return VisitNew(exp as NewExpression);
|
||||
case ExpressionType.NewArrayInit:
|
||||
case ExpressionType.NewArrayBounds:
|
||||
return VisitNewArray(exp as NewArrayExpression);
|
||||
default:
|
||||
return exp.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitLambda(LambdaExpression lambda)
|
||||
{
|
||||
if (lambda.Body.NodeType == ExpressionType.MemberAccess && sep == " ")
|
||||
{
|
||||
MemberExpression m = lambda.Body as MemberExpression;
|
||||
|
||||
if (m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
return string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
|
||||
}
|
||||
return Visit(lambda.Body);
|
||||
}
|
||||
|
||||
protected virtual string VisitBinary(BinaryExpression b)
|
||||
{
|
||||
string left, right;
|
||||
var operand = BindOperant(b.NodeType); //sep= " " ??
|
||||
if (operand == "AND" || operand == "OR")
|
||||
{
|
||||
MemberExpression m = b.Left as MemberExpression;
|
||||
if (m != null && m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
left = string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
}
|
||||
m = b.Right as MemberExpression;
|
||||
if (m != null && m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
right = string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
|
||||
if (operand == "=" && right == "null") operand = "is";
|
||||
else if (operand == "<>" && right == "null") operand = "is not";
|
||||
else if (operand == "=" || operand == "<>")
|
||||
{
|
||||
if (IsTrueExpression(right)) right = GetQuotedTrueValue();
|
||||
else if (IsFalseExpression(right)) right = GetQuotedFalseValue();
|
||||
|
||||
if (IsTrueExpression(left)) left = GetQuotedTrueValue();
|
||||
else if (IsFalseExpression(left)) left = GetQuotedFalseValue();
|
||||
|
||||
}
|
||||
|
||||
switch (operand)
|
||||
{
|
||||
case "MOD":
|
||||
case "COALESCE":
|
||||
return string.Format("{0}({1},{2})", operand, left, right);
|
||||
default:
|
||||
return left + sep + operand + sep + right;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitMemberAccess(MemberExpression m)
|
||||
|
||||
protected override string VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
if (m.Expression != null &&
|
||||
m.Expression.NodeType == ExpressionType.Parameter
|
||||
&& m.Expression.Type == typeof(T))
|
||||
{
|
||||
string field = GetFieldName(pd, m.Member.Name);
|
||||
string field = GetFieldName(_pd, m.Member.Name);
|
||||
return field;
|
||||
}
|
||||
|
||||
if (m.Expression != null && m.Expression.NodeType == ExpressionType.Convert)
|
||||
{
|
||||
string field = GetFieldName(pd, m.Member.Name);
|
||||
string field = GetFieldName(_pd, m.Member.Name);
|
||||
return field;
|
||||
}
|
||||
|
||||
@@ -168,303 +38,14 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
object o = getter();
|
||||
return GetQuotedValue(o, o != null ? o.GetType() : null);
|
||||
|
||||
SqlParameters.Add(o);
|
||||
return string.Format("@{0}", SqlParameters.Count - 1);
|
||||
|
||||
//return GetQuotedValue(o, o != null ? o.GetType() : null);
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitNew(NewExpression nex)
|
||||
{
|
||||
// TODO : check !
|
||||
var member = Expression.Convert(nex, typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
try
|
||||
{
|
||||
var getter = lambda.Compile();
|
||||
object o = getter();
|
||||
return GetQuotedValue(o, o.GetType());
|
||||
}
|
||||
catch (System.InvalidOperationException)
|
||||
{ // FieldName ?
|
||||
List<Object> exprs = VisitExpressionList(nex.Arguments);
|
||||
var r = new StringBuilder();
|
||||
foreach (Object e in exprs)
|
||||
{
|
||||
r.AppendFormat("{0}{1}",
|
||||
r.Length > 0 ? "," : "",
|
||||
e);
|
||||
}
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitParameter(ParameterExpression p)
|
||||
{
|
||||
return p.Name;
|
||||
}
|
||||
|
||||
protected virtual string VisitConstant(ConstantExpression c)
|
||||
{
|
||||
if (c.Value == null)
|
||||
return "null";
|
||||
else if (c.Value.GetType() == typeof(bool))
|
||||
{
|
||||
object o = GetQuotedValue(c.Value, c.Value.GetType());
|
||||
return string.Format("({0}={1})", GetQuotedTrueValue(), o);
|
||||
}
|
||||
else
|
||||
return GetQuotedValue(c.Value, c.Value.GetType());
|
||||
}
|
||||
|
||||
protected virtual string VisitUnary(UnaryExpression u)
|
||||
{
|
||||
switch (u.NodeType)
|
||||
{
|
||||
case ExpressionType.Not:
|
||||
string o = Visit(u.Operand);
|
||||
if (IsFieldName(o)) o = o + "=" + GetQuotedValue(true, typeof(bool));
|
||||
return "NOT (" + o + ")";
|
||||
default:
|
||||
return Visit(u.Operand);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
List<Object> args = this.VisitExpressionList(m.Arguments);
|
||||
|
||||
Object r;
|
||||
if (m.Object != null)
|
||||
r = Visit(m.Object);
|
||||
else
|
||||
{
|
||||
r = args[0];
|
||||
args.RemoveAt(0);
|
||||
}
|
||||
|
||||
//TODO: We should probably add the same logic we've done for ModelToSqlExpressionHelper with checking for:
|
||||
// InvariantStartsWith, InvariantEndsWith, SqlWildcard, etc...
|
||||
// since we should be able to easily handle that with the Poco objects too.
|
||||
|
||||
switch (m.Method.Name)
|
||||
{
|
||||
case "ToUpper":
|
||||
return string.Format("upper({0})", r);
|
||||
case "ToLower":
|
||||
return string.Format("lower({0})", r);
|
||||
case "SqlWildcard":
|
||||
case "StartsWith":
|
||||
case "EndsWith":
|
||||
case "Contains":
|
||||
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)
|
||||
{
|
||||
var length = Int32.Parse(args[1].ToString());
|
||||
return string.Format("substring({0} from {1} for {2})",
|
||||
r,
|
||||
startIndex,
|
||||
length);
|
||||
}
|
||||
else
|
||||
return string.Format("substring({0} from {1})",
|
||||
r,
|
||||
startIndex);
|
||||
case "Round":
|
||||
case "Floor":
|
||||
case "Ceiling":
|
||||
case "Coalesce":
|
||||
case "Abs":
|
||||
case "Sum":
|
||||
return string.Format("{0}({1}{2})",
|
||||
m.Method.Name,
|
||||
r,
|
||||
args.Count == 1 ? string.Format(",{0}", args[0]) : "");
|
||||
case "Concat":
|
||||
var s = new StringBuilder();
|
||||
foreach (Object e in args)
|
||||
{
|
||||
s.AppendFormat(" || {0}", e);
|
||||
}
|
||||
return string.Format("{0}{1}", r, s.ToString());
|
||||
|
||||
case "In":
|
||||
|
||||
var member = Expression.Convert(m.Arguments[1], typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
|
||||
var inArgs = getter() as object[];
|
||||
|
||||
var sIn = new StringBuilder();
|
||||
foreach (Object e in inArgs)
|
||||
{
|
||||
if (e.GetType().ToString() != "System.Collections.Generic.List`1[System.Object]")
|
||||
{
|
||||
sIn.AppendFormat("{0}{1}",
|
||||
sIn.Length > 0 ? "," : "",
|
||||
GetQuotedValue(e, e.GetType()));
|
||||
}
|
||||
else
|
||||
{
|
||||
var listArgs = e as IList<Object>;
|
||||
foreach (Object el in listArgs)
|
||||
{
|
||||
sIn.AppendFormat("{0}{1}",
|
||||
sIn.Length > 0 ? "," : "",
|
||||
GetQuotedValue(el, el.GetType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Format("{0} {1} ({2})", r, m.Method.Name, sIn.ToString());
|
||||
case "Desc":
|
||||
return string.Format("{0} DESC", r);
|
||||
case "Alias":
|
||||
case "As":
|
||||
return string.Format("{0} As {1}", r,
|
||||
GetQuotedColumnName(RemoveQuoteFromAlias(RemoveQuote(args[0].ToString()))));
|
||||
case "ToString":
|
||||
return r.ToString();
|
||||
default:
|
||||
var s2 = new StringBuilder();
|
||||
foreach (Object e in args)
|
||||
{
|
||||
s2.AppendFormat(",{0}", GetQuotedValue(e, e.GetType()));
|
||||
}
|
||||
return string.Format("{0}({1}{2})", m.Method.Name, r, s2.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual List<Object> VisitExpressionList(ReadOnlyCollection<Expression> original)
|
||||
{
|
||||
var list = new List<Object>();
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
if (original[i].NodeType == ExpressionType.NewArrayInit ||
|
||||
original[i].NodeType == ExpressionType.NewArrayBounds)
|
||||
{
|
||||
|
||||
list.AddRange(VisitNewArrayFromExpressionList(original[i] as NewArrayExpression));
|
||||
}
|
||||
else
|
||||
list.Add(Visit(original[i]));
|
||||
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected virtual string VisitNewArray(NewArrayExpression na)
|
||||
{
|
||||
|
||||
List<Object> exprs = VisitExpressionList(na.Expressions);
|
||||
var r = new StringBuilder();
|
||||
foreach (Object e in exprs)
|
||||
{
|
||||
r.Append(r.Length > 0 ? "," + e : e);
|
||||
}
|
||||
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
protected virtual List<Object> VisitNewArrayFromExpressionList(NewArrayExpression na)
|
||||
{
|
||||
|
||||
List<Object> exprs = VisitExpressionList(na.Expressions);
|
||||
return exprs;
|
||||
}
|
||||
|
||||
|
||||
protected virtual string BindOperant(ExpressionType e)
|
||||
{
|
||||
|
||||
switch (e)
|
||||
{
|
||||
case ExpressionType.Equal:
|
||||
return "=";
|
||||
case ExpressionType.NotEqual:
|
||||
return "<>";
|
||||
case ExpressionType.GreaterThan:
|
||||
return ">";
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
return ">=";
|
||||
case ExpressionType.LessThan:
|
||||
return "<";
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
return "<=";
|
||||
case ExpressionType.AndAlso:
|
||||
return "AND";
|
||||
case ExpressionType.OrElse:
|
||||
return "OR";
|
||||
case ExpressionType.Add:
|
||||
return "+";
|
||||
case ExpressionType.Subtract:
|
||||
return "-";
|
||||
case ExpressionType.Multiply:
|
||||
return "*";
|
||||
case ExpressionType.Divide:
|
||||
return "/";
|
||||
case ExpressionType.Modulo:
|
||||
return "MOD";
|
||||
case ExpressionType.Coalesce:
|
||||
return "COALESCE";
|
||||
default:
|
||||
return e.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("\"{0}\"", tableName);
|
||||
}
|
||||
|
||||
public virtual string GetQuotedColumnName(string columnName)
|
||||
{
|
||||
return string.Format("\"{0}\"", columnName);
|
||||
}
|
||||
|
||||
public virtual string GetQuotedName(string name)
|
||||
{
|
||||
return string.Format("\"{0}\"", name);
|
||||
}
|
||||
|
||||
private string GetQuotedTrueValue()
|
||||
{
|
||||
return GetQuotedValue(true, typeof(bool));
|
||||
}
|
||||
|
||||
private string GetQuotedFalseValue()
|
||||
{
|
||||
return GetQuotedValue(false, typeof(bool));
|
||||
}
|
||||
|
||||
public virtual string GetQuotedValue(object value, Type fieldType)
|
||||
{
|
||||
return GetQuotedValue(value, fieldType, EscapeParam, ShouldQuoteValue);
|
||||
}
|
||||
|
||||
|
||||
protected virtual string GetFieldName(Database.PocoData pocoData, string name)
|
||||
{
|
||||
var column = pocoData.Columns.FirstOrDefault(x => x.Value.PropertyInfo.Name == name);
|
||||
@@ -472,34 +53,10 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(pocoData.TableInfo.TableName),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(column.Value.ColumnName));
|
||||
}
|
||||
|
||||
private string GetTrueExpression()
|
||||
{
|
||||
object o = GetQuotedTrueValue();
|
||||
return string.Format("({0}={1})", o, o);
|
||||
}
|
||||
|
||||
private string GetFalseExpression()
|
||||
{
|
||||
|
||||
return string.Format("({0}={1})",
|
||||
GetQuotedTrueValue(),
|
||||
GetQuotedFalseValue());
|
||||
}
|
||||
|
||||
private bool IsTrueExpression(string exp)
|
||||
{
|
||||
return (exp == GetTrueExpression());
|
||||
}
|
||||
|
||||
private bool IsFalseExpression(string exp)
|
||||
{
|
||||
return (exp == GetFalseExpression());
|
||||
}
|
||||
|
||||
protected bool IsFieldName(string quotedExp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//protected bool IsFieldName(string quotedExp)
|
||||
//{
|
||||
// return true;
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
@@ -10,37 +11,46 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class Query<T> : IQuery<T>
|
||||
{
|
||||
//private readonly ExpressionHelper<T> _expresionist = new ExpressionHelper<T>();
|
||||
private readonly ModelToSqlExpressionHelper<T> _expresionist = new ModelToSqlExpressionHelper<T>();
|
||||
private readonly List<string> _wheres = new List<string>();
|
||||
|
||||
public Query()
|
||||
: base()
|
||||
{
|
||||
|
||||
}
|
||||
private readonly List<Tuple<string, object[]>> _wheres = new List<Tuple<string, object[]>>();
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to be used instead of manually creating an instance
|
||||
/// </summary>
|
||||
public static IQuery<T> Builder
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Query<T>();
|
||||
}
|
||||
get { return new Query<T>(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a where clause to the query
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <returns>This instance so calls to this method are chainable</returns>
|
||||
public virtual IQuery<T> Where(Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
if (predicate != null)
|
||||
{
|
||||
string whereExpression = _expresionist.Visit(predicate);
|
||||
_wheres.Add(whereExpression);
|
||||
var expressionHelper = new ModelToSqlExpressionHelper<T>();
|
||||
string whereExpression = expressionHelper.Visit(predicate);
|
||||
|
||||
_wheres.Add(new Tuple<string, object[]>(whereExpression, expressionHelper.GetSqlParameters()));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<string> WhereClauses()
|
||||
|
||||
/// <summary>
|
||||
/// Returns all translated where clauses and their sql parameters
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<Tuple<string, object[]>> GetWhereClauses()
|
||||
{
|
||||
return _wheres;
|
||||
}
|
||||
|
||||
[Obsolete("This is no longer used, use the GetWhereClauses method which includes the SQL parameters")]
|
||||
public List<string> WhereClauses()
|
||||
{
|
||||
return _wheres.Select(x => x.Item1).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,10 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
if (sql == null)
|
||||
throw new Exception("Sql cannot be null");
|
||||
|
||||
var query1 = query as Query<T>;
|
||||
if (query1 == null)
|
||||
throw new Exception("Query cannot be null");
|
||||
|
||||
_sql = sql;
|
||||
foreach (var clause in query1.WhereClauses())
|
||||
foreach (var clause in query.GetWhereClauses())
|
||||
{
|
||||
_sql.Where(clause);
|
||||
_sql.Where(clause.Item1, clause.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,15 +66,31 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
|
||||
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
|
||||
var sql = GetBaseWhere(GetBase, isContent, isMedia, objectTypeId, key).Append(GetGroupBy(isContent, isMedia));
|
||||
var nodeDto = _work.Database.FirstOrDefault<dynamic>(sql);
|
||||
if (nodeDto == null)
|
||||
return null;
|
||||
|
||||
var factory = new UmbracoEntityFactory();
|
||||
var entity = factory.BuildEntityFromDynamic(nodeDto);
|
||||
var sql = GetFullSqlForEntityType(key, isContent, isMedia, objectTypeId);
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
|
||||
return entity;
|
||||
return entities.FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
var nodeDto = _work.Database.FirstOrDefault<dynamic>(sql);
|
||||
if (nodeDto == null)
|
||||
return null;
|
||||
|
||||
var factory = new UmbracoEntityFactory();
|
||||
var entity = factory.BuildEntityFromDynamic(nodeDto);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public virtual IUmbracoEntity Get(int id)
|
||||
@@ -94,61 +110,90 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
|
||||
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
|
||||
var sql = GetBaseWhere(GetBase, isContent, isMedia, objectTypeId, id).Append(GetGroupBy(isContent, isMedia));
|
||||
|
||||
var nodeDto = _work.Database.FirstOrDefault<dynamic>(sql);
|
||||
if (nodeDto == null)
|
||||
return null;
|
||||
var sql = GetFullSqlForEntityType(id, isContent, isMedia, objectTypeId);
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
|
||||
var factory = new UmbracoEntityFactory();
|
||||
var entity = factory.BuildEntityFromDynamic(nodeDto);
|
||||
return entities.FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
var nodeDto = _work.Database.FirstOrDefault<dynamic>(sql);
|
||||
if (nodeDto == null)
|
||||
return null;
|
||||
|
||||
return entity;
|
||||
var factory = new UmbracoEntityFactory();
|
||||
var entity = factory.BuildEntityFromDynamic(nodeDto);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public virtual IEnumerable<IUmbracoEntity> GetAll(Guid objectTypeId, params int[] ids)
|
||||
{
|
||||
if (ids.Any())
|
||||
{
|
||||
foreach (var id in ids)
|
||||
return PerformGetAll(objectTypeId, sql1 => sql1.Where(" umbracoNode.id in (@ids)", new {ids = ids}));
|
||||
}
|
||||
else
|
||||
{
|
||||
return PerformGetAll(objectTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<IUmbracoEntity> GetAll(Guid objectTypeId, params Guid[] keys)
|
||||
{
|
||||
if (keys.Any())
|
||||
{
|
||||
return PerformGetAll(objectTypeId, sql1 => sql1.Where(" umbracoNode.uniqueID in (@keys)", new { keys = keys }));
|
||||
}
|
||||
else
|
||||
{
|
||||
return PerformGetAll(objectTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IUmbracoEntity> PerformGetAll(Guid objectTypeId, Action<Sql> filter = null)
|
||||
{
|
||||
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
|
||||
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
|
||||
var sql = GetFullSqlForEntityType(isContent, isMedia, objectTypeId, filter);
|
||||
|
||||
var factory = new UmbracoEntityFactory();
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
yield return Get(id, objectTypeId);
|
||||
yield return entity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
|
||||
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
|
||||
var sql = GetBaseWhere(GetBase, isContent, isMedia, string.Empty, objectTypeId).Append(GetGroupBy(isContent, isMedia));
|
||||
|
||||
var factory = new UmbracoEntityFactory();
|
||||
|
||||
if (isMedia)
|
||||
var dtos = _work.Database.Fetch<dynamic>(sql);
|
||||
foreach (var entity in dtos.Select(dto => factory.BuildEntityFromDynamic(dto)))
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
yield return entity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var dtos = _work.Database.Fetch<dynamic>(sql);
|
||||
foreach (var entity in dtos.Select(dto => factory.BuildEntityFromDynamic(dto)))
|
||||
{
|
||||
yield return entity;
|
||||
}
|
||||
yield return entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query)
|
||||
{
|
||||
var wheres = string.Concat(" AND ", string.Join(" AND ", ((Query<IUmbracoEntity>) query).WhereClauses()));
|
||||
var sqlClause = GetBase(false, false, wheres);
|
||||
var sqlClause = GetBase(false, false, null);
|
||||
var translator = new SqlTranslator<IUmbracoEntity>(sqlClause, query);
|
||||
var sql = translator.Translate().Append(GetGroupBy(false, false));
|
||||
|
||||
@@ -162,28 +207,41 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
public virtual IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId)
|
||||
{
|
||||
|
||||
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
|
||||
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
|
||||
|
||||
var wheres = string.Concat(" AND ", string.Join(" AND ", ((Query<IUmbracoEntity>)query).WhereClauses()));
|
||||
var sqlClause = GetBaseWhere(GetBase, isContent, isMedia, wheres, objectTypeId);
|
||||
var sqlClause = GetBaseWhere(GetBase, isContent, isMedia, null, objectTypeId);
|
||||
|
||||
var translator = new SqlTranslator<IUmbracoEntity>(sqlClause, query);
|
||||
var sql = translator.Translate().Append(GetGroupBy(isContent, isMedia));
|
||||
var entitySql = translator.Translate();
|
||||
|
||||
var factory = new UmbracoEntityFactory();
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
var wheres = query.GetWhereClauses().ToArray();
|
||||
|
||||
var mediaSql = GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)), sql =>
|
||||
{
|
||||
//adds the additional filters
|
||||
foreach (var whereClause in wheres)
|
||||
{
|
||||
sql.Where(whereClause.Item1, whereClause.Item2);
|
||||
}
|
||||
});
|
||||
|
||||
//treat media differently for now
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
new UmbracoEntityRelator().Map, mediaSql);
|
||||
return entities;
|
||||
}
|
||||
else
|
||||
{
|
||||
//use dynamic so that we can get ALL properties from the SQL so we can chuck that data into our AdditionalData
|
||||
var dtos = _work.Database.Fetch<dynamic>(sql);
|
||||
var finalSql = entitySql.Append(GetGroupBy(isContent, false));
|
||||
var dtos = _work.Database.Fetch<dynamic>(finalSql);
|
||||
return dtos.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
|
||||
}
|
||||
}
|
||||
@@ -193,7 +251,68 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#region Sql Statements
|
||||
|
||||
protected virtual Sql GetBase(bool isContent, bool isMedia, string additionWhereStatement = "")
|
||||
protected Sql GetFullSqlForEntityType(Guid key, bool isContent, bool isMedia, Guid objectTypeId)
|
||||
{
|
||||
var entitySql = GetBaseWhere(GetBase, isContent, isMedia, objectTypeId, key);
|
||||
|
||||
if (isMedia == false) return entitySql.Append(GetGroupBy(isContent, false));
|
||||
|
||||
return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)));
|
||||
}
|
||||
|
||||
protected Sql GetFullSqlForEntityType(int id, bool isContent, bool isMedia, Guid objectTypeId)
|
||||
{
|
||||
var entitySql = GetBaseWhere(GetBase, isContent, isMedia, objectTypeId, id);
|
||||
|
||||
if (isMedia == false) return entitySql.Append(GetGroupBy(isContent, false));
|
||||
|
||||
return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)));
|
||||
}
|
||||
|
||||
protected Sql GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectTypeId, Action<Sql> filter)
|
||||
{
|
||||
var entitySql = GetBaseWhere(GetBase, isContent, isMedia, filter, objectTypeId);
|
||||
|
||||
if (isMedia == false) return entitySql.Append(GetGroupBy(isContent, false));
|
||||
|
||||
return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)), filter);
|
||||
}
|
||||
|
||||
private Sql GetFullSqlForMedia(Sql entitySql, Action<Sql> filter = null)
|
||||
{
|
||||
//this will add any dataNvarchar property to the output which can be added to the additional properties
|
||||
|
||||
var joinSql = new Sql()
|
||||
.Select("contentNodeId, versionId, dataNvarchar, dataNtext, controlId, alias as propertyTypeAlias")
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<PropertyDataDto, NodeDto>(dto => dto.NodeId, dto => dto.NodeId)
|
||||
.InnerJoin<PropertyTypeDto>()
|
||||
.On<PropertyTypeDto, PropertyDataDto>(dto => dto.Id, dto => dto.PropertyTypeId)
|
||||
.InnerJoin<DataTypeDto>()
|
||||
.On<PropertyTypeDto, DataTypeDto>(dto => dto.DataTypeId, dto => dto.DataTypeId)
|
||||
.Where("umbracoNode.nodeObjectType = @nodeObjectType", new {nodeObjectType = Constants.ObjectTypes.Media});
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
filter(joinSql);
|
||||
}
|
||||
|
||||
//We're going to create a query to query against the entity SQL
|
||||
// because we cannot group by nText columns and we have a COUNT in the entitySql we cannot simply left join
|
||||
// the entitySql query, we have to join the wrapped query to get the ntext in the result
|
||||
|
||||
var wrappedSql = new Sql("SELECT * FROM (")
|
||||
.Append(entitySql)
|
||||
.Append(new Sql(") tmpTbl LEFT JOIN ("))
|
||||
.Append(joinSql)
|
||||
.Append(new Sql(") as property ON id = property.contentNodeId"))
|
||||
.OrderBy("sortOrder");
|
||||
|
||||
return wrappedSql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter)
|
||||
{
|
||||
var columns = new List<object>
|
||||
{
|
||||
@@ -221,21 +340,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
columns.Add("contenttype.isContainer");
|
||||
}
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
columns.Add("property.dataNvarchar as umbracoFile");
|
||||
columns.Add("property.controlId");
|
||||
}
|
||||
//Creates an SQL query to return a single row for the entity
|
||||
|
||||
var sql = new Sql()
|
||||
var entitySql = new Sql()
|
||||
.Select(columns.ToArray())
|
||||
.From("umbracoNode umbracoNode")
|
||||
.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
|
||||
|
||||
|
||||
.From("umbracoNode umbracoNode");
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
sql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id")
|
||||
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id")
|
||||
.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType")
|
||||
.LeftJoin(
|
||||
"(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published")
|
||||
@@ -245,60 +358,56 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.On("umbracoNode.id = latest.nodeId");
|
||||
}
|
||||
|
||||
if (isMedia)
|
||||
entitySql.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
|
||||
|
||||
if (customFilter != null)
|
||||
{
|
||||
sql.LeftJoin(
|
||||
"(SELECT contentNodeId, versionId, dataNvarchar, controlId FROM cmsPropertyData " +
|
||||
"INNER JOIN umbracoNode ON cmsPropertyData.contentNodeId = umbracoNode.id " +
|
||||
"INNER JOIN cmsPropertyType ON cmsPropertyType.id = cmsPropertyData.propertytypeid " +
|
||||
"INNER JOIN cmsDataType ON cmsPropertyType.dataTypeId = cmsDataType.nodeId "+
|
||||
"WHERE umbracoNode.nodeObjectType = '" + Constants.ObjectTypes.Media + "'" + additionWhereStatement + ") as property")
|
||||
.On("umbracoNode.id = property.contentNodeId");
|
||||
customFilter(entitySql);
|
||||
}
|
||||
|
||||
return sql;
|
||||
return entitySql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, string, Sql> baseQuery, bool isContent, bool isMedia, string additionWhereStatement, Guid nodeObjectType)
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, Action<Sql> filter, Guid nodeObjectType)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, additionWhereStatement)
|
||||
var sql = baseQuery(isContent, isMedia, filter)
|
||||
.Where("umbracoNode.nodeObjectType = @NodeObjectType", new { NodeObjectType = nodeObjectType });
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, string, Sql> baseQuery, bool isContent, bool isMedia, int id)
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, int id)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, " AND umbracoNode.id = '" + id + "'")
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.id = @Id", new { Id = id })
|
||||
.Append(GetGroupBy(isContent, isMedia));
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, string, Sql> baseQuery, bool isContent, bool isMedia, Guid key)
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, Guid key)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, " AND umbracoNode.uniqueID = '" + key + "'")
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key })
|
||||
.Append(GetGroupBy(isContent, isMedia));
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, string, Sql> baseQuery, bool isContent, bool isMedia, Guid nodeObjectType, int id)
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, Guid nodeObjectType, int id)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, " AND umbracoNode.id = '" + id + "'")
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.id = @Id AND umbracoNode.nodeObjectType = @NodeObjectType",
|
||||
new { Id = id, NodeObjectType = nodeObjectType });
|
||||
new {Id = id, NodeObjectType = nodeObjectType});
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, string, Sql> baseQuery, bool isContent, bool isMedia, Guid nodeObjectType, Guid key)
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, Guid nodeObjectType, Guid key)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, " AND umbracoNode.uniqueID = '" + key + "'")
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.uniqueID = @UniqueID AND umbracoNode.nodeObjectType = @NodeObjectType",
|
||||
new { UniqueID = key, NodeObjectType = nodeObjectType });
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetGroupBy(bool isContent, bool isMedia)
|
||||
protected virtual Sql GetGroupBy(bool isContent, bool isMedia, bool includeSort = true)
|
||||
{
|
||||
var columns = new List<object>
|
||||
{
|
||||
@@ -324,19 +433,18 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
columns.Add("contenttype.thumbnail");
|
||||
columns.Add("contenttype.isContainer");
|
||||
}
|
||||
|
||||
var sql = new Sql()
|
||||
.GroupBy(columns.ToArray());
|
||||
|
||||
if (isMedia)
|
||||
if (includeSort)
|
||||
{
|
||||
columns.Add("property.dataNvarchar");
|
||||
columns.Add("property.controlId");
|
||||
sql = sql.OrderBy("umbracoNode.sortOrder");
|
||||
}
|
||||
|
||||
var sql = new Sql()
|
||||
.GroupBy(columns.ToArray())
|
||||
.OrderBy("umbracoNode.sortOrder");
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -384,10 +492,16 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
[Column("controlId")]
|
||||
public Guid DataTypeControlId { get; set; }
|
||||
|
||||
[Column("umbracoFile")]
|
||||
public string UmbracoFile { get; set; }
|
||||
}
|
||||
[Column("propertyTypeAlias")]
|
||||
public string PropertyAlias { get; set; }
|
||||
|
||||
[Column("dataNvarchar")]
|
||||
public string NVarcharValue { get; set; }
|
||||
|
||||
[Column("dataNtext")]
|
||||
public string NTextValue { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a special relator in that it is not returning a DTO but a real resolved entity and that it accepts
|
||||
/// a dynamic instance.
|
||||
@@ -418,10 +532,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Current.UmbracoProperties = new List<UmbracoEntity.UmbracoProperty>();
|
||||
}
|
||||
Current.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty
|
||||
{
|
||||
DataTypeControlId = p.DataTypeControlId,
|
||||
Value = p.UmbracoFile
|
||||
});
|
||||
{
|
||||
DataTypeControlId = p.DataTypeControlId,
|
||||
Value = p.NTextValue.IsNullOrWhiteSpace()
|
||||
? p.NVarcharValue
|
||||
: p.NTextValue
|
||||
});
|
||||
// Return null to indicate we're not done with this UmbracoEntity yet
|
||||
return null;
|
||||
}
|
||||
@@ -433,7 +549,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var prev = Current;
|
||||
|
||||
// Setup the new current UmbracoEntity
|
||||
|
||||
|
||||
Current = _factory.BuildEntityFromDynamic(a);
|
||||
|
||||
//add the property/create the prop list if null
|
||||
@@ -442,7 +558,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
new UmbracoEntity.UmbracoProperty
|
||||
{
|
||||
DataTypeControlId = p.DataTypeControlId,
|
||||
Value = p.UmbracoFile
|
||||
Value = p.NTextValue.IsNullOrWhiteSpace()
|
||||
? p.NVarcharValue
|
||||
: p.NTextValue
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -202,13 +202,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//find the member by username
|
||||
var memberSql = new Sql();
|
||||
var memberObjectType = new Guid(Constants.ObjectTypes.Member);
|
||||
var escapedUsername = PetaPocoExtensions.EscapeAtSymbols(username);
|
||||
|
||||
memberSql.Select("umbracoNode.id")
|
||||
.From<NodeDto>()
|
||||
.InnerJoin<MemberDto>()
|
||||
.On<NodeDto, MemberDto>(dto => dto.NodeId, dto => dto.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == memberObjectType)
|
||||
.Where<MemberDto>(x => x.LoginName == escapedUsername);
|
||||
.Where<MemberDto>(x => x.LoginName == username);
|
||||
var memberIdUsername = Database.Fetch<int?>(memberSql).FirstOrDefault();
|
||||
if (memberIdUsername.HasValue == false)
|
||||
{
|
||||
@@ -279,6 +279,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
public void AssignRolesInternal(int[] memberIds, string[] roleNames)
|
||||
{
|
||||
//ensure they're unique
|
||||
memberIds = memberIds.Distinct().ToArray();
|
||||
|
||||
//create the missing roles first
|
||||
|
||||
var existingSql = new Sql()
|
||||
|
||||
@@ -520,10 +520,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public bool Exists(string username)
|
||||
{
|
||||
var sql = new Sql();
|
||||
var escapedUserName = PetaPocoExtensions.EscapeAtSymbols(username);
|
||||
|
||||
sql.Select("COUNT(*)")
|
||||
.From<MemberDto>()
|
||||
.Where<MemberDto>(x => x.LoginName == escapedUserName);
|
||||
.Where<MemberDto>(x => x.LoginName == username);
|
||||
|
||||
return Database.ExecuteScalar<int>(sql) > 0;
|
||||
}
|
||||
|
||||
@@ -262,10 +262,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public bool Exists(string username)
|
||||
{
|
||||
var sql = new Sql();
|
||||
var escapedUserName = PetaPocoExtensions.EscapeAtSymbols(username);
|
||||
|
||||
sql.Select("COUNT(*)")
|
||||
.From<UserDto>()
|
||||
.Where<UserDto>(x => x.UserName == escapedUserName);
|
||||
.Where<UserDto>(x => x.UserName == username);
|
||||
|
||||
return Database.ExecuteScalar<int>(sql) > 0;
|
||||
}
|
||||
|
||||
@@ -188,6 +188,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="updateDate"></param>
|
||||
/// <returns></returns>
|
||||
protected PropertyCollection GetPropertyCollection(int id, Guid versionId, IContentTypeComposition contentType, DateTime createDate, DateTime updateDate)
|
||||
|
||||
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
|
||||
@@ -13,10 +13,19 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
string EscapeString(string val);
|
||||
|
||||
string GetWildcardPlaceholder();
|
||||
string GetStringColumnEqualComparison(string column, int paramIndex, TextColumnType columnType);
|
||||
string GetStringColumnWildcardComparison(string column, int paramIndex, TextColumnType columnType);
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType);
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType);
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType);
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType);
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
string GetStringColumnWildcardComparison(string column, string value, TextColumnType columnType);
|
||||
|
||||
string GetQuotedTableName(string tableName);
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract class for defining MS sql implementations
|
||||
/// </summary>
|
||||
/// <typeparam name="TSyntax"></typeparam>
|
||||
public abstract class MicrosoftSqlSyntaxProviderBase<TSyntax> : SqlSyntaxProviderBase<TSyntax>
|
||||
where TSyntax : ISqlSyntaxProvider
|
||||
{
|
||||
public override string RenameTable { get { return "sp_rename '{0}', '{1}'"; } }
|
||||
|
||||
public override string AddColumn { get { return "ALTER TABLE {0} ADD {1}"; } }
|
||||
|
||||
public override string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("[{0}]", tableName);
|
||||
}
|
||||
|
||||
public override string GetQuotedColumnName(string columnName)
|
||||
{
|
||||
return string.Format("[{0}]", columnName);
|
||||
}
|
||||
|
||||
public override string GetQuotedName(string name)
|
||||
{
|
||||
return string.Format("[{0}]", name);
|
||||
}
|
||||
|
||||
public override string GetStringColumnEqualComparison(string column, int paramIndex, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnEqualComparison(column, paramIndex, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for = comparison with NText columns but allows this syntax
|
||||
return string.Format("{0} LIKE @{1}", column, paramIndex);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnWildcardComparison(string column, int paramIndex, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnWildcardComparison(column, paramIndex, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE @{1}", column, paramIndex);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
public override string GetStringColumnWildcardComparison(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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// Represents an SqlSyntaxProvider for Sql Ce
|
||||
/// </summary>
|
||||
[SqlSyntaxProviderAttribute("System.Data.SqlServerCe.4.0")]
|
||||
public class SqlCeSyntaxProvider : SqlSyntaxProviderBase<SqlCeSyntaxProvider>
|
||||
public class SqlCeSyntaxProvider : MicrosoftSqlSyntaxProviderBase<SqlCeSyntaxProvider>
|
||||
{
|
||||
public SqlCeSyntaxProvider()
|
||||
{
|
||||
@@ -60,6 +60,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return indexType;
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
public override string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
@@ -74,76 +75,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
}
|
||||
}
|
||||
|
||||
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 GetStringColumnWildcardComparison(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);
|
||||
}
|
||||
|
||||
public override string GetQuotedColumnName(string columnName)
|
||||
{
|
||||
return string.Format("[{0}]", columnName);
|
||||
}
|
||||
|
||||
public override string GetQuotedName(string name)
|
||||
{
|
||||
return string.Format("[{0}]", name);
|
||||
}
|
||||
|
||||
|
||||
public override string FormatColumnRename(string tableName, string oldName, string newName)
|
||||
{
|
||||
@@ -285,10 +217,10 @@ ORDER BY TABLE_NAME, INDEX_NAME");
|
||||
}
|
||||
}
|
||||
|
||||
public override string AddColumn { get { return "ALTER TABLE {0} ADD {1}"; } }
|
||||
|
||||
|
||||
public override string DropIndex { get { return "DROP INDEX {1}.{0}"; } }
|
||||
|
||||
public override string RenameTable { get { return "sp_rename '{0}', '{1}'"; } }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
@@ -10,7 +9,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// Represents an SqlSyntaxProvider for Sql Server
|
||||
/// </summary>
|
||||
[SqlSyntaxProviderAttribute("System.Data.SqlClient")]
|
||||
public class SqlServerSyntaxProvider : SqlSyntaxProviderBase<SqlServerSyntaxProvider>
|
||||
public class SqlServerSyntaxProvider : MicrosoftSqlSyntaxProviderBase<SqlServerSyntaxProvider>
|
||||
{
|
||||
public SqlServerSyntaxProvider()
|
||||
{
|
||||
@@ -33,91 +32,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// Gets/sets the version of the current SQL server instance
|
||||
/// </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 GetStringColumnWildcardComparison(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);
|
||||
}
|
||||
|
||||
public override string GetQuotedColumnName(string columnName)
|
||||
{
|
||||
return string.Format("[{0}]", columnName);
|
||||
}
|
||||
|
||||
public override string GetQuotedName(string name)
|
||||
{
|
||||
return string.Format("[{0}]", name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override IEnumerable<string> GetTablesInSchema(Database db)
|
||||
{
|
||||
@@ -218,12 +134,11 @@ order by T.name, I.name");
|
||||
get { return "ALTER TABLE [{0}] DROP CONSTRAINT [DF_{0}_{1}]"; }
|
||||
}
|
||||
|
||||
public override string AddColumn { get { return "ALTER TABLE {0} ADD {1}"; } }
|
||||
|
||||
|
||||
public override string DropIndex { get { return "DROP INDEX {0} ON {1}"; } }
|
||||
|
||||
public override string RenameColumn { get { return "sp_rename '{0}.{1}', '{2}', 'COLUMN'"; } }
|
||||
|
||||
public override string RenameTable { get { return "sp_rename '{0}', '{1}'"; } }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
};
|
||||
}
|
||||
|
||||
public string GetWildcardPlaceholder()
|
||||
{
|
||||
return "%";
|
||||
}
|
||||
|
||||
public string StringLengthNonUnicodeColumnDefinitionFormat = "VARCHAR({0})";
|
||||
public string StringLengthUnicodeColumnDefinitionFormat = "NVARCHAR({0})";
|
||||
|
||||
@@ -108,34 +113,51 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return PetaPocoExtensions.EscapeAtSymbols(val.Replace("'", "''"));
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnEqualComparison(string column, int paramIndex, 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}) = upper(@{1})", column, paramIndex);
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnWildcardComparison(string column, int paramIndex, 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 upper(@{1})", column, paramIndex);
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
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());
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
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());
|
||||
return string.Format("upper({0}) LIKE '{1}%'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
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());
|
||||
return string.Format("upper({0}) LIKE '%{1}'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
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());
|
||||
return string.Format("upper({0}) LIKE '%{1}%'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload with the parameter index instead")]
|
||||
public virtual string GetStringColumnWildcardComparison(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());
|
||||
return string.Format("upper({0}) LIKE '{1}'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetQuotedTableName(string tableName)
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
/// <remarks>
|
||||
/// See: http://issues.umbraco.org/issue/U4-3876
|
||||
/// </remarks>
|
||||
public static string GetDeleteSubquery(this ISqlSyntaxProvider sqlProvider, string tableName, string columnName, Sql subQuery)
|
||||
public static Sql GetDeleteSubquery(this ISqlSyntaxProvider sqlProvider, string tableName, string columnName, Sql subQuery)
|
||||
{
|
||||
return string.Format(@"DELETE FROM {0} WHERE {1} IN (SELECT {1} FROM ({2}) x)",
|
||||
sqlProvider.GetQuotedTableName(tableName),
|
||||
sqlProvider.GetQuotedColumnName(columnName),
|
||||
subQuery.SQL);
|
||||
return new Sql(string.Format(@"DELETE FROM {0} WHERE {1} IN (SELECT {1} FROM ({2}) x)",
|
||||
sqlProvider.GetQuotedTableName(tableName),
|
||||
sqlProvider.GetQuotedColumnName(columnName),
|
||||
subQuery.SQL), subQuery.Arguments);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -484,6 +484,10 @@ namespace Umbraco.Core.Services
|
||||
public IEnumerable<IContent> GetDescendants(int id)
|
||||
{
|
||||
var content = GetById(id);
|
||||
if (content == null)
|
||||
{
|
||||
return Enumerable.Empty<IContent>();
|
||||
}
|
||||
return GetDescendants(content);
|
||||
}
|
||||
|
||||
@@ -496,7 +500,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(content.Path) && x.Id != content.Id);
|
||||
var pathMatch = content.Path + ",";
|
||||
var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(pathMatch) && x.Id != content.Id);
|
||||
var contents = repository.GetByQuery(query);
|
||||
|
||||
return contents;
|
||||
|
||||
@@ -252,7 +252,8 @@ namespace Umbraco.Core.Services
|
||||
using (var repository = _repositoryFactory.CreateEntityRepository(_uowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var entity = repository.Get(id);
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.Path.StartsWith(entity.Path) && x.Id != id);
|
||||
var pathMatch = entity.Path + ",";
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.Path.StartsWith(pathMatch) && x.Id != id);
|
||||
var entities = repository.GetByQuery(query);
|
||||
|
||||
return entities;
|
||||
|
||||
@@ -402,6 +402,10 @@ namespace Umbraco.Core.Services
|
||||
public IEnumerable<IMedia> GetDescendants(int id)
|
||||
{
|
||||
var media = GetById(id);
|
||||
if (media == null)
|
||||
{
|
||||
return Enumerable.Empty<IMedia>();
|
||||
}
|
||||
return GetDescendants(media);
|
||||
}
|
||||
|
||||
@@ -415,7 +419,8 @@ namespace Umbraco.Core.Services
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
var query = Query<IMedia>.Builder.Where(x => x.Path.StartsWith(media.Path) && x.Id != media.Id);
|
||||
var pathMatch = media.Path + ",";
|
||||
var query = Query<IMedia>.Builder.Where(x => x.Path.StartsWith(pathMatch) && x.Id != media.Id);
|
||||
var medias = repository.GetByQuery(query);
|
||||
|
||||
return medias;
|
||||
@@ -1198,4 +1203,4 @@ namespace Umbraco.Core.Services
|
||||
public static event TypedEventHandler<IMediaService, RecycleBinEventArgs> EmptiedRecycleBin;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,6 +233,7 @@
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixTwoZero\AssignMissingPrimaryForMySqlKeys2.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixTwoZero\ChangePasswordColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixTwoZero\UpdateToNewMemberPropertyAliases.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\MicrosoftSqlSyntaxProviderBase.cs" />
|
||||
<Compile Include="Persistence\Querying\SqlStringExtensions.cs" />
|
||||
<Compile Include="Persistence\Querying\StringPropertyMatchType.cs" />
|
||||
<Compile Include="Persistence\Querying\TextColumnType.cs" />
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
//using System;
|
||||
//using System.Linq;
|
||||
//using NUnit.Framework;
|
||||
//using Umbraco.Core.Models;
|
||||
//using Umbraco.Core.Persistence;
|
||||
//using Umbraco.Core.Persistence.SqlSyntax;
|
||||
//using Umbraco.Tests.TestHelpers;
|
||||
//using Umbraco.Tests.TestHelpers.Entities;
|
||||
|
||||
//namespace Umbraco.Tests.Persistence
|
||||
//{
|
||||
// [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
|
||||
// [TestFixture]
|
||||
// public class PetaPocoDynamicQueryTests : BaseDatabaseFactoryTest
|
||||
// {
|
||||
// [Test]
|
||||
// public void Check_Poco_Storage_Growth()
|
||||
// {
|
||||
// //CreateStuff();
|
||||
|
||||
// for (int i = 0; i < 1000; i++)
|
||||
// {
|
||||
// DatabaseContext.Database.Fetch<dynamic>(
|
||||
// "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='" + i + "'");
|
||||
// }
|
||||
|
||||
// //var oc11 = Database.PocoData.GetCachedPocoData().Count();
|
||||
// //var oc12 = Database.PocoData.GetConverters().Count();
|
||||
// //var oc13 = Database.GetAutoMappers().Count();
|
||||
// //var oc14 = Database.GetMultiPocoFactories().Count();
|
||||
|
||||
// //for (int i = 0; i < 2; i++)
|
||||
// //{
|
||||
// // i1 = DatabaseContext.Database.Fetch<dynamic>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");
|
||||
// // r1 = i1.Select(x => x.TABLE_NAME).Cast<string>().ToList();
|
||||
// //}
|
||||
|
||||
// //var oc21 = Database.PocoData.GetCachedPocoData().Count();
|
||||
// //var oc22 = Database.PocoData.GetConverters().Count();
|
||||
// //var oc23 = Database.GetAutoMappers().Count();
|
||||
// //var oc24 = Database.GetMultiPocoFactories().Count();
|
||||
|
||||
// //var roots = ServiceContext.ContentService.GetRootContent();
|
||||
// //foreach (var content in roots)
|
||||
// //{
|
||||
// // var d = ServiceContext.ContentService.GetDescendants(content);
|
||||
// //}
|
||||
|
||||
// //var oc31 = Database.PocoData.GetCachedPocoData().Count();
|
||||
// //var oc32 = Database.PocoData.GetConverters().Count();
|
||||
// //var oc33 = Database.GetAutoMappers().Count();
|
||||
// //var oc34 = Database.GetMultiPocoFactories().Count();
|
||||
|
||||
// //for (int i = 0; i < 2; i++)
|
||||
// //{
|
||||
// // roots = ServiceContext.ContentService.GetRootContent();
|
||||
// // foreach (var content in roots)
|
||||
// // {
|
||||
// // var d = ServiceContext.ContentService.GetDescendants(content);
|
||||
// // }
|
||||
// //}
|
||||
|
||||
// //var oc41 = Database.PocoData.GetCachedPocoData().Count();
|
||||
// //var oc42 = Database.PocoData.GetConverters().Count();
|
||||
// //var oc43 = Database.GetAutoMappers().Count();
|
||||
// //var oc44 = Database.GetMultiPocoFactories().Count();
|
||||
|
||||
// //var i2 = DatabaseContext.Database.Fetch<dynamic>("SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS");
|
||||
// //var r2 =
|
||||
// // i2.Select(
|
||||
// // item =>
|
||||
// // new ColumnInfo(item.TABLE_NAME, item.COLUMN_NAME, item.ORDINAL_POSITION, item.COLUMN_DEFAULT,
|
||||
// // item.IS_NULLABLE, item.DATA_TYPE)).ToList();
|
||||
|
||||
|
||||
// var pocoData = Database.PocoData.GetCachedPocoData();
|
||||
// Console.WriteLine("GetCachedPocoData: " + pocoData.Count());
|
||||
// foreach (var keyValuePair in pocoData)
|
||||
// {
|
||||
// Console.WriteLine(keyValuePair.Value.GetFactories().Count());
|
||||
// }
|
||||
|
||||
// Console.WriteLine("GetConverters: " + Database.PocoData.GetConverters().Count());
|
||||
// Console.WriteLine("GetAutoMappers: " + Database.GetAutoMappers().Count());
|
||||
// Console.WriteLine("GetMultiPocoFactories: " + Database.GetMultiPocoFactories().Count());
|
||||
|
||||
// //Assert.AreEqual(oc11, oc21);
|
||||
// //Assert.AreEqual(oc12, oc22);
|
||||
// //Assert.AreEqual(oc13, oc23);
|
||||
// //Assert.AreEqual(oc14, oc24);
|
||||
|
||||
// //Assert.AreEqual(oc31, oc41);
|
||||
// //Assert.AreEqual(oc32, oc42);
|
||||
// //Assert.AreEqual(oc33, oc43);
|
||||
// //Assert.AreEqual(oc34, oc44);
|
||||
// }
|
||||
|
||||
// public void CreateStuff()
|
||||
// {
|
||||
// var contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "test1");
|
||||
// var contentType2 = MockedContentTypes.CreateTextpageContentType("test2", "test2");
|
||||
// var contentType3 = MockedContentTypes.CreateTextpageContentType("test3", "test3");
|
||||
// ServiceContext.ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 });
|
||||
// contentType1.AllowedContentTypes = new[]
|
||||
// {
|
||||
// new ContentTypeSort(new Lazy<int>(() => contentType2.Id), 0, contentType2.Alias),
|
||||
// new ContentTypeSort(new Lazy<int>(() => contentType3.Id), 1, contentType3.Alias)
|
||||
// };
|
||||
// contentType2.AllowedContentTypes = new[]
|
||||
// {
|
||||
// new ContentTypeSort(new Lazy<int>(() => contentType1.Id), 0, contentType1.Alias),
|
||||
// new ContentTypeSort(new Lazy<int>(() => contentType3.Id), 1, contentType3.Alias)
|
||||
// };
|
||||
// contentType3.AllowedContentTypes = new[]
|
||||
// {
|
||||
// new ContentTypeSort(new Lazy<int>(() => contentType1.Id), 0, contentType1.Alias),
|
||||
// new ContentTypeSort(new Lazy<int>(() => contentType2.Id), 1, contentType2.Alias)
|
||||
// };
|
||||
// ServiceContext.ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 });
|
||||
|
||||
// var roots = MockedContent.CreateTextpageContent(contentType1, -1, 3);
|
||||
// ServiceContext.ContentService.Save(roots);
|
||||
// foreach (var root in roots)
|
||||
// {
|
||||
// var item1 = MockedContent.CreateTextpageContent(contentType1, root.Id, 3);
|
||||
// var item2 = MockedContent.CreateTextpageContent(contentType2, root.Id, 3);
|
||||
// var item3 = MockedContent.CreateTextpageContent(contentType3, root.Id, 3);
|
||||
|
||||
// ServiceContext.ContentService.Save(item1.Concat(item2).Concat(item3));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,14 +1,195 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
|
||||
namespace Umbraco.Tests.Persistence
|
||||
{
|
||||
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
|
||||
[TestFixture, NUnit.Framework.Ignore]
|
||||
public class PetaPocoCachesTest : BaseServiceTest
|
||||
{
|
||||
/// <summary>
|
||||
/// This tests the peta poco caches
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This test WILL fail. This is because we cannot stop PetaPoco from creating more cached items for queries such as
|
||||
/// ContentTypeRepository.GetAll(1,2,3,4);
|
||||
/// when combined with other GetAll queries that pass in an array of Ids, each query generated for different length
|
||||
/// arrays will produce a unique query which then gets added to the cache.
|
||||
///
|
||||
/// This test confirms this, if you analyze the DIFFERENCE output below you can see why the cached queries grow.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void Check_Peta_Poco_Caches()
|
||||
{
|
||||
var result = new List<Tuple<double, int, IEnumerable<string>>>();
|
||||
|
||||
Database.PocoData.UseLongKeys = true;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int id1, id2, id3;
|
||||
string alias;
|
||||
CreateStuff(out id1, out id2, out id3, out alias);
|
||||
QueryStuff(id1, id2, id3, alias);
|
||||
|
||||
double totalBytes1;
|
||||
IEnumerable<string> keys;
|
||||
Console.Write(Database.PocoData.PrintDebugCacheReport(out totalBytes1, out keys));
|
||||
|
||||
result.Add(new Tuple<double, int, IEnumerable<string>>(totalBytes1, keys.Count(), keys));
|
||||
}
|
||||
|
||||
for (int index = 0; index < result.Count; index++)
|
||||
{
|
||||
var tuple = result[index];
|
||||
Console.WriteLine("Bytes: {0}, Delegates: {1}", tuple.Item1, tuple.Item2);
|
||||
if (index != 0)
|
||||
{
|
||||
Console.WriteLine("----------------DIFFERENCE---------------------");
|
||||
var diff = tuple.Item3.Except(result[index - 1].Item3);
|
||||
foreach (var d in diff)
|
||||
{
|
||||
Console.WriteLine(d);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var allByteResults = result.Select(x => x.Item1).Distinct();
|
||||
var totalKeys = result.Select(x => x.Item2).Distinct();
|
||||
|
||||
Assert.AreEqual(1, allByteResults.Count());
|
||||
Assert.AreEqual(1, totalKeys.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Verify_Memory_Expires()
|
||||
{
|
||||
Database.PocoData.SlidingExpirationSeconds = 2;
|
||||
|
||||
var managedCache = new Database.ManagedCache();
|
||||
|
||||
int id1, id2, id3;
|
||||
string alias;
|
||||
CreateStuff(out id1, out id2, out id3, out alias);
|
||||
QueryStuff(id1, id2, id3, alias);
|
||||
|
||||
var count1 = managedCache.GetCache().GetCount();
|
||||
Console.WriteLine("Keys = " + count1);
|
||||
Assert.Greater(count1, 0);
|
||||
|
||||
Thread.Sleep(10000);
|
||||
|
||||
var count2 = managedCache.GetCache().GetCount();
|
||||
Console.WriteLine("Keys = " + count2);
|
||||
Assert.Less(count2, count1);
|
||||
}
|
||||
|
||||
private void QueryStuff(int id1, int id2, int id3, string alias1)
|
||||
{
|
||||
var contentService = ServiceContext.ContentService;
|
||||
|
||||
|
||||
|
||||
contentService.CountDescendants(id3);
|
||||
|
||||
contentService.CountChildren(id3);
|
||||
|
||||
contentService.Count(contentTypeAlias: alias1);
|
||||
|
||||
contentService.Count();
|
||||
|
||||
contentService.GetById(Guid.NewGuid());
|
||||
|
||||
contentService.GetByLevel(2);
|
||||
|
||||
contentService.GetChildren(id1);
|
||||
|
||||
contentService.GetDescendants(id2);
|
||||
|
||||
contentService.GetVersions(id3);
|
||||
|
||||
contentService.GetRootContent();
|
||||
|
||||
contentService.GetContentForExpiration();
|
||||
|
||||
contentService.GetContentForRelease();
|
||||
|
||||
contentService.GetContentInRecycleBin();
|
||||
|
||||
((ContentService)contentService).GetPublishedDescendants(new Content("Test", -1, new ContentType(-1))
|
||||
{
|
||||
Id = id1,
|
||||
Path = "-1," + id1
|
||||
});
|
||||
|
||||
contentService.GetByVersion(Guid.NewGuid());
|
||||
}
|
||||
|
||||
private void CreateStuff(out int id1, out int id2, out int id3, out string alias)
|
||||
{
|
||||
var contentService = ServiceContext.ContentService;
|
||||
|
||||
var ctAlias = "umbTextpage" + Guid.NewGuid().ToString("N");
|
||||
alias = ctAlias;
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
contentService.CreateContentWithIdentity("Test", -1, "umbTextpage", 0);
|
||||
}
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType(ctAlias, "test Doc Type");
|
||||
contentTypeService.Save(contentType);
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
contentService.CreateContentWithIdentity("Test", -1, ctAlias, 0);
|
||||
}
|
||||
var parent = contentService.CreateContentWithIdentity("Test", -1, ctAlias, 0);
|
||||
id1 = parent.Id;
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
contentService.CreateContentWithIdentity("Test", parent, ctAlias);
|
||||
}
|
||||
IContent current = parent;
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
current = contentService.CreateContentWithIdentity("Test", current, ctAlias);
|
||||
}
|
||||
contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory" + Guid.NewGuid().ToString("N"), "Mandatory Doc Type", true);
|
||||
contentType.PropertyGroups.First().PropertyTypes.Add(
|
||||
new PropertyType(Guid.NewGuid(), DataTypeDatabaseType.Ntext)
|
||||
{
|
||||
Alias = "tags",
|
||||
DataTypeDefinitionId = 1041
|
||||
});
|
||||
contentTypeService.Save(contentType);
|
||||
var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1);
|
||||
|
||||
contentService.Publish(content1);
|
||||
id2 = content1.Id;
|
||||
|
||||
var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1);
|
||||
|
||||
contentService.Publish(content2);
|
||||
id3 = content2.Id;
|
||||
|
||||
contentService.MoveToRecycleBin(content1);
|
||||
}
|
||||
}
|
||||
|
||||
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
|
||||
[TestFixture]
|
||||
public class PetaPocoExtensionsTest : BaseDatabaseFactoryTest
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.InnerJoin("[cmsContentVersion]").On("[cmsDocument].[versionId] = [cmsContentVersion].[VersionId]")
|
||||
.InnerJoin("[cmsContent]").On("[cmsContentVersion].[ContentId] = [cmsContent].[nodeId]")
|
||||
.InnerJoin("[umbracoNode]").On("[cmsContent].[nodeId] = [umbracoNode].[id]")
|
||||
.Where("[umbracoNode].[nodeObjectType] = 'c66ba18e-eaf3-4cff-8a22-41b16d66a972'");
|
||||
.Where("[umbracoNode].[nodeObjectType] = @0", new Guid("c66ba18e-eaf3-4cff-8a22-41b16d66a972"));
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -36,6 +36,12 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
|
||||
@@ -50,8 +56,8 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.InnerJoin("[cmsContentVersion]").On("[cmsDocument].[versionId] = [cmsContentVersion].[VersionId]")
|
||||
.InnerJoin("[cmsContent]").On("[cmsContentVersion].[ContentId] = [cmsContent].[nodeId]")
|
||||
.InnerJoin("[umbracoNode]").On("[cmsContent].[nodeId] = [umbracoNode].[id]")
|
||||
.Where("[umbracoNode].[nodeObjectType] = 'c66ba18e-eaf3-4cff-8a22-41b16d66a972'")
|
||||
.Where("[umbracoNode].[id] = 1050");
|
||||
.Where("[umbracoNode].[nodeObjectType] = @0", new Guid("c66ba18e-eaf3-4cff-8a22-41b16d66a972"))
|
||||
.Where("[umbracoNode].[id] = @0", 1050);
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -67,6 +73,12 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
|
||||
@@ -82,9 +94,9 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.InnerJoin("[cmsContentVersion]").On("[cmsDocument].[versionId] = [cmsContentVersion].[VersionId]")
|
||||
.InnerJoin("[cmsContent]").On("[cmsContentVersion].[ContentId] = [cmsContent].[nodeId]")
|
||||
.InnerJoin("[umbracoNode]").On("[cmsContent].[nodeId] = [umbracoNode].[id]")
|
||||
.Where("[umbracoNode].[nodeObjectType] = 'c66ba18e-eaf3-4cff-8a22-41b16d66a972'")
|
||||
.Where("[umbracoNode].[id] = 1050")
|
||||
.Where("[cmsContentVersion].[VersionId] = '2b543516-a944-4ee6-88c6-8813da7aaa07'")
|
||||
.Where("[umbracoNode].[nodeObjectType] = @0", new Guid("c66ba18e-eaf3-4cff-8a22-41b16d66a972"))
|
||||
.Where("[umbracoNode].[id] = @0", 1050)
|
||||
.Where("[cmsContentVersion].[VersionId] = @0", new Guid("2b543516-a944-4ee6-88c6-8813da7aaa07"))
|
||||
.OrderBy("[cmsContentVersion].[VersionDate] DESC");
|
||||
|
||||
var sql = new Sql();
|
||||
@@ -102,6 +114,11 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
@@ -116,8 +133,8 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
expected.Select("*");
|
||||
expected.From("[cmsPropertyData]");
|
||||
expected.InnerJoin("[cmsPropertyType]").On("[cmsPropertyData].[propertytypeid] = [cmsPropertyType].[id]");
|
||||
expected.Where("[cmsPropertyData].[contentNodeId] = 1050");
|
||||
expected.Where("[cmsPropertyData].[versionId] = '2b543516-a944-4ee6-88c6-8813da7aaa07'");
|
||||
expected.Where("[cmsPropertyData].[contentNodeId] = @0", 1050);
|
||||
expected.Where("[cmsPropertyData].[versionId] = @0", new Guid("2b543516-a944-4ee6-88c6-8813da7aaa07"));
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -128,6 +145,11 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.Where<PropertyDataDto>(x => x.VersionId == versionId);
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.On("[cmsContentType].[nodeId] = [cmsDocumentType].[contentTypeNodeId]")
|
||||
.InnerJoin("[umbracoNode]")
|
||||
.On("[cmsContentType].[nodeId] = [umbracoNode].[id]")
|
||||
.Where("[umbracoNode].[nodeObjectType] = 'a2cb7800-f571-4787-9638-bc48539a0efb'")
|
||||
.Where("[cmsDocumentType].[IsDefault] = 1");
|
||||
.Where("[umbracoNode].[nodeObjectType] = @0", new Guid("a2cb7800-f571-4787-9638-bc48539a0efb"))
|
||||
.Where("[cmsDocumentType].[IsDefault] = @0", true);
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -37,6 +37,12 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
|
||||
@@ -52,9 +58,9 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.On("[cmsContentType].[nodeId] = [cmsDocumentType].[contentTypeNodeId]")
|
||||
.InnerJoin("[umbracoNode]")
|
||||
.On("[cmsContentType].[nodeId] = [umbracoNode].[id]")
|
||||
.Where("[umbracoNode].[nodeObjectType] = 'a2cb7800-f571-4787-9638-bc48539a0efb'")
|
||||
.Where("[cmsDocumentType].[IsDefault] = 1")
|
||||
.Where("[umbracoNode].[id] = 1050");
|
||||
.Where("[umbracoNode].[nodeObjectType] = @0", new Guid("a2cb7800-f571-4787-9638-bc48539a0efb"))
|
||||
.Where("[cmsDocumentType].[IsDefault] = @0", true)
|
||||
.Where("[umbracoNode].[id] = @0", 1050);
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -64,11 +70,17 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectType)
|
||||
.Where<DocumentTypeDto>(x => x.IsDefault == true)
|
||||
.Where<DocumentTypeDto>(x => x.IsDefault)
|
||||
.Where<NodeDto>(x => x.NodeId == 1050);
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
|
||||
@@ -100,7 +112,7 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
var expected = new Sql();
|
||||
expected.Select("*")
|
||||
.From("[cmsContentTypeAllowedContentType]")
|
||||
.Where("[cmsContentTypeAllowedContentType].[Id] = 1050");
|
||||
.Where("[cmsContentTypeAllowedContentType].[Id] = @0", 1050);
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -109,6 +121,12 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
|
||||
@@ -120,7 +138,7 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.From("[cmsPropertyTypeGroup]")
|
||||
.RightJoin("[cmsPropertyType]").On("[cmsPropertyTypeGroup].[id] = [cmsPropertyType].[propertyTypeGroupId]")
|
||||
.InnerJoin("[cmsDataType]").On("[cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]")
|
||||
.Where("[cmsPropertyType].[contentTypeId] = 1050");
|
||||
.Where("[cmsPropertyType].[contentTypeId] = @0", 1050);
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -133,6 +151,12 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -19,7 +19,7 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
expected.Select("*")
|
||||
.From("[cmsDataType]")
|
||||
.InnerJoin("[umbracoNode]").On("[cmsDataType].[nodeId] = [umbracoNode].[id]")
|
||||
.Where("[umbracoNode].[nodeObjectType] = '30a2a501-1978-4ddb-a57b-f7efed43ba3c'");
|
||||
.Where("[umbracoNode].[nodeObjectType] = @0", new Guid("30a2a501-1978-4ddb-a57b-f7efed43ba3c"));
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -30,6 +30,12 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Console.WriteLine("Model to Sql ExpressionHelper: \n" + result);
|
||||
|
||||
Assert.AreEqual("upper([umbracoNode].[path]) like '-1%'", result);
|
||||
Assert.AreEqual("upper([umbracoNode].[path]) LIKE upper(@0)", result);
|
||||
Assert.AreEqual("-1%", modelToSqlExpressionHelper.GetSqlParameters()[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -36,7 +37,8 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Console.WriteLine("Model to Sql ExpressionHelper: \n" + result);
|
||||
|
||||
Assert.AreEqual("[umbracoNode].[parentID] = -1", result);
|
||||
Assert.AreEqual("[umbracoNode].[parentID] = @0", result);
|
||||
Assert.AreEqual(-1, modelToSqlExpressionHelper.GetSqlParameters()[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -48,7 +50,8 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Console.WriteLine("Model to Sql ExpressionHelper: \n" + result);
|
||||
|
||||
Assert.AreEqual("[umbracoUser].[userLogin] = 'hello@@world.com'", result);
|
||||
Assert.AreEqual("[umbracoUser].[userLogin] = @0", result);
|
||||
Assert.AreEqual("hello@world.com", modelToSqlExpressionHelper.GetSqlParameters()[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -60,7 +63,8 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Console.WriteLine("Model to Sql ExpressionHelper: \n" + result);
|
||||
|
||||
Assert.AreEqual("upper([umbracoUser].[userLogin]) = 'HELLO@@WORLD.COM'", result);
|
||||
Assert.AreEqual("upper([umbracoUser].[userLogin]) = upper(@0)", result);
|
||||
Assert.AreEqual("hello@world.com", modelToSqlExpressionHelper.GetSqlParameters()[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -75,7 +79,9 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Console.WriteLine("Model to Sql ExpressionHelper: \n" + result);
|
||||
|
||||
Assert.AreEqual("upper(`umbracoUser`.`userLogin`) = 'MYDOMAIN\\\\MYUSER'", result);
|
||||
Assert.AreEqual("upper(`umbracoUser`.`userLogin`) = upper(@0)", result);
|
||||
Assert.AreEqual("mydomain\\myuser", modelToSqlExpressionHelper.GetSqlParameters()[0]);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -90,7 +96,8 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Console.WriteLine("Poco to Sql ExpressionHelper: \n" + result);
|
||||
|
||||
Assert.AreEqual("upper(`umbracoUser`.`userLogin`) like 'MYDOMAIN\\\\MYUSER%'", result);
|
||||
Assert.AreEqual("upper(`umbracoUser`.`userLogin`) LIKE upper(@0)", result);
|
||||
Assert.AreEqual("mydomain\\myuser%", modelToSqlExpressionHelper.GetSqlParameters()[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
.From("[cmsContentVersion]")
|
||||
.InnerJoin("[cmsContent]").On("[cmsContentVersion].[ContentId] = [cmsContent].[nodeId]")
|
||||
.InnerJoin("[umbracoNode]").On("[cmsContent].[nodeId] = [umbracoNode].[id]")
|
||||
.Where("[umbracoNode].[nodeObjectType] = 'b796f64c-1f99-4ffb-b886-4bf4bc011a9c'");
|
||||
.Where("[umbracoNode].[nodeObjectType] = @0", new Guid("b796f64c-1f99-4ffb-b886-4bf4bc011a9c"));
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -33,6 +33,12 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
expected.Select("*")
|
||||
.From("[cmsContentType]")
|
||||
.InnerJoin("[umbracoNode]").On("[cmsContentType].[nodeId] = [umbracoNode].[id]")
|
||||
.Where("[umbracoNode].[nodeObjectType] = '4ea4382b-2f5a-4c2b-9587-ae9b3cf3602e'");
|
||||
.Where("[umbracoNode].[nodeObjectType] = @0", new Guid("4ea4382b-2f5a-4c2b-9587-ae9b3cf3602e"));
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -30,6 +30,12 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
|
||||
Assert.That(sql.SQL, Is.EqualTo(expected.SQL));
|
||||
|
||||
Assert.AreEqual(expected.Arguments.Length, sql.Arguments.Length);
|
||||
for (int i = 0; i < expected.Arguments.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.Arguments[i], sql.Arguments[i]);
|
||||
}
|
||||
|
||||
Console.WriteLine(sql.SQL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
@@ -6,12 +7,141 @@ using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Querying
|
||||
{
|
||||
[TestFixture]
|
||||
public class PetaPocoSqlTests : BaseUsingSqlCeSyntax
|
||||
{
|
||||
//x =>
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_With_Starts_With_Additional_Parameters()
|
||||
{
|
||||
var content = new NodeDto() { NodeId = 123, Path = "-1,123" };
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Path.SqlStartsWith(content.Path, TextColumnType.NVarchar));
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (upper([umbracoNode].[path]) LIKE upper(@0))", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(1, sql.Arguments.Length);
|
||||
Assert.AreEqual(content.Path + "%", sql.Arguments[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_With_Starts_With_By_Variable()
|
||||
{
|
||||
var content = new NodeDto() {NodeId = 123, Path = "-1,123"};
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Path.StartsWith(content.Path) && x.NodeId != content.NodeId);
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (upper([umbracoNode].[path]) LIKE upper(@0) AND [umbracoNode].[id] <> @1)", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(2, sql.Arguments.Length);
|
||||
Assert.AreEqual(content.Path + "%", sql.Arguments[0]);
|
||||
Assert.AreEqual(content.NodeId, sql.Arguments[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_With_Not_Starts_With()
|
||||
{
|
||||
var level = 1;
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Level == level && !x.Path.StartsWith("-20"));
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[level] = @0 AND NOT (upper([umbracoNode].[path]) LIKE upper(@1)))", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(2, sql.Arguments.Length);
|
||||
Assert.AreEqual(level, sql.Arguments[0]);
|
||||
Assert.AreEqual("-20%", sql.Arguments[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_With_Equals_Clause()
|
||||
{
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Text.Equals("Hello@world.com"));
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (upper([umbracoNode].[text]) = upper(@0))", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(1, sql.Arguments.Length);
|
||||
Assert.AreEqual("Hello@world.com", sql.Arguments[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_With_False_Boolean()
|
||||
{
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => !x.Trashed);
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (NOT ([umbracoNode].[trashed] = @0))", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(1, sql.Arguments.Length);
|
||||
Assert.AreEqual(true, sql.Arguments[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_With_Boolean()
|
||||
{
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Trashed);
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[trashed] = @0)", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(1, sql.Arguments.Length);
|
||||
Assert.AreEqual(true, sql.Arguments[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_With_ToUpper()
|
||||
{
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Text.ToUpper() == "hello".ToUpper());
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (upper([umbracoNode].[text]) = upper(@0))", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(1, sql.Arguments.Length);
|
||||
Assert.AreEqual("hello", sql.Arguments[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_With_ToString()
|
||||
{
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Text == 1.ToString());
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[text] = @0)", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(1, sql.Arguments.Length);
|
||||
Assert.AreEqual("1", sql.Arguments[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_With_Wildcard()
|
||||
{
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Text.StartsWith("D"));
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (upper([umbracoNode].[text]) LIKE upper(@0))", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(1, sql.Arguments.Length);
|
||||
Assert.AreEqual("D%", sql.Arguments[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_Single_Constant()
|
||||
{
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.NodeId == 2);
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[id] = @0)", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(1, sql.Arguments.Length);
|
||||
Assert.AreEqual(2, sql.Arguments[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_And_Constant()
|
||||
{
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.NodeId != 2 && x.NodeId != 3);
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[id] <> @0 AND [umbracoNode].[id] <> @1)", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(2, sql.Arguments.Length);
|
||||
Assert.AreEqual(2, sql.Arguments[0]);
|
||||
Assert.AreEqual(3, sql.Arguments[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Clause_Or_Constant()
|
||||
{
|
||||
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Text == "hello" || x.NodeId == 3);
|
||||
|
||||
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[text] = @0 OR [umbracoNode].[id] = @1)", sql.SQL.Replace("\n", " "));
|
||||
Assert.AreEqual(2, sql.Arguments.Length);
|
||||
Assert.AreEqual("hello", sql.Arguments[0]);
|
||||
Assert.AreEqual(3, sql.Arguments[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Select_From_With_Type()
|
||||
@@ -78,7 +208,7 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
public void Can_Use_Where_Predicate()
|
||||
{
|
||||
var expected = new Sql();
|
||||
expected.Select("*").From("[cmsContent]").Where("[cmsContent].[nodeId] = 1045");
|
||||
expected.Select("*").From("[cmsContent]").Where("[cmsContent].[nodeId] = @0", 1045);
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*").From<ContentDto>().Where<ContentDto>(x => x.NodeId == 1045);
|
||||
@@ -94,8 +224,8 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
var expected = new Sql();
|
||||
expected.Select("*")
|
||||
.From("[cmsContent]")
|
||||
.Where("[cmsContent].[nodeId] = 1045")
|
||||
.Where("[cmsContent].[contentType] = 1050");
|
||||
.Where("[cmsContent].[nodeId] = @0", 1045)
|
||||
.Where("[cmsContent].[contentType] = @0", 1050);
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
|
||||
@@ -12,21 +12,7 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
[TestFixture]
|
||||
public class QueryBuilderTests : BaseUsingSqlCeSyntax
|
||||
{
|
||||
[Test]
|
||||
public void Dates_Formatted_Properly()
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select("*").From<DocumentDto>();
|
||||
|
||||
var dt = new DateTime(2013, 11, 21, 13, 25, 55);
|
||||
|
||||
var query = Query<IContent>.Builder.Where(x => x.ExpireDate <= dt);
|
||||
var translator = new SqlTranslator<IContent>(sql, query);
|
||||
|
||||
var result = translator.Translate();
|
||||
|
||||
Assert.IsTrue(result.SQL.Contains("[expireDate] <= '2013-11-21 13:25:55'"));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Can_Build_StartsWith_Query_For_IContent()
|
||||
@@ -43,11 +29,15 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
var result = translator.Translate();
|
||||
var strResult = result.SQL;
|
||||
|
||||
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (upper([umbracoNode].[path]) like '-1%')";
|
||||
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (upper([umbracoNode].[path]) LIKE upper(@0))";
|
||||
|
||||
// Assert
|
||||
Assert.That(strResult, Is.Not.Empty);
|
||||
Assert.That(strResult, Is.EqualTo(expectedResult));
|
||||
|
||||
Assert.AreEqual(1, result.Arguments.Length);
|
||||
Assert.AreEqual("-1%", sql.Arguments[0]);
|
||||
|
||||
Console.WriteLine(strResult);
|
||||
}
|
||||
|
||||
@@ -66,11 +56,15 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
var result = translator.Translate();
|
||||
var strResult = result.SQL;
|
||||
|
||||
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE ([umbracoNode].[parentID] = -1)";
|
||||
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE ([umbracoNode].[parentID] = @0)";
|
||||
|
||||
// Assert
|
||||
Assert.That(strResult, Is.Not.Empty);
|
||||
Assert.That(strResult, Is.EqualTo(expectedResult));
|
||||
|
||||
Assert.AreEqual(1, result.Arguments.Length);
|
||||
Assert.AreEqual(-1, sql.Arguments[0]);
|
||||
|
||||
Console.WriteLine(strResult);
|
||||
}
|
||||
|
||||
@@ -89,11 +83,14 @@ namespace Umbraco.Tests.Persistence.Querying
|
||||
var result = translator.Translate();
|
||||
var strResult = result.SQL;
|
||||
|
||||
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE ([cmsContentType].[alias] = 'umbTextpage')";
|
||||
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE ([cmsContentType].[alias] = @0)";
|
||||
|
||||
// Assert
|
||||
Assert.That(strResult, Is.Not.Empty);
|
||||
Assert.That(strResult, Is.EqualTo(expectedResult));
|
||||
Assert.AreEqual(1, result.Arguments.Length);
|
||||
Assert.AreEqual("umbTextpage", sql.Arguments[0]);
|
||||
|
||||
Console.WriteLine(strResult);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,11 @@ namespace Umbraco.Tests.Persistence.SyntaxProvider
|
||||
FROM [cmsContentXml]
|
||||
INNER JOIN [umbracoNode]
|
||||
ON [cmsContentXml].[nodeId] = [umbracoNode].[id]
|
||||
WHERE ([umbracoNode].[nodeObjectType] = 'b796f64c-1f99-4ffb-b886-4bf4bc011a9c')) x)".Replace(Environment.NewLine, " ").Replace("\n", " ").Replace("\r", " "), sql.Replace(Environment.NewLine, " ").Replace("\n", " ").Replace("\r", " "));
|
||||
WHERE ([umbracoNode].[nodeObjectType] = @0)) x)".Replace(Environment.NewLine, " ").Replace("\n", " ").Replace("\r", " "),
|
||||
sql.SQL.Replace(Environment.NewLine, " ").Replace("\n", " ").Replace("\r", " "));
|
||||
|
||||
Assert.AreEqual(1, sql.Arguments.Length);
|
||||
Assert.AreEqual(mediaObjectType, sql.Arguments[0]);
|
||||
}
|
||||
|
||||
[NUnit.Framework.Ignore("This doesn't actually test anything")]
|
||||
|
||||
@@ -76,6 +76,30 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(entities.Any(x => x.Trashed), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Children_By_ParentId()
|
||||
{
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
var entities = service.GetChildren(folderId);
|
||||
|
||||
Assert.That(entities.Any(), Is.True);
|
||||
Assert.That(entities.Count(), Is.EqualTo(3));
|
||||
Assert.That(entities.Any(x => x.Trashed), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Descendants_By_ParentId()
|
||||
{
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
var entities = service.GetDescendents(folderId);
|
||||
|
||||
Assert.That(entities.Any(), Is.True);
|
||||
Assert.That(entities.Count(), Is.EqualTo(4));
|
||||
Assert.That(entities.Any(x => x.Trashed), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Throws_When_Getting_All_With_Invalid_Type()
|
||||
{
|
||||
@@ -129,7 +153,7 @@ namespace Umbraco.Tests.Services
|
||||
var entities = service.GetAll(UmbracoObjectTypes.Media);
|
||||
|
||||
Assert.That(entities.Any(), Is.True);
|
||||
Assert.That(entities.Count(), Is.EqualTo(3));
|
||||
Assert.That(entities.Count(), Is.EqualTo(5));
|
||||
//Assert.That(entities.Any(x => ((UmbracoEntity)x).UmbracoFile != string.Empty), Is.True);
|
||||
Assert.That(
|
||||
entities.Any(
|
||||
@@ -140,6 +164,8 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
private static bool _isSetup = false;
|
||||
|
||||
private int folderId;
|
||||
|
||||
public override void CreateTestData()
|
||||
{
|
||||
if (_isSetup == false)
|
||||
@@ -150,8 +176,9 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
//Create and Save folder-Media -> 1050
|
||||
var folderMediaType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1);
|
||||
var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1);
|
||||
ServiceContext.MediaService.Save(folder, 0);
|
||||
folderId = folder.Id;
|
||||
|
||||
//Create and Save image-Media -> 1051
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
@@ -162,6 +189,12 @@ namespace Umbraco.Tests.Services
|
||||
var fileMediaType = ServiceContext.ContentTypeService.GetMediaType(1033);
|
||||
var file = MockedMedia.CreateMediaFile(fileMediaType, folder.Id);
|
||||
ServiceContext.MediaService.Save(file, 0);
|
||||
|
||||
var subfolder = MockedMedia.CreateMediaFolder(folderMediaType, folder.Id);
|
||||
ServiceContext.MediaService.Save(subfolder, 0);
|
||||
var subfolder2 = MockedMedia.CreateMediaFolder(folderMediaType, subfolder.Id);
|
||||
ServiceContext.MediaService.Save(subfolder2, 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -93,15 +93,20 @@ namespace Umbraco.Tests.Services
|
||||
ServiceContext.MemberTypeService.Save(memberType);
|
||||
IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test");
|
||||
ServiceContext.MemberService.Save(member);
|
||||
//need to test with '@' symbol in the lookup
|
||||
IMember member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2@test.com");
|
||||
ServiceContext.MemberService.Save(member2);
|
||||
|
||||
ServiceContext.MemberService.AddRole("MyTestRole1");
|
||||
ServiceContext.MemberService.AddRole("MyTestRole2");
|
||||
ServiceContext.MemberService.AddRole("MyTestRole3");
|
||||
ServiceContext.MemberService.AssignRoles(new[] { member.Id }, new[] { "MyTestRole1", "MyTestRole2" });
|
||||
ServiceContext.MemberService.AssignRoles(new[] { member.Id, member2.Id }, new[] { "MyTestRole1", "MyTestRole2" });
|
||||
|
||||
var memberRoles = ServiceContext.MemberService.GetAllRoles("test");
|
||||
|
||||
Assert.AreEqual(2, memberRoles.Count());
|
||||
|
||||
var memberRoles2 = ServiceContext.MemberService.GetAllRoles("test2@test.com");
|
||||
Assert.AreEqual(2, memberRoles2.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -324,9 +329,12 @@ namespace Umbraco.Tests.Services
|
||||
ServiceContext.MemberTypeService.Save(memberType);
|
||||
IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test");
|
||||
ServiceContext.MemberService.Save(member);
|
||||
IMember member2 = MockedMember.CreateSimpleMember(memberType, "test", "test2@test.com", "pass", "test2@test.com");
|
||||
ServiceContext.MemberService.Save(member2);
|
||||
|
||||
Assert.IsTrue(ServiceContext.MemberService.Exists("test"));
|
||||
Assert.IsFalse(ServiceContext.MemberService.Exists("notFound"));
|
||||
Assert.IsTrue(ServiceContext.MemberService.Exists("test2@test.com"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -127,9 +127,10 @@ namespace Umbraco.Tests.Services
|
||||
var userType = MockedUserType.CreateUserType();
|
||||
ServiceContext.UserService.SaveUserType(userType);
|
||||
var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io", userType);
|
||||
|
||||
var user2 = ServiceContext.UserService.CreateUserWithIdentity("john2@umbraco.io", "john2@umbraco.io", userType);
|
||||
Assert.IsTrue(ServiceContext.UserService.Exists("JohnDoe"));
|
||||
Assert.IsFalse(ServiceContext.UserService.Exists("notFound"));
|
||||
Assert.IsTrue(ServiceContext.UserService.Exists("john2@umbraco.io"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -2675,9 +2675,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>6220</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>6230</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:6220</IISUrl>
|
||||
<IISUrl>http://localhost:6240</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -123,8 +123,8 @@ namespace UmbracoExamine.DataServices
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = _applicationContext.DatabaseContext.Database.Fetch<PropertyAliasDto>("select distinct alias from cmsPropertyType order by alias");
|
||||
return result.Select(r => r.Alias).ToList();
|
||||
var result = _applicationContext.DatabaseContext.Database.Fetch<string>("select distinct alias from cmsPropertyType order by alias");
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user