PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/DynamicLinqTest.cs

https://bitbucket.org/danipen/mono
C# | 337 lines | 228 code | 42 blank | 67 comment | 16 complexity | dccbdfe23f5c4a82e16197c60ed46abb MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. #region MIT license
  2. //
  3. // MIT license
  4. //
  5. // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. //
  25. #endregion
  26. using System;
  27. using System.Collections.Generic;
  28. using System.Linq;
  29. using System.Text;
  30. using NUnit.Framework;
  31. using System.Linq.Dynamic;
  32. using Test_NUnit;
  33. using System.Linq.Expressions;
  34. using System.Reflection;
  35. using nwind;
  36. // test ns
  37. #if MYSQL
  38. namespace Test_NUnit_MySql
  39. #elif ORACLE && ODP
  40. namespace Test_NUnit_OracleODP
  41. #elif ORACLE
  42. namespace Test_NUnit_Oracle
  43. #elif POSTGRES
  44. namespace Test_NUnit_PostgreSql
  45. #elif SQLITE
  46. namespace Test_NUnit_Sqlite
  47. #elif INGRES
  48. namespace Test_NUnit_Ingres
  49. #elif MSSQL && L2SQL
  50. namespace Test_NUnit_MsSql_Strict
  51. #elif MSSQL
  52. namespace Test_NUnit_MsSql
  53. #elif FIREBIRD
  54. namespace Test_NUnit_Firebird
  55. #endif
  56. {
  57. [TestFixture]
  58. public class DynamicLinqTest : TestBase
  59. {
  60. [Test]
  61. public void DL1_Products()
  62. {
  63. Northwind db = CreateDB();
  64. var q = db.Products.Where("SupplierID=1 And UnitsInStock>2")
  65. .OrderBy("ProductID");
  66. var list = q.ToList();
  67. Assert.IsTrue(list.Count > 0, "Expected results from dynamic query");
  68. }
  69. [Test]
  70. public void DL2_ProductCount()
  71. {
  72. Northwind db = CreateDB();
  73. int numProducts = db.Products.Where("SupplierID=1").Count();
  74. Assert.IsTrue(numProducts > 0, "Expected results from dynamic query");
  75. }
  76. //note:
  77. //user Sqlite reports problems with DynamicLinq Count() -
  78. //but neither DL2 nor DL3 tests seem to hit the problem.
  79. [Test]
  80. public void DL3_ProductCount()
  81. {
  82. Northwind db = CreateDB();
  83. int numProducts = db.Products.Count();
  84. Assert.IsTrue(numProducts > 0, "Expected results from dynamic query");
  85. }
  86. [Test]
  87. public void DL4_DynamicAssociationProperty()
  88. {
  89. Northwind db = CreateDB();
  90. var orders = db.GetTable<Order>();
  91. var res = orders.Select(@"new (OrderID,Customer.ContactName)");
  92. List<object> list = new List<object>();
  93. foreach (var u in res)
  94. list.Add(u);
  95. Assert.IsTrue(list.Count > 0);
  96. }
  97. #region NestedPropertiesDynamicSelect
  98. const string obsoleteError=@"Since beta2 in Linq2Sql to project a new entity (ie: select new Order(3)) is forbidden for coherence reasons, so this tests doesn't mimic the Linq2Sql behavior and it is obsolete and should be modified. If you apply such test cases to Linq2Sql you'll get Test_NUnit_MsSql_Strict.DynamicLinqTest.DL5_NestedObjectSelect:
  99. System.NotSupportedException : Explicit construction of entity type 'MsNorthwind.XX' in query is not allowed.\n\nMore Info in: http://linqinaction.net/blogs/roller/archive/2007/11/27/explicit-construction-of-entity-type-in-query-is-not-allowed.aspx";
  100. [Test(Description = "dynamic version of F16_NestedObjectSelect")]
  101. public void DL5_NestedObjectSelect()
  102. {
  103. Assert.Ignore(obsoleteError);
  104. Northwind db = CreateDB();
  105. var orders = db.GetTable<Order>();
  106. var res = orders.SelectNested(new string[] { "OrderID", "Customer.ContactName" });
  107. List<Order> list = res.ToList();
  108. Assert.IsTrue(list.Count > 0);
  109. }
  110. [Test]
  111. public void DL6_StaticVersionOfDynamicAssociatonWithExtensionMethodTest(bool bug_in_dynamic_linq)
  112. {
  113. Assert.Ignore(obsoleteError);
  114. //is this maybe a bug in DynamicLinq?
  115. //from DynamicLinq, we receive this query which has ContactName but misses ContactTitle:
  116. //MTable.CreateQuery: value(Table`1[Order]).Select(o => new Order() {OrderID = o.OrderID, Customer = new Customer() {ContactName = o.Customer.ContactName}})
  117. //Also - the non-dynamic version F17_NestedObjectSelect_Ver2 succeeds.
  118. Northwind db = CreateDB();
  119. var orders = db.GetTable<Order>().ToArray().AsQueryable();
  120. var query = from order in orders
  121. //where order.Customer != null
  122. select new Order
  123. {
  124. OrderID = order.OrderID,
  125. Customer = new Customer
  126. {
  127. ContactName = order.Customer.ContactName,
  128. ContactTitle = order.Customer.ContactTitle
  129. }
  130. };
  131. var list = query.ToList();
  132. Assert.IsTrue(list.Count > 0);
  133. }
  134. [Test]
  135. public void DL7_DynamicAssociatonUsingDoubleProjection(bool bug_in_dynamic_linq)
  136. {
  137. Assert.Ignore(obsoleteError);
  138. //this fails - but not in our code:
  139. //A first chance exception of type 'System.NullReferenceException' occurred in Unknown Module.
  140. //System.Transactions Critical: 0 : <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Critical"><TraceIdentifier>http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled</TraceIdentifier><Description>Unhandled exception</Description><AppDomain>Test_NUnit_Mysql.vshost.exe</AppDomain><Exception><ExceptionType>System.NullReferenceException, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>Object reference not set to an instance of an object.</Message><StackTrace> at lambda_method(ExecutionScope , Order )
  141. // at System.Linq.Enumerable.&amp;lt;SelectIterator&amp;gt;d__d`2.MoveNext()
  142. // at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
  143. // at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
  144. // at Test_NUnit_MySql.DynamicLinqTest.DL7_DynamicAssociatonUsingDoubleProjection() in E:\ggprj\dbLinq\dblinq2007\Tests\Test_NUnit\DynamicLinqTest.cs:line 150
  145. Northwind db = CreateDB();
  146. // Double projection works in Linq-SQL:
  147. var orders = db.GetTable<Order>().ToArray().AsQueryable();
  148. var query = orders.SelectNested(new string[] { "OrderID", "Customer.ContactName" });
  149. var list = query.ToList();
  150. Assert.IsTrue(list.Count > 0);
  151. }
  152. #endregion
  153. #region Predicates
  154. /// <summary>
  155. /// Reported by pwy.mail in issue http://code.google.com/p/dblinq2007/issues/detail?id=68
  156. /// </summary>
  157. [Test]
  158. public void DL8_CountTest2()
  159. {
  160. Northwind db = CreateDB();
  161. Expression<Func<Customer, bool>> predicate = c => c.City == "Paris";
  162. int count = db.Customers.Count(predicate);
  163. Assert.Greater(count, 0); // Some databases have more than 1 customer in Paris
  164. }
  165. /// <summary>
  166. /// Reported by pwy.mail in issue http://code.google.com/p/dblinq2007/issues/detail?id=69
  167. /// </summary>
  168. [Test]
  169. public void DL9_PredicateBuilderCount()
  170. {
  171. //2008.May.17: breaks because we are not handling an 'InvocationExpression' in ExpressionTreeParser.
  172. //possibily a tree rewrite is needed.
  173. Northwind db = CreateDB();
  174. var predicate = PredicateBuilder.True<Customer>();
  175. predicate = predicate.And(m => m.City == "Paris");
  176. int predicateCount = db.Customers.Count(predicate);
  177. int normalCount = db.Customers.Where(c => c.City == "Paris").Count();
  178. Assert.AreEqual(normalCount, predicateCount);
  179. }
  180. /// <summary>
  181. /// Reported by pwy.mail in issue http://code.google.com/p/dblinq2007/issues/detail?id=69
  182. /// </summary>
  183. [Test]
  184. public void DL10_PredicateBuilderWhere()
  185. {
  186. Northwind db = CreateDB();
  187. var predicate = PredicateBuilder.True<Customer>();
  188. predicate = predicate.And(m => m.City == "Paris");
  189. predicate = predicate.And(n => n.CompanyName == "Around the Horn");
  190. IList<Customer> list = db.Customers.AsQueryable().Where(predicate).ToList();
  191. }
  192. /// <summary>
  193. /// Reported by pwy.mail in issue http://code.google.com/p/dblinq2007/issues/detail?id=73
  194. /// </summary>
  195. [Test]
  196. public void DL11_ThenByDescending()
  197. {
  198. Northwind db = CreateDB();
  199. var q = db.Products.Where("SupplierID=1 And UnitsInStock>2")
  200. .OrderBy(" ProductName asc,ProductID desc");
  201. var list = q.ToList();
  202. Assert.IsTrue(list.Count > 0, "Expected results from dynamic query");
  203. }
  204. /// <summary>
  205. /// Build predicate expressions dynamically.
  206. /// </summary>
  207. static class PredicateBuilder
  208. {
  209. public static Expression<Func<T, bool>> True<T>() { return f => true; }
  210. public static Expression<Func<T, bool>> False<T>() { return f => false; }
  211. }
  212. // Test patch from:
  213. // http://groups.google.com/group/dblinq/browse_frm/thread/9fa41554044afeaa/4ef1605e020be9fc?lnk=raot#4ef1605e020be9fc
  214. [Test]
  215. public void DL12_Count_Via_Expression()
  216. {
  217. var db = CreateDB();
  218. IQueryable employees = db.Employees;
  219. var employeeCount = (int) employees.Provider.Execute(
  220. Expression.Call(typeof(Queryable), "Count",
  221. new Type[]{employees.ElementType},
  222. employees.Expression));
  223. Assert.AreEqual(9, employeeCount);
  224. }
  225. }
  226. #endregion
  227. #region ExtensionMethods
  228. /// <summary>
  229. /// Extension written by Marc Gravell.
  230. /// Traverses nested properties
  231. /// </summary>
  232. static class SelectUsingSingleProjection
  233. {
  234. internal static IQueryable<T> SelectNested<T>(this IQueryable<T> source, params string[] propertyNames)
  235. where T : new()
  236. {
  237. Type type = typeof(T);
  238. var sourceItem = Expression.Parameter(type, "t");
  239. Expression exp = CreateAndInit(type, sourceItem, propertyNames);
  240. return source.Select(Expression.Lambda<Func<T, T>>(exp, sourceItem));
  241. }
  242. static Expression CreateAndInit(Type type, Expression source, string[] propertyNames)
  243. {
  244. if (type == null) throw new ArgumentNullException("type");
  245. if (source == null) throw new ArgumentNullException("source");
  246. if (propertyNames == null) throw new ArgumentNullException("propertyNames");
  247. var newExpr = Expression.New(type.GetConstructor(Type.EmptyTypes));
  248. // take "Foo.A", "Bar", "Foo.B" to "Foo" ["A","B"], "Bar" []
  249. var groupedNames = from name in propertyNames
  250. let dotIndex = name.IndexOf('.')
  251. let primary = dotIndex < 0 ? name : name.Substring(0, dotIndex)
  252. let aux = dotIndex < 0 ? null : name.Substring(dotIndex + 1)
  253. group aux by primary into grouped
  254. select new
  255. {
  256. Primary = grouped.Key,
  257. Aux = grouped.Where(x => x != null).ToArray()
  258. };
  259. List<MemberBinding> bindings = new List<MemberBinding>();
  260. foreach (var grp in groupedNames)
  261. {
  262. PropertyInfo dest = type.GetProperty(grp.Primary);
  263. Expression value, readFrom = Expression.Property(source, grp.Primary);
  264. if (grp.Aux.Length == 0)
  265. {
  266. value = readFrom;
  267. }
  268. else
  269. {
  270. value = CreateAndInit(dest.PropertyType, readFrom, grp.Aux);
  271. }
  272. bindings.Add(Expression.Bind(dest, value));
  273. }
  274. return Expression.MemberInit(newExpr, bindings);
  275. }
  276. /// <summary>
  277. /// Extension method provided by pwy.mail in issue http://code.google.com/p/dblinq2007/issues/detail?id=69
  278. /// </summary>
  279. internal static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
  280. Expression<Func<T, bool>> expr2)
  281. {
  282. var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
  283. return Expression.Lambda<Func<T, bool>>
  284. (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
  285. }
  286. internal static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
  287. Expression<Func<T, bool>> expr2)
  288. {
  289. var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
  290. return Expression.Lambda<Func<T, bool>>
  291. (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
  292. }
  293. }
  294. #endregion
  295. }