Compare commits

...

41 Commits

Author SHA1 Message Date
Shannon b8ea50d644 Merge remote-tracking branch 'origin/6.2.4' into 7.1.8
Conflicts:
	build/NuSpecs/build/UmbracoCms.targets
	src/Umbraco.Core/Configuration/UmbracoVersion.cs
	src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
	src/Umbraco.Tests/Services/EntityServiceTests.cs
	src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
2014-10-08 17:30:45 +11:00
Shannon 1eab26c0f6 reverts IQuery 2014-10-08 17:26:55 +11:00
Shannon 0543c620eb bumps version 2014-10-08 17:25:06 +11:00
Shannon 646e5f173d Fixes descendant queries to ensure that the comma is suffixed to the path, otherwise strange things could happen when there are longer ids! 2014-10-08 17:23:14 +11:00
Shannon b5594517bd Fixes: U4-5583 Can no longer link to Media Items from RTE in 6.2.3 - Due to a cherry pick/merge issue since the newer 7.x EntityRepository deals with NVarchar and NText values whereas the 6.x one did not. Have backported the mapping poco classes to now also support NVarchar and NText for the EntityRepository. Have also fixed the basic query to ensure that there are no left joins before inner joins which can also cause problems. Fixed up the duplicate where clause. Adds more tests to entity service. 2014-10-08 17:13:28 +11:00
Sebastiaan Janssen 5501c9531b Bump version 2014-10-07 11:22:51 +02:00
Shannon 8824ab2b27 reverts JS from tree controller and updates the c# method to create the tree child node URLs to ensure the custom start node param is ignored, this is a bit cleaner. 2014-10-07 12:52:02 +11:00
Shannon b60e292d5f Fixes: U4-5578 MNTP with root node, recursive output 2014-10-07 11:51:11 +11:00
Shannon e1dcf6b061 reverts IQuery 2014-10-07 11:50:35 +11:00
Sebastiaan Janssen 246dfba8ac Bump version 2014-10-02 18:06:15 +02:00
Shannon c0c7d21001 Merge remote-tracking branch 'origin/6.2.3' into 7.1.7 2014-10-03 00:29:33 +10:00
Shannon 7d189a6fb8 Backports the @ symbol escaping fixes 2014-10-03 00:28:49 +10:00
Shannon e60dcfa144 Merge branch '7.1.7' of https://github.com/umbraco/Umbraco-CMS into 7.1.7 2014-10-03 00:26:25 +10:00
Shannon 3f8b779ae4 adds note 2014-10-03 00:23:38 +10:00
Shannon 72dc5fc477 Removes unused method 2014-10-03 00:23:28 +10:00
Shannon 737f2fb707 Fixes: U4-5566 Quite a few hard coded queries with incorrect escape syntax for mysql 2014-10-03 00:07:40 +10:00
Shannon a13ead0d10 unescapes @ symbols now that sql params are in place 2014-10-03 00:06:09 +10:00
Shannon 414dbe45a6 Fixes: U4-5460 User with start content set won't see the selected node. 2014-10-02 13:38:44 +02:00
Sebastiaan Janssen 340328aeba Fixes merge issue 2014-10-02 11:44:41 +02:00
Shannon f875dc15f7 Merge branch '6.2.3' into 7.1.7
Conflicts:
	build/Build.bat
	build/NuSpecs/UmbracoCms.Core.nuspec
	build/NuSpecs/UmbracoCms.nuspec
	build/NuSpecs/build/UmbracoCms.targets
	src/Umbraco.Core/Configuration/UmbracoVersion.cs
	src/Umbraco.Core/Models/DeepCloneHelper.cs
	src/Umbraco.Core/Persistence/Querying/BaseExpressionHelper.cs
	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
	src/Umbraco.Core/Services/MediaService.cs
	src/Umbraco.Core/Umbraco.Core.csproj
	src/Umbraco.Tests/Persistence/PetaPocoExtensionsTest.cs
	src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
	src/Umbraco.Web.UI/umbraco/dashboard/DesktopMediaUploader.ascx
	src/Umbraco.Web/Umbraco.Web.csproj
	src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/DesktopMediaUploader.ascx
2014-10-01 16:47:49 +10:00
Shannon 71242430da Fixes a query that would cause the new petapoco changes to have issues since it was asking for the wrong type 2014-10-01 16:37:42 +10:00
Shannon 1e04735826 updates iis port 2014-09-29 16:47:00 +02:00
Shannon b975a02bfa Updates version to 7.1.7 2014-09-29 16:46:53 +02:00
Shannon 88ec514630 fixes entity repo merges, this also means that the n+1 fixes for entity repository will be in this release. 2014-09-29 16:46:46 +02:00
Shannon 6f7ec84f18 Backports fixes to SQL parameterization and PetaPoco mem updates 2014-09-29 16:46:37 +02:00
Shannon 4ee4f296fc updates version 2014-09-29 17:31:24 +10:00
Shannon b9e4950e36 fixes up entity repo merges to support old db schema 2014-09-29 17:30:09 +10:00
Shannon ba52f9235e Backports fixes to SQL parameterization and PetaPoco mem updates 2014-09-29 17:11:58 +10:00
Sebastiaan Janssen 33ccf490ab Update nuspec to ask for a valid nuget pkg 2014-08-25 15:53:45 +02:00
Sebastiaan Janssen 101e116baf Bump version number 2014-08-25 15:14:21 +02:00
Shannon ebf24d69b5 Fixes: U4-5384 Custom ApiController routes not working after upgrade to 7.1.5 2014-08-25 14:33:50 +02:00
Shannon c94662e49c Fixes: U4-5388 YSOD after doctype rename & U4-5387 Deleting Properties in document types causes "Object reference not set to an instance of an object" 2014-08-25 14:33:03 +02:00
Sebastiaan Janssen 5d37eaf993 #U4-4673 Fixed Due in version: 7.1.6 2014-08-25 14:32:35 +02:00
Sebastiaan Janssen 1ded2c9baf #U4-5385 fixed Due in version: 7.1.6 2014-08-25 14:32:14 +02:00
Sebastiaan Janssen 2daacd8d57 #U4-5379 Fixed Due in version: 7.1.6
Some users have not set an email, don't strip out empty entries
2014-08-25 14:31:50 +02:00
Shannon 3f4fa8b8ed Fixes: U4-5380 Booting.aspx security issue 2014-08-25 14:31:04 +02:00
Sebastiaan Janssen 03ba8c9e14 Update to 6.2.2, removes airinstallbadge 2014-08-25 13:46:21 +02:00
Shannon 13b57c7638 adds some logging 2014-08-25 16:40:45 +10:00
Shannon a8b297903d Ensures we don't get any ysods when changing doc type properties and the content re-creation since it's running on an async thread (U4-5388 , U4-5387 ) 2014-08-25 16:16:42 +10:00
Shannon 89b5774106 Fixes: U4-5380 Booting.aspx security issue 2014-08-21 14:39:06 -06:00
Shannon 774f201514 Adds a simple cache mechanism to hold reflected property info when cloning - reduces perf to 10% of what it used to be 2014-08-20 20:09:05 -06:00
60 changed files with 2048 additions and 1600 deletions
+1 -1
View File
@@ -1 +1 @@
7.1.5
7.1.8
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.1.5");
private static readonly Version Version = new Version("7.1.8");
/// <summary>
/// Gets the current version of Umbraco.
+6
View File
@@ -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)
+10
View File
@@ -165,6 +165,16 @@ namespace Umbraco.Core.Media
ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L);
// Save the new image using the dimensions of the image
var predictableThumbnailName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", maxWidthHeight.ToString(CultureInfo.InvariantCulture));
using (var ms = new MemoryStream())
{
bp.Save(ms, codec, ep);
ms.Seek(0, 0);
fs.AddFile(predictableThumbnailName, ms);
}
// TODO: Remove this, this is ONLY here for backwards compatibility but it is essentially completely unusable see U4-5385
var newFileName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", string.Format("{0}x{1}", widthTh, heightTh));
using (var ms = new MemoryStream())
{
+264 -187
View File
@@ -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();
}
}
@@ -26,7 +26,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)
@@ -129,7 +129,7 @@ namespace Umbraco.Core.Persistence
public static Sql OrderByDescending(this Sql sql, params object[] columns)
{
return sql.Append(new Sql("ORDER BY " + String.Join(", ", (from x in columns select x.ToString() + " DESC").ToArray())));
return sql.Append(new Sql("ORDER BY " + String.Join(", ", (from x in columns select x + " DESC").ToArray())));
}
}
}
@@ -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;
//}
}
}
+27 -17
View File
@@ -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);
}
}
@@ -141,45 +141,59 @@ namespace Umbraco.Core.Persistence.Repositories
{
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 = GetFullSqlForEntityType(isContent, isMedia, objectTypeId, string.Empty);
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));
@@ -193,12 +207,11 @@ 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 entitySql = translator.Translate();
@@ -207,7 +220,16 @@ namespace Umbraco.Core.Persistence.Repositories
if (isMedia)
{
var mediaSql = GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)), wheres);
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
@@ -218,7 +240,8 @@ namespace Umbraco.Core.Persistence.Repositories
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>(entitySql.Append(GetGroupBy(isContent, false)));
var finalSql = entitySql.Append(GetGroupBy(isContent, false));
var dtos = _work.Database.Fetch<dynamic>(finalSql);
return dtos.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
}
}
@@ -246,16 +269,16 @@ namespace Umbraco.Core.Persistence.Repositories
return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)));
}
protected Sql GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectTypeId, string additionalWhereClause)
protected Sql GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectTypeId, Action<Sql> filter)
{
var entitySql = GetBaseWhere(GetBase, isContent, isMedia, additionalWhereClause, objectTypeId);
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)));
return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)), filter);
}
private Sql GetFullSqlForMedia(Sql entitySql, string additionWhereStatement = "")
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
@@ -268,7 +291,12 @@ namespace Umbraco.Core.Persistence.Repositories
.On<PropertyTypeDto, PropertyDataDto>(dto => dto.Id, dto => dto.PropertyTypeId)
.InnerJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(dto => dto.DataTypeId, dto => dto.DataTypeId)
.Where("umbracoNode.nodeObjectType = @nodeObjectType" + additionWhereStatement, new {nodeObjectType = Constants.ObjectTypes.Media});
.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
@@ -284,7 +312,7 @@ namespace Umbraco.Core.Persistence.Repositories
return wrappedSql;
}
protected virtual Sql GetBase(bool isContent, bool isMedia, string additionWhereStatement = "")
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter)
{
var columns = new List<object>
{
@@ -316,10 +344,8 @@ namespace Umbraco.Core.Persistence.Repositories
var entitySql = new Sql()
.Select(columns.ToArray())
.From("umbracoNode umbracoNode")
.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
.From("umbracoNode umbracoNode");
if (isContent || isMedia)
{
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id")
@@ -332,43 +358,50 @@ namespace Umbraco.Core.Persistence.Repositories
.On("umbracoNode.id = latest.nodeId");
}
entitySql.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
if (customFilter != null)
{
customFilter(entitySql);
}
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});
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;
@@ -497,7 +530,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
// Add this UmbracoProperty to the current additional data
Current.AdditionalData[p.PropertyAlias] = new UmbracoEntity.EntityProperty
{
{
PropertyEditorAlias = p.PropertyEditorAlias,
Value = p.NTextValue.IsNullOrWhiteSpace()
? p.NVarcharValue
@@ -516,7 +549,7 @@ namespace Umbraco.Core.Persistence.Repositories
var prev = Current;
// Setup the new current UmbracoEntity
Current = _factory.BuildEntityFromDynamic(a);
if (p != null && p.PropertyAlias.IsNullOrWhiteSpace() == false)
@@ -203,13 +203,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)
{
@@ -280,6 +280,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()
@@ -529,10 +529,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;
}
@@ -160,6 +160,8 @@ namespace Umbraco.Core.Persistence.Repositories
//TODO: Consider caching implications.
//TODO: We need to add lookups for parentId or path! (i.e. get content in tag group that are descendants of x)
public IEnumerable<TaggedEntity> GetTaggedEntitiesByTagGroup(TaggableObjectTypes objectType, string tagGroup)
{
@@ -285,7 +287,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (withGrouping)
{
sql = sql.Select("cmsTags.Id, cmsTags.Tag, cmsTags.[Group], Count(*) NodeCount");
sql = sql.Select("cmsTags.Id, cmsTags.Tag, cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + @", Count(*) NodeCount");
}
else
{
@@ -315,7 +317,7 @@ namespace Umbraco.Core.Persistence.Repositories
private Sql ApplyGroupByToTagsQuery(Sql sql)
{
return sql.GroupBy(new string[] { "cmsTags.Id", "cmsTags.Tag", "cmsTags.[Group]" });
return sql.GroupBy(new string[] { "cmsTags.Id", "cmsTags.Tag", "cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + @"" });
}
private IEnumerable<ITag> ExecuteTagsQuery(Sql sql)
@@ -438,7 +440,7 @@ namespace Umbraco.Core.Persistence.Repositories
" AND tagId IN ",
"(SELECT id FROM cmsTags INNER JOIN ",
tagSetSql,
" ON (TagSet.Tag = cmsTags.Tag and TagSet.[Group] = cmsTags.[Group]))");
" ON (TagSet.Tag = cmsTags.Tag and TagSet." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + @" = cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + @"))");
Database.Execute(deleteSql);
}
@@ -484,9 +486,13 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns></returns>
private static string GetTagSet(IEnumerable<ITag> tagsToInsert)
{
//TODO: Fix this query, since this is going to be basically a unique query each time, this will cause some mem usage in peta poco,
// and surely there's a nicer way!
//TODO: When we fix, be sure to remove the @ symbol escape
var array = tagsToInsert
.Select(tag =>
string.Format("select '{0}' as Tag, '{1}' as [Group]",
string.Format("select '{0}' as Tag, '{1}' as " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + @"",
PetaPocoExtensions.EscapeAtSymbols(tag.Text.Replace("'", "''")), tag.Group))
.ToArray();
return "(" + string.Join(" union ", array).Replace(" ", " ") + ") as TagSet";
@@ -261,10 +261,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;
}
@@ -230,6 +230,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("cmsPropertyData.*, cmsDataTypePreValues.id as preValId, cmsDataTypePreValues.value, cmsDataTypePreValues.sortorder, cmsDataTypePreValues.alias, cmsDataTypePreValues.datatypeNodeId")
@@ -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)
@@ -22,12 +22,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);
}
}
}
+6 -1
View File
@@ -520,6 +520,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);
}
@@ -532,7 +536,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;
+2 -1
View File
@@ -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;
+6 -1
View File
@@ -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;
+1
View File
@@ -394,6 +394,7 @@
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixTwoZero\ChangePasswordColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixTwoZero\UpdateToNewMemberPropertyAliases.cs" />
<Compile Include="Persistence\DbConnectionExtensions.cs" />
<Compile Include="Persistence\SqlSyntax\MicrosoftSqlSyntaxProviderBase.cs" />
<Compile Include="PropertyEditors\DefaultPropertyValueConverterAttribute.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSeven\UpdateRelatedLinksData.cs" />
<Compile Include="PropertyEditors\IValueEditor.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,201 @@
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;
ServiceContext.TagService.GetTagsForEntity(id1);
ServiceContext.TagService.GetAllContentTags();
ServiceContext.TagService.GetTagsForEntity(id2);
ServiceContext.TagService.GetTagsForEntity(id3);
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("test", DataTypeDatabaseType.Ntext)
{
Alias = "tags",
DataTypeDefinitionId = 1041
});
contentTypeService.Save(contentType);
var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1);
content1.SetTags("tags", new[] { "hello", "world", "some", "tags" }, true);
contentService.Publish(content1);
id2 = content1.Id;
var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1);
content2.SetTags("tags", new[] { "hello", "world", "some", "tags" }, true);
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);
}
}
@@ -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).ToArray();
Assert.That(entities.Any(), Is.True);
Assert.That(entities.Count(), Is.EqualTo(3));
Assert.That(entities.Count(), Is.EqualTo(5));
Assert.That(
entities.Any(
@@ -150,6 +174,8 @@ namespace Umbraco.Tests.Services
private static bool _isSetup = false;
private int folderId;
public override void CreateTestData()
{
if (_isSetup == false)
@@ -160,8 +186,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);
@@ -172,6 +199,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);
}
}
@@ -94,15 +94,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]
@@ -325,9 +330,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]
@@ -130,9 +130,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]
@@ -1,4 +1,7 @@
//used for the media picker dialog
//TODO: SD: Pretty sure we don't want this anymore and we should just be using the treepicker.html instead for all tree picking.
//used for the content picker dialog
angular.module("umbraco").controller("Umbraco.Dialogs.ContentPickerController",
function ($scope, eventsService, entityResource, searchService, $log) {
var dialogOptions = $scope.dialogOptions;
+2 -2
View File
@@ -2530,9 +2530,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7150</DevelopmentServerPort>
<DevelopmentServerPort>7180</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7150</IISUrl>
<IISUrl>http://localhost:7180</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -97,7 +97,6 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(x => x.Published, expression => expression.Ignore())
.ForMember(x => x.Updator, expression => expression.Ignore())
.ForMember(x => x.Alias, expression => expression.Ignore());
//FROM IMember TO ContentItemDto<IMember>
config.CreateMap<IMember, ContentItemDto<IMember>>()
.ForMember(
@@ -43,12 +43,8 @@ namespace Umbraco.Web.Mvc
/// <returns></returns>
public static string GetAuthHeaderTokenVal(ApplicationContext appContext)
{
int numberOfUsers;
var users = appContext.Services.UserService.GetAll(0, 25, out numberOfUsers);
var admin = users.FirstOrDefault(u => u.UserType.Alias == "admin" && u.RawPasswordValue != string.Empty && u.RawPasswordValue.InvariantEquals("default") == false);
var admin = appContext.Services.UserService.GetUserById(0);
if (admin == null)
return string.Empty;
var token = string.Format("{0}u____u{1}u____u{2}", admin.Email, admin.Username, admin.RawPasswordValue);
@@ -95,8 +91,8 @@ namespace Umbraco.Web.Mvc
//decrypt the string
var text = encrypted.DecryptWithMachineKey();
//split
var split = text.Split(new[] { "u____u" }, StringSplitOptions.RemoveEmptyEntries);
//split - some users have not set an email, don't strip out empty entries
var split = text.Split(new[] {"u____u"}, StringSplitOptions.None);
if (split.Length != 3) return false;
//compare
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
@@ -149,24 +150,28 @@ namespace Umbraco.Web.PropertyEditors
/// <returns></returns>
public override IDictionary<string, object> ConvertDbToEditor(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
{
var result = new Dictionary<string, object>();
var result = new List<PreValue>();
//the pre-values just take up one field with a semi-colon delimiter so we'll just parse
var dictionary = persistedPreVals.FormatAsDictionary();
if (dictionary.Any())
{
//there should only be one val
var delimited = dictionary.First().Value.Value.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
var delimited = dictionary.First().Value.Value.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
for (var index = 0; index < delimited.Length; index++)
{
result.Add(index.ToInvariantString(), delimited[index]);
result.Add(new PreValue(index, delimited[index]));
}
}
//the items list will be a dictionary of it's id -> value we need to use the id for persistence for backwards compatibility
return new Dictionary<string, object> { { "items", result } };
return new Dictionary<string, object> { { "items", result.ToDictionary(x => x.Id, x => PreValueAsDictionary(x)) } };
}
private IDictionary<string, object> PreValueAsDictionary(PreValue preValue)
{
return new Dictionary<string, object> { { "value", preValue.Value }, { "sortOrder", preValue.SortOrder } };
}
/// <summary>
/// Take the posted values and convert them to a semi-colon separated list so that its backwards compatible
/// </summary>
+1 -18
View File
@@ -64,24 +64,7 @@ namespace Umbraco.Web.Trees
{
get { return Security.CurrentUser.StartContentId; }
}
/// <summary>
/// Gets the tree nodes for the given id
/// </summary>
/// <param name="id"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
/// <remarks>
/// If the content item is a container node then we will not return anything
/// </remarks>
protected override TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings)
{
var nodes = new TreeNodeCollection();
var entities = GetChildEntities(id);
nodes.AddRange(entities.Select(entity => GetSingleTreeNode(entity, id, queryStrings)).Where(node => node != null));
return nodes;
}
/// <summary>
/// Creates a tree node for a content item based on an UmbracoEntity
/// </summary>
@@ -6,6 +6,7 @@ using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence;
@@ -69,7 +70,51 @@ namespace Umbraco.Web.Trees
/// </summary>
protected abstract int UserStartNode { get; }
protected abstract TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings);
/// <summary>
/// Gets the tree nodes for the given id
/// </summary>
/// <param name="id"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
protected virtual TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings)
{
var nodes = new TreeNodeCollection();
var altStartId = string.Empty;
if (queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
altStartId = queryStrings.GetValue<string>(TreeQueryStringParameters.StartNodeId);
//check if a request has been made to render from a specific start node
if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != Constants.System.Root.ToString(CultureInfo.InvariantCulture))
{
id = altStartId;
//we need to verify that the user has access to view this node, otherwise we'll render an empty tree collection
// TODO: in the future we could return a validation statement so we can have some UI to notify the user they don't have access
if (HasPathAccess(id, queryStrings) == false)
{
LogHelper.Warn<ContentTreeControllerBase>("The user " + Security.CurrentUser.Username + " does not have access to the tree node " + id);
return new TreeNodeCollection();
}
// So there's an alt id specified, it's not the root node and the user has access to it, great! But there's one thing we
// need to consider:
// If the tree is being rendered in a dialog view we want to render only the children of the specified id, but
// when the tree is being rendered normally in a section and the current user's start node is not -1, then
// we want to include their start node in the tree as well.
// Therefore, in the latter case, we want to change the id to -1 since we want to render the current user's root node
// and the GetChildEntities method will take care of rendering the correct root node.
// If it is in dialog mode, then we don't need to change anything and the children will just render as per normal.
if (IsDialog(queryStrings) == false && UserStartNode != Constants.System.Root)
{
id = Constants.System.Root.ToString(CultureInfo.InvariantCulture);
}
}
var entities = GetChildEntities(id);
nodes.AddRange(entities.Select(entity => GetSingleTreeNode(entity, id, queryStrings)).Where(node => node != null));
return nodes;
}
protected abstract MenuItemCollection PerformGetMenuForNode(string id, FormDataCollection queryStrings);
@@ -108,59 +153,44 @@ namespace Umbraco.Web.Trees
protected abstract bool HasPathAccess(string id, FormDataCollection queryStrings);
/// <summary>
/// This will automatically check if the recycle bin needs to be rendered (i.e. its the first level)
/// and will automatically append it to the result of GetChildNodes.
/// Ensures the recycle bin is appended when required (i.e. user has access to the root and it's not in dialog mode)
/// </summary>
/// <param name="id"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
/// <remarks>
/// This method is overwritten strictly to render the recycle bin, it should serve no other purpose
/// </remarks>
protected sealed override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
//check if we're rendering the root
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.Root.ToInvariantString() && UserStartNode == Constants.System.Root)
{
//when rendering the root, 3 things can happen:
//1. we return -1 children without modifications
//2. the user has a non -1 content root set and we return that
//3. the tree has a non -1 content root set and we return that - if the user has access to it.
var altStartId = string.Empty;
var hasUserRoot = UserStartNode != Constants.System.Root;
var hasTreeRoot = queryStrings.HasKey(TreeQueryStringParameters.StartNodeId);
if (queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
altStartId = queryStrings.GetValue<string>(TreeQueryStringParameters.StartNodeId);
//initial id
var idToLoad = id;
//user permission override root
if (hasUserRoot)
idToLoad = UserStartNode.ToString(CultureInfo.InvariantCulture);
//tree overrides root
if (hasTreeRoot)
//check if a request has been made to render from a specific start node
if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != Constants.System.Root.ToString(CultureInfo.InvariantCulture))
{
//but only if the user is allowed to access this node
var altId = queryStrings.GetValue<string>(TreeQueryStringParameters.StartNodeId);
//so if we dont have a user content root or the user has access
if (hasUserRoot == false || HasPathAccess(altId, queryStrings))
{
idToLoad = altId;
}
id = altStartId;
}
//load whatever root nodes we concluded was the user/tree root
var nodes = GetTreeNodesInternal(idToLoad, queryStrings);
//only render the recycle bin if we are not in dialog and the start id is still the root
if (IsDialog(queryStrings) == false && idToLoad == Constants.System.Root.ToInvariantString())
var nodes = GetTreeNodesInternal(id, queryStrings);
//only render the recycle bin if we are not in dialog and the start id id still the root
if (IsDialog(queryStrings) == false && id == Constants.System.Root.ToInvariantString())
{
nodes.Add(CreateTreeNode(
RecycleBinId.ToInvariantString(),
idToLoad,
id,
queryStrings,
ui.GetText("general", "recycleBin"),
"icon-trash",
RecycleBinSmells,
queryStrings.GetValue<string>("application") + TreeAlias.EnsureStartsWith('/') + "/recyclebin"));
}
return nodes;
@@ -58,14 +58,6 @@ namespace Umbraco.Web.Trees
get { return Security.CurrentUser.StartMediaId; }
}
protected override TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings)
{
var nodes = new TreeNodeCollection();
var entities = GetChildEntities(id);
nodes.AddRange(entities.Select(entity => GetSingleTreeNode(entity, id, queryStrings)).Where(node => node != null));
return nodes;
}
/// <summary>
/// Creates a tree node for a content item based on an UmbracoEntity
/// </summary>
+4 -1
View File
@@ -13,7 +13,10 @@ namespace Umbraco.Web.Trees
.EnsureEndsWith('?');
//now we need to append the query strings
actionUrl += "id=" + nodeId.EnsureEndsWith('&') + queryStrings.ToQueryString("id");
actionUrl += "id=" + nodeId.EnsureEndsWith('&') + queryStrings.ToQueryString("id",
//Always ignore the custom start node id when generating URLs for tree nodes since this is a custom once-only parameter
// that should only ever be used when requesting a tree to render (root), not a tree node
TreeQueryStringParameters.StartNodeId);
return actionUrl;
}
+3 -1
View File
@@ -1853,7 +1853,9 @@
<Content Include="umbraco.presentation\umbraco\controls\Tree\CustomTreeService.asmx" />
<Content Include="umbraco.presentation\umbraco\developer\RelationTypes\EditRelationType.aspx" />
<Content Include="umbraco.presentation\umbraco\developer\RelationTypes\NewRelationType.aspx" />
<Content Include="umbraco.presentation\umbraco\developer\RelationTypes\RelationTypesWebService.asmx" />
<Content Include="umbraco.presentation\umbraco\developer\RelationTypes\RelationTypesWebService.asmx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\dashboard\FeedProxy.aspx" />
<Content Include="umbraco.presentation\umbraco\dialogs\AssignDomain2.aspx">
<SubType>ASPXCodeBehind</SubType>
+1
View File
@@ -51,6 +51,7 @@ namespace Umbraco.Web
{
// the keepalive service will use that url
ApplicationContext.Current.OriginalRequestUrl = string.Format("{0}:{1}{2}", httpContext.Request.ServerVariables["SERVER_NAME"], httpContext.Request.ServerVariables["SERVER_PORT"], IOHelper.ResolveUrl(SystemDirectories.Umbraco));
LogHelper.Info<UmbracoModule>("Setting OriginalRequestUrl: " + ApplicationContext.Current.OriginalRequestUrl);
}
// do not process if client-side request
@@ -25,7 +25,10 @@ namespace Umbraco.Web.WebApi
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
var routeData = request.GetRouteData();
if (routeData == null || routeData.Route == null || routeData.Route.DataTokens["Namespaces"] == null)
if (routeData == null
|| routeData.Route == null
|| routeData.Route.DataTokens == null
|| routeData.Route.DataTokens["Namespaces"] == null)
return base.SelectController(request);
// Look up controller in route data
+21 -17
View File
@@ -21,6 +21,7 @@ using umbraco.cms.businesslogic.cache;
using umbraco.cms.businesslogic.web;
using umbraco.DataLayer;
using umbraco.presentation.nodeFactory;
using Umbraco.Web;
using Action = umbraco.BusinessLogic.Actions.Action;
using Node = umbraco.NodeFactory.Node;
using Umbraco.Core;
@@ -97,13 +98,13 @@ namespace umbraco
{
get
{
if (HttpContext.Current == null)
if (UmbracoContext.Current == null || UmbracoContext.Current.HttpContext == null)
return XmlContentInternal;
var content = HttpContext.Current.Items[XmlContextContentItemKey] as XmlDocument;
var content = UmbracoContext.Current.HttpContext.Items[XmlContextContentItemKey] as XmlDocument;
if (content == null)
{
content = XmlContentInternal;
HttpContext.Current.Items[XmlContextContentItemKey] = content;
UmbracoContext.Current.HttpContext.Items[XmlContextContentItemKey] = content;
}
return content;
}
@@ -828,24 +829,27 @@ namespace umbraco
/// </summary>
internal void RemoveXmlFilePersistenceQueue()
{
HttpContext.Current.Application.Lock();
HttpContext.Current.Application[PersistenceFlagContextKey] = null;
HttpContext.Current.Application.UnLock();
if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null)
{
UmbracoContext.Current.HttpContext.Application.Lock();
UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey] = null;
UmbracoContext.Current.HttpContext.Application.UnLock();
}
}
internal bool IsXmlQueuedForPersistenceToFile
{
get
{
if (HttpContext.Current != null)
if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null)
{
bool val = HttpContext.Current.Application[PersistenceFlagContextKey] != null;
bool val = UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey] != null;
if (val)
{
DateTime persistenceTime = DateTime.MinValue;
try
{
persistenceTime = (DateTime)HttpContext.Current.Application[PersistenceFlagContextKey];
persistenceTime = (DateTime)UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey];
if (persistenceTime > GetCacheFileUpdateTime())
{
return true;
@@ -894,8 +898,8 @@ namespace umbraco
private void ClearContextCache()
{
// If running in a context very important to reset context cache orelse new nodes are missing
if (HttpContext.Current != null && HttpContext.Current.Items.Contains(XmlContextContentItemKey))
HttpContext.Current.Items.Remove(XmlContextContentItemKey);
if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null && UmbracoContext.Current.HttpContext.Items.Contains(XmlContextContentItemKey))
UmbracoContext.Current.HttpContext.Items.Remove(XmlContextContentItemKey);
}
/// <summary>
@@ -1193,20 +1197,20 @@ order by umbracoNode.level, umbracoNode.sortOrder";
{
//if this is called outside a web request we cannot queue it it will run in the current thread.
if (HttpContext.Current != null)
if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null)
{
HttpContext.Current.Application.Lock();
UmbracoContext.Current.HttpContext.Application.Lock();
try
{
if (HttpContext.Current.Application[PersistenceFlagContextKey] != null)
if (UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey] != null)
{
HttpContext.Current.Application.Add(PersistenceFlagContextKey, null);
UmbracoContext.Current.HttpContext.Application.Add(PersistenceFlagContextKey, null);
}
HttpContext.Current.Application[PersistenceFlagContextKey] = DateTime.UtcNow;
UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey] = DateTime.UtcNow;
}
finally
{
HttpContext.Current.Application.UnLock();
UmbracoContext.Current.HttpContext.Application.UnLock();
}
}
else
@@ -5,6 +5,7 @@ using System.Web;
using System.Web.Script.Serialization;
using System.Web.Services;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
using umbraco.DataLayer;
using umbraco.BusinessLogic;
using umbraco.presentation.webservices;
@@ -45,7 +46,7 @@ namespace umbraco.presentation.umbraco.webservices
if (!String.IsNullOrEmpty(group) && !String.IsNullOrEmpty(id))
{
sql = @"SELECT TOP (20) tag FROM cmsTags WHERE tag LIKE @prefix AND cmsTags.id not in
(SELECT tagID FROM cmsTagRelationShip WHERE NodeId = @nodeId) AND cmstags.[group] = @group;";
(SELECT tagID FROM cmsTagRelationShip WHERE NodeId = @nodeId) AND cmstags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + " = @group;";
rr = SqlHelper.ExecuteReader(sql,
SqlHelper.CreateParameter("@count", count),
@@ -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)
{
+20 -19
View File
@@ -5,6 +5,7 @@ using System.Text;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
using umbraco.DataLayer;
using umbraco.BusinessLogic;
using umbraco.interfaces;
@@ -157,7 +158,7 @@ namespace umbraco.cms.businesslogic.Tags
sql += " (";
sql += " select NewTags.Id from ";
sql += " " + TagSet + " ";
sql += " inner join cmsTags as NewTags on (TagSet.Tag = NewTags.Tag and TagSet.[Group] = TagSet.[Group]) ";
sql += " inner join cmsTags as NewTags on (TagSet.Tag = NewTags.Tag and TagSet." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + " = TagSet." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + ") ";
sql += " ) as NewTagsSet ";
sql += " on (cmsTagRelationship.TagId = NewTagsSet.Id and cmsTagRelationship.NodeId = " + string.Format("{0}", nodeId) + ") ";
sql += " inner join cmsTags as OldTags on (cmsTagRelationship.tagId = OldTags.Id) ";
@@ -166,10 +167,10 @@ namespace umbraco.cms.businesslogic.Tags
SqlHelper.ExecuteNonQuery(sql);
//adds any tags found in csv that aren't in cmsTag for that group
sql = "insert into cmsTags (Tag,[Group]) ";
sql += " select TagSet.[Tag], TagSet.[Group] from ";
sql = "insert into cmsTags (Tag," + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + @") ";
sql += " select TagSet." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Tag") + @", TagSet." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + @" from ";
sql += " " + TagSet + " ";
sql += " left outer join cmsTags on (TagSet.Tag = cmsTags.Tag and TagSet.[Group] = cmsTags.[Group])";
sql += " left outer join cmsTags on (TagSet.Tag = cmsTags.Tag and TagSet." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + " = cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + ")";
sql += " where cmsTags.Id is null ";
SqlHelper.ExecuteNonQuery(sql);
@@ -179,7 +180,7 @@ namespace umbraco.cms.businesslogic.Tags
sql += "( ";
sql += "select NewTags.Id from ";
sql += " " + TagSet + " ";
sql += "inner join cmsTags as NewTags on (TagSet.Tag = NewTags.Tag and TagSet.[Group] = TagSet.[Group]) ";
sql += "inner join cmsTags as NewTags on (TagSet.Tag = NewTags.Tag and TagSet." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + " = TagSet." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group") + ") ";
sql += ") as NewTagsSet ";
sql += "left outer join cmsTagRelationship ";
sql += "on (cmsTagRelationship.TagId = NewTagsSet.Id and cmsTagRelationship.NodeId = " + string.Format("{0}", nodeId) + ") ";
@@ -217,7 +218,7 @@ namespace umbraco.cms.businesslogic.Tags
/// <param name="group"></param>
public static void RemoveTagsFromNode(int nodeId, string group)
{
SqlHelper.ExecuteNonQuery("DELETE FROM cmsTagRelationship WHERE (nodeId = @nodeId) AND EXISTS (SELECT id FROM cmsTags WHERE (cmsTagRelationship.tagId = id) AND ([group] = @group));",
SqlHelper.ExecuteNonQuery("DELETE FROM cmsTagRelationship WHERE (nodeId = @nodeId) AND EXISTS (SELECT id FROM cmsTags WHERE (cmsTagRelationship.tagId = id) AND (" + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + " = @group));",
SqlHelper.CreateParameter("@nodeId", nodeId),
SqlHelper.CreateParameter("@group", group));
}
@@ -241,7 +242,7 @@ namespace umbraco.cms.businesslogic.Tags
public static int AddTag(string tag, string group)
{
SqlHelper.ExecuteNonQuery("INSERT INTO cmsTags(tag,[group]) VALUES (@tag,@group)",
SqlHelper.ExecuteNonQuery("INSERT INTO cmsTags(tag," + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + ") VALUES (@tag,@group)",
SqlHelper.CreateParameter("@tag", tag.Trim()),
SqlHelper.CreateParameter("@group", group));
return GetTagId(tag, group);
@@ -250,7 +251,7 @@ namespace umbraco.cms.businesslogic.Tags
public static int GetTagId(string tag, string group)
{
int retval = 0;
string sql = "SELECT id FROM cmsTags where tag=@tag AND [group]=@group;";
string sql = "SELECT id FROM cmsTags where tag=@tag AND " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + "=@group;";
object result = SqlHelper.ExecuteScalar<object>(sql,
SqlHelper.CreateParameter("@tag", tag),
SqlHelper.CreateParameter("@group", group));
@@ -263,10 +264,10 @@ namespace umbraco.cms.businesslogic.Tags
public static IEnumerable<Tag> GetTags(int nodeId, string group)
{
var sql = @"SELECT cmsTags.id, cmsTags.tag, cmsTags.[group], count(cmsTagRelationShip.tagid) AS nodeCount FROM cmsTags
var sql = @"SELECT cmsTags.id, cmsTags.tag, cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + @", count(cmsTagRelationShip.tagid) AS nodeCount FROM cmsTags
INNER JOIN cmsTagRelationship ON cmsTagRelationShip.tagId = cmsTags.id
WHERE cmsTags.[group] = @group AND cmsTagRelationship.nodeid = @nodeid
GROUP BY cmsTags.id, cmsTags.tag, cmsTags.[group]";
WHERE cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + @" = @group AND cmsTagRelationship.nodeid = @nodeid
GROUP BY cmsTags.id, cmsTags.tag, cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group");
return ConvertSqlToTags(sql,
SqlHelper.CreateParameter("@group", group),
@@ -282,10 +283,10 @@ namespace umbraco.cms.businesslogic.Tags
public static IEnumerable<Tag> GetTags(int nodeId)
{
string sql = @"SELECT cmsTags.id, cmsTags.tag, cmsTags.[group], count(cmsTagRelationShip.tagid) AS nodeCount FROM cmsTags
string sql = @"SELECT cmsTags.id, cmsTags.tag, cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + @", count(cmsTagRelationShip.tagid) AS nodeCount FROM cmsTags
INNER JOIN cmsTagRelationShip ON cmsTagRelationShip.tagid = cmsTags.id
WHERE cmsTagRelationShip.nodeid = @nodeId
GROUP BY cmsTags.id, cmsTags.tag, cmsTags.[group]";
GROUP BY cmsTags.id, cmsTags.tag, cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group");
return ConvertSqlToTags(sql, SqlHelper.CreateParameter("@nodeId", nodeId));
@@ -299,10 +300,10 @@ namespace umbraco.cms.businesslogic.Tags
public static IEnumerable<Tag> GetTags(string group)
{
string sql = @"SELECT cmsTags.id, cmsTags.tag, cmsTags.[group], count(cmsTagRelationShip.tagid) AS nodeCount FROM cmsTags
string sql = @"SELECT cmsTags.id, cmsTags.tag, cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + @", count(cmsTagRelationShip.tagid) AS nodeCount FROM cmsTags
INNER JOIN cmsTagRelationShip ON cmsTagRelationShip.tagid = cmsTags.id
WHERE cmsTags.[group] = @group
GROUP BY cmsTags.id, cmsTags.tag, cmsTags.[group]";
WHERE cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + @" = @group
GROUP BY cmsTags.id, cmsTags.tag, cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group");
return ConvertSqlToTags(sql, SqlHelper.CreateParameter("@group", group));
@@ -316,9 +317,9 @@ namespace umbraco.cms.businesslogic.Tags
public static IEnumerable<Tag> GetTags()
{
string sql = @"SELECT cmsTags.id, cmsTags.tag, cmsTags.[group], count(cmsTagRelationShip.tagid) AS nodeCount FROM cmsTags
string sql = @"SELECT cmsTags.id, cmsTags.tag, cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group") + @", count(cmsTagRelationShip.tagid) AS nodeCount FROM cmsTags
LEFT JOIN cmsTagRelationShip ON cmsTagRelationShip.tagid = cmsTags.id
GROUP BY cmsTags.id, cmsTags.tag, cmsTags.[group]";
GROUP BY cmsTags.id, cmsTags.tag, cmsTags." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("group");
return ConvertSqlToTags(sql);
@@ -366,7 +367,7 @@ namespace umbraco.cms.businesslogic.Tags
private static string GetSqlSet(string commaSeparatedArray, string group)
{
// create array
var array = commaSeparatedArray.Trim().Split(',').ToList().ConvertAll(tag => string.Format("select '{0}' as Tag, '{1}' as [Group]", tag.Replace("'", ""), group)).ToArray();
var array = commaSeparatedArray.Trim().Split(',').ToList().ConvertAll(tag => string.Format("select '{0}' as Tag, '{1}' as " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Group"), tag.Replace("'", ""), group)).ToArray();
return "(" + string.Join(" union ", array).Replace(" ", " ") + ") as TagSet";
}
private static string GetSqlStringArray(string commaSeparatedArray)
+14 -1
View File
@@ -50,7 +50,13 @@ namespace umbraco.cms.helpers
if (Uri.TryCreate(callerUrl, UriKind.RelativeOrAbsolute, out localUri))
{
// check for local urls
if (!requestUri.IsAbsoluteUri || requestUri.Host == localUri.Host)
//Cannot start with // since that is not a local url
if (!requestUri.OriginalString.StartsWith("//")
//cannot be non-absolute and also contain the char : since that will indicate a protocol
&& (!requestUri.IsAbsoluteUri && !requestUri.OriginalString.Contains(":"))
//needs to be non-absolute or the hosts must match the current request
&& (!requestUri.IsAbsoluteUri || requestUri.Host == localUri.Host))
{
return true;
}
@@ -61,6 +67,13 @@ namespace umbraco.cms.helpers
throw new ArgumentException("CallerUrl is in a wrong format that couldn't be parsed as a valid URI. If you don't want to evaluate for local urls, but just proxy urls then leave callerUrl empty", "callerUrl");
}
}
//we cannot continue if the url is not absolute
if (!requestUri.IsAbsoluteUri)
{
return false;
}
// check for valid proxy urls
var feedProxyXml = XmlHelper.OpenAsXmlDocument(IOHelper.MapPath(SystemFiles.FeedProxyConfig));
if (feedProxyXml != null &&
+3 -1
View File
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
VisualStudioVersion = 12.0.30723.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Web.UI", "Umbraco.Web.UI\Umbraco.Web.UI.csproj", "{4C4C194C-B5E4-4991-8F87-4373E24CC19F}"
EndProject
@@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2849E9D4
..\build\RevertToCleanInstall.bat = ..\build\RevertToCleanInstall.bat
..\build\RevertToEmptyInstall.bat = ..\build\RevertToEmptyInstall.bat
umbraco.presentation.targets = umbraco.presentation.targets
..\build\UmbracoVersion.txt = ..\build\UmbracoVersion.txt
..\build\webpihash.txt = ..\build\webpihash.txt
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{FD962632-184C-4005-A5F3-E705D92FC645}"