Merge pull request #3913 from omwok/master
[mono.git] / mcs / class / System.Data.Linq / src / DbLinq / Test / Providers / WriteTest.cs
1 #region MIT license\r
2 // \r
3 // MIT license\r
4 //\r
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne\r
6 // \r
7 // Permission is hereby granted, free of charge, to any person obtaining a copy\r
8 // of this software and associated documentation files (the "Software"), to deal\r
9 // in the Software without restriction, including without limitation the rights\r
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
11 // copies of the Software, and to permit persons to whom the Software is\r
12 // furnished to do so, subject to the following conditions:\r
13 // \r
14 // The above copyright notice and this permission notice shall be included in\r
15 // all copies or substantial portions of the Software.\r
16 // \r
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
23 // THE SOFTWARE.\r
24 // \r
25 #endregion\r
26 \r
27 using System;\r
28 using System.Collections.Generic;\r
29 using System.Text;\r
30 using System.Linq;\r
31 using System.Linq.Expressions;\r
32 \r
33 using NUnit.Framework;\r
34 using Test_NUnit;\r
35 using System.ComponentModel;\r
36 using System.Data.Linq.Mapping;\r
37 \r
38 using nwind;\r
39 \r
40 #if MONO_STRICT\r
41 using System.Data.Linq;\r
42 #if MONO\r
43 using DbLinq.Util;\r
44 #endif\r
45 #else\r
46 using DbLinq.Data.Linq;\r
47 using DbLinq.Util;\r
48 #endif\r
49 \r
50 #if ORACLE\r
51 using Id = System.Decimal;\r
52 #else\r
53 using Id = System.Int32;\r
54 #endif\r
55 \r
56 // test ns \r
57 #if MYSQL\r
58     namespace Test_NUnit_MySql\r
59 #elif ORACLE && ODP\r
60     namespace Test_NUnit_OracleODP\r
61 #elif ORACLE\r
62     namespace Test_NUnit_Oracle\r
63 #elif POSTGRES\r
64     namespace Test_NUnit_PostgreSql\r
65 #elif SQLITE\r
66     namespace Test_NUnit_Sqlite\r
67 #elif INGRES\r
68     namespace Test_NUnit_Ingres\r
69 #elif MSSQL && L2SQL\r
70     namespace Test_NUnit_MsSql_Strict\r
71 #elif MSSQL\r
72     namespace Test_NUnit_MsSql\r
73 #elif FIREBIRD\r
74     namespace Test_NUnit_Firebird\r
75 #endif\r
76 {\r
77     [TestFixture]\r
78     public class WriteTest : TestBase\r
79     {\r
80         [SetUp]\r
81         public void TestSetup()\r
82         {\r
83             base.BaseSetUp();\r
84 \r
85             Profiler.At("START: WriteTest.TestSetup()");\r
86 \r
87             Northwind db = CreateDB();\r
88             // "[Products]" gets converted to "Products".\r
89             //This is a DbLinq-defined escape sequence, by Pascal.\r
90             //db.ExecuteCommand("DELETE FROM [Products] WHERE [ProductName] like 'temp%'");\r
91 \r
92             var deleteProducts = db.Products.Where(p => p.ProductName.StartsWith("temp")).ToList();\r
93             db.Products.DeleteAllOnSubmit(deleteProducts);\r
94 \r
95             var deleteCategories = db.Categories.Where(c => c.CategoryName.StartsWith("temp")).ToList();\r
96             db.Categories.DeleteAllOnSubmit(deleteCategories);\r
97 \r
98             db.SubmitChanges();\r
99 \r
100             Profiler.At("END: WriteTest.TestSetup()");\r
101         }\r
102 \r
103         #region Tests 'E' test live object cache\r
104         [Test]\r
105         public void E1_LiveObjectsAreUnique()\r
106         {\r
107             //grab an object twice, make sure we get the same object each time\r
108             Northwind db = CreateDB();\r
109             var q = from p in db.Products select p;\r
110             Product product1 = q.First();\r
111             Product product2 = q.First();\r
112             Assert.AreSame(product1, product2); \r
113 \r
114             string uniqueStr = "Unique" + Environment.TickCount;\r
115             product1.QuantityPerUnit = uniqueStr;\r
116             bool isSameObject1 = product2.QuantityPerUnit == uniqueStr;\r
117             Assert.IsTrue(isSameObject1, "Expected product1 and product2 to be the same live object, but their fields are different");\r
118             object oProduct1 = product1;\r
119             object oProduct2 = product2;\r
120             bool isSameObject2 = oProduct1 == oProduct2;\r
121             Assert.IsTrue(isSameObject2, "Expected product1 and product2 to be the same live object, but their fields are different");\r
122         }\r
123 \r
124         [Test]\r
125         public void E2_LiveObjectsAreUnique_Scalar()\r
126         {\r
127             //grab an object twice, make sure we get the same object each time\r
128             Northwind db = CreateDB();\r
129             var q = from p in db.Products select p;\r
130             Product product1 = q.First(p => p.ProductName == "Chai");\r
131             Product product2 = q.Single(p => p.ProductName == "Chai");\r
132             bool isSame = object.ReferenceEquals(product1, product2);\r
133             Assert.IsTrue(isSame, "Expected product2 and product2 to be the same live object");\r
134         }\r
135 \r
136 #if MYSQL && USE_ALLTYPES\r
137         [Test]\r
138         public void E3_UpdateEnum()\r
139         {\r
140             Northwind db = CreateDB();\r
141 \r
142             var q = from at in db.Alltypes where at.int_ == 1 select at;\r
143 \r
144             Alltype row = q.First();\r
145             DbLinq_EnumTest newValue = row.DbLinq_EnumTest == DbLinq_EnumTest.BB\r
146                 ? DbLinq_EnumTest.CC\r
147                 : DbLinq_EnumTest.BB;\r
148 \r
149             row.DbLinq_EnumTest = newValue;\r
150 \r
151             db.SubmitChanges();\r
152         }\r
153 #endif\r
154         #endregion\r
155 \r
156 \r
157         #region Tests 'G' do insertion\r
158         private int insertProduct_priv()\r
159         {\r
160             Northwind db = CreateDB();\r
161 \r
162             Product newProd = new Product();\r
163             newProd.CategoryID = db.Categories.First().CategoryID;\r
164             newProd.ProductName = "Temp." + Environment.TickCount;\r
165             newProd.QuantityPerUnit = "33 1/2";\r
166             db.Products.InsertOnSubmit(newProd);\r
167             db.SubmitChanges();\r
168             AssertHelper.Greater(newProd.ProductID, 0, "After insertion, ProductID should be non-zero");\r
169             //Assert.IsFalse(newProd.IsModified, "After insertion, Product.IsModified should be false");\r
170             return (int)newProd.ProductID; //this test cab be used from delete tests\r
171         }\r
172 \r
173         [Test]\r
174         public void G1_InsertProduct()\r
175         {\r
176             insertProduct_priv();\r
177         }\r
178 \r
179         [Test]\r
180         public void G2_DeleteTest()\r
181         {\r
182             int insertedID = insertProduct_priv();\r
183             AssertHelper.Greater(insertedID, 0, "DeleteTest cannot operate if row was not inserted");\r
184 \r
185             Northwind db = CreateDB();\r
186 \r
187             var q = from p in db.Products where p.ProductID == insertedID select p;\r
188             List<Product> insertedProducts = q.ToList();\r
189             foreach (Product insertedProd in insertedProducts)\r
190             {\r
191                 db.Products.DeleteOnSubmit(insertedProd);\r
192             }\r
193             db.SubmitChanges();\r
194 \r
195             int numLeft = (from p in db.Products where p.ProductID == insertedID select p).Count();\r
196             Assert.AreEqual(numLeft, 0, "After deletion, expected count of Products with ID=" + insertedID + " to be zero, instead got " + numLeft);\r
197         }\r
198 \r
199         [Test]\r
200         public void G3_DeleteTest()\r
201         {\r
202             int insertedID = insertProduct_priv();\r
203             AssertHelper.Greater(insertedID, 0, "DeleteTest cannot operate if row was not inserted");\r
204 \r
205             Northwind db = CreateDB();\r
206 \r
207             var q = from p in db.Products where p.ProductID == insertedID select p;\r
208             List<Product> insertedProducts = q.ToList();\r
209             foreach (Product insertedProd in insertedProducts)\r
210             {\r
211                 db.Products.DeleteOnSubmit(insertedProd);\r
212             }\r
213             db.SubmitChanges();\r
214 \r
215             int numLeft = (from p in db.Products where p.ProductID == insertedID select p).Count();\r
216             Assert.AreEqual(numLeft, 0, "After deletion, expected count of Products with ID=" + insertedID + " to be zero, instead got " + numLeft);\r
217         }\r
218 \r
219         [Test]\r
220         public void G4_DuplicateSubmitTest()\r
221         {\r
222             Northwind db = CreateDB();\r
223             int productCount1 = db.Products.Count();\r
224 #if INGRES && !MONO_STRICT\r
225             Product p_temp = new Product { ProductName = "temp_g4", Discontinued = "N" };\r
226 #else\r
227             Product p_temp = new Product { ProductName = "temp_g4", Discontinued = false };\r
228 #endif\r
229             db.Products.InsertOnSubmit(p_temp);\r
230             db.SubmitChanges();\r
231             db.SubmitChanges();\r
232             int productCount2 = db.Products.Count();\r
233             Assert.IsTrue(productCount2 == productCount1 + 1, "Expected product count to grow by one");\r
234         }\r
235 \r
236         /// <summary>\r
237         /// there is a bug in v0.14 where fields cannot be updated to be null.\r
238         /// </summary>\r
239         [Test]\r
240         public void G5_SetFieldToNull()\r
241         {\r
242             string productName = "temp_G5_" + Environment.TickCount;\r
243             Northwind db = CreateDB();\r
244 #if ORACLE\r
245             //todo fix Oracle\r
246             Product p1 = new Product { ProductName = productName, Discontinued = false, UnitPrice = 11 };\r
247 #elif INGRES && !MONO_STRICT\r
248             Product p1 = new Product { ProductName = productName, Discontinued = "N", UnitPrice = 11m };\r
249 #else\r
250             Product p1 = new Product { ProductName = productName, Discontinued = false, UnitPrice = 11m };\r
251 #endif\r
252             db.Products.InsertOnSubmit(p1);\r
253             db.SubmitChanges();\r
254 \r
255             p1.UnitPrice = null;\r
256             db.SubmitChanges();\r
257 \r
258             Northwind db3 = CreateDB();\r
259             Product p3 = db3.Products.Single(p => p.ProductName == productName);\r
260             Assert.IsNull(p3.UnitPrice);\r
261         }\r
262 \r
263         /// <summary>\r
264         /// there is a bug in v0.14 where table Customers cannot be updated,\r
265         /// because quotes where missing around the primaryKey in the UPDATE statement.\r
266         /// </summary>\r
267         [Test]\r
268         public void G6_UpdateTableWithStringPK()\r
269         {\r
270             Northwind db = CreateDB();\r
271             var customer = new Customer\r
272             {\r
273                 CompanyName = "Test Company",\r
274                 ContactName = "Test Customer",\r
275                 CustomerID  = "BT___",\r
276             };\r
277             db.Customers.InsertOnSubmit(customer);\r
278             db.SubmitChanges();\r
279             Customer BT = db.Customers.Single(c => c.CustomerID == "BT___");\r
280             BT.Country = "U.K.";\r
281             db.SubmitChanges();\r
282 \r
283             db.Customers.DeleteOnSubmit(customer);\r
284             db.SubmitChanges();\r
285         }\r
286 \r
287         [Test]\r
288         public void G7_InsertTableWithStringPK()\r
289         {\r
290             Northwind db = CreateDB();\r
291             db.ExecuteCommand("DELETE FROM [Customers] WHERE [CustomerID]='TEMP_'");\r
292 \r
293             Customer custTemp = new Customer\r
294             {\r
295                 CustomerID = "TEMP_",\r
296                 CompanyName = "Magellan",\r
297                 ContactName = "Antonio Pigafetta",\r
298                 City = "Lisboa",\r
299             };\r
300             db.Customers.InsertOnSubmit(custTemp);\r
301             db.SubmitChanges();\r
302         }\r
303 \r
304         [Test]\r
305         public void G8_DeleteTableWithStringPK()\r
306         {\r
307             Northwind db = CreateDB();\r
308             Customer cust = (from c in db.Customers\r
309                              where c.CustomerID == "TEMP_"\r
310                              select c).Single();\r
311             db.Customers.DeleteOnSubmit(cust);\r
312             db.SubmitChanges();\r
313         }\r
314 \r
315         [Test]\r
316         public void G9_UpdateOnlyChangedProperty()\r
317         {\r
318             Northwind db = CreateDB();\r
319             var cust = (from c in db.Customers\r
320                         select c).First();\r
321 \r
322             var old = cust.City;\r
323             cust.City = "Tallinn";\r
324             db.SubmitChanges();\r
325             db.SubmitChanges(); // A second call does not update anything\r
326 \r
327             //exposes bug:\r
328             //Npgsql.NpgsqlException was unhandled\r
329             //Message="ERROR: 23502: null value in column \"companyname\" violates not-null constraint" \r
330             cust.City = old;\r
331             db.SubmitChanges();\r
332 \r
333         }\r
334 \r
335 #if POSTGRES\r
336 \r
337         public class Northwind1 : Northwind\r
338         {\r
339             public Northwind1(System.Data.IDbConnection connection)\r
340                 : base(connection) { }\r
341 \r
342             [System.Data.Linq.Mapping.Table(Name = "cust1")]\r
343             public class Cust1\r
344             {\r
345                 \r
346                 string _customerid;\r
347 \r
348                 [System.Data.Linq.Mapping.Column(Storage = "_customerid",\r
349                 Name = "customerid", IsPrimaryKey = true,\r
350                 DbType = "char(10)",\r
351                 IsDbGenerated = true,\r
352                 Expression = "nextval('seq8')")]\r
353                 public string CustomerId\r
354                 {\r
355                     get { return _customerid; }\r
356                     set { _customerid = value; }\r
357                 }\r
358 \r
359                 // Dummy property is required only as workaround over empty insert list bug\r
360                 // If this bug is fixed this may be removed\r
361                 string _dummy;\r
362                 [System.Data.Linq.Mapping.Column(Storage = "_dummy",\r
363                 DbType = "text", Name = "dummy")]\r
364                 public string Dummy\r
365                 {\r
366                     get;\r
367                     set;\r
368                 }\r
369 \r
370             }\r
371 \r
372             public Table<Cust1> Cust1s\r
373             {\r
374 \r
375                 get\r
376                 {\r
377                     return base.GetTable<Cust1>();\r
378                 }\r
379             }\r
380         }\r
381 \r
382         [Test]\r
383         public void G10_InsertCharSerialPrimaryKey()\r
384         {\r
385             Northwind dbo = CreateDB();\r
386             Northwind1 db = new Northwind1(dbo.Connection);\r
387             try\r
388             {\r
389                 db.ExecuteCommand(\r
390                     @"create sequence seq8;\r
391 create temp table cust1 ( CustomerID char(10) DEFAULT nextval('seq8'),\r
392 dummy text\r
393 );\r
394 ");\r
395 \r
396                 Table<Northwind1.Cust1> cust1s =\r
397                     db.GetTable<Northwind1.Cust1>();\r
398 \r
399                 var cust1 = new Northwind1.Cust1();\r
400                 cust1.Dummy = "";\r
401                 db.Cust1s.InsertOnSubmit(cust1);\r
402                 db.SubmitChanges();\r
403                 Assert.IsNotNull(cust1.CustomerId);\r
404             }\r
405             finally\r
406             {\r
407                 try { db.ExecuteCommand("drop table cust1;"); }\r
408                 catch { }\r
409                 try { db.ExecuteCommand("drop sequence seq8;"); }\r
410                 catch { }\r
411             }\r
412         }\r
413 #endif\r
414 \r
415         public class NorthwindG11 : Northwind\r
416         {\r
417             public NorthwindG11(System.Data.IDbConnection connection)\r
418                 : base(connection) { }\r
419 \r
420             [Table(Name = "rid")]\r
421             public class Rid : INotifyPropertyChanged\r
422             {\r
423 \r
424                 protected int _id;\r
425 \r
426                 protected int _reanr;\r
427 \r
428 \r
429 #if INGRES\r
430           [System.Data.Linq.Mapping.Column(Storage = "_id", Name = "id", DbType = "integer", IsPrimaryKey = true, IsDbGenerated = true, Expression = "next value for rid_id1_seq")]\r
431 #else\r
432                 [System.Data.Linq.Mapping.Column(Storage = "_id", Name = "id", DbType = "integer", IsPrimaryKey = true, IsDbGenerated = true, Expression = "nextval('rid_id1_seq')")]\r
433 #endif\r
434                 public int Id\r
435                 {\r
436                     get { return _id; }\r
437                     set\r
438                     {\r
439                         _id = value;\r
440                         OnPropertyChanged("Id");\r
441                     }\r
442                 }\r
443 \r
444 #if INGRES\r
445           [System.Data.Linq.Mapping.Column(Storage = "_reanr", Name = "reanr", DbType = "integer", IsDbGenerated = true, CanBeNull = false, Expression = "next value for rid_reanr_seq")]\r
446 #else\r
447                 [System.Data.Linq.Mapping.Column(Storage = "_reanr", Name = "reanr", DbType = "integer", IsDbGenerated = true, CanBeNull = false, Expression = "nextval('rid_reanr_seq')")]\r
448 #endif\r
449                 public int Reanr\r
450                 {\r
451                     get { return _reanr; }\r
452                     set\r
453                     {\r
454                         _reanr = value;\r
455                         OnPropertyChanged("Reanr");\r
456                     }\r
457                 }\r
458 \r
459 \r
460                 #region INotifyPropertyChanged handling\r
461                 public event PropertyChangedEventHandler PropertyChanged;\r
462                 protected virtual void OnPropertyChanged(string propertyName)\r
463                 {\r
464                     if (PropertyChanged != null)\r
465                     {\r
466                         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));\r
467                     }\r
468                 }\r
469                 #endregion\r
470 \r
471             }\r
472 \r
473 \r
474             public Table<Rid> Rids\r
475             {\r
476                 get\r
477                 {\r
478                     return base.GetTable<Rid>();\r
479                 }\r
480             }\r
481         }\r
482 \r
483 #if (POSTGRES || INGRES) && !MONO_STRICT\r
484 #if !DEBUG && POSTGRES\r
485         [Explicit]\r
486 #endif\r
487         [Test]\r
488         public void G11_TwoSequencesInTable()\r
489         {\r
490             Northwind dbo = CreateDB();\r
491             NorthwindG11 db = new NorthwindG11(dbo.Connection);\r
492 \r
493             db.ExecuteCommand(@"create sequence rid_id1_seq");\r
494             db.ExecuteCommand(@"create sequence rid_reanr_seq");\r
495 #if INGRES\r
496             db.ExecuteCommand(@"create table Rid ( id int primary key DEFAULT rid_id1_seq.nextval, reanr int DEFAULT rid_reanr_seq.nextval)");\r
497 #else\r
498             db.ExecuteCommand(@"create temp table Rid ( id int primary key DEFAULT nextval('rid_id1_seq'), reanr int DEFAULT nextval('rid_reanr_seq'))");\r
499 #endif\r
500             DbLinq.Data.Linq.Table<NorthwindG11.Rid> Rids = db.GetTable<NorthwindG11.Rid>();\r
501 \r
502             var Rid = new NorthwindG11.Rid();\r
503             Rid.Reanr = 22;\r
504             Exception e = null;\r
505             db.Rids.InsertOnSubmit(Rid);\r
506 \r
507             Rid = new NorthwindG11.Rid();\r
508             Rid.Reanr = 23;\r
509             db.Rids.InsertOnSubmit(Rid);\r
510             try\r
511             {\r
512                 db.SubmitChanges();\r
513             }\r
514             catch (Exception ex)\r
515             {\r
516                 e = ex;\r
517             }\r
518             db.ExecuteCommand("drop table rid");\r
519             db.ExecuteCommand("drop sequence rid_reanr_seq");\r
520             db.ExecuteCommand("drop sequence rid_id1_seq");\r
521             if (e != null)\r
522             {\r
523                 throw e;\r
524             }\r
525             Assert.AreEqual(2, Rid.Id);\r
526             Assert.AreEqual(23, Rid.Reanr);\r
527         }\r
528 \r
529 #endif\r
530 \r
531 #if !DEBUG && (SQLITE || (MSSQL && !L2SQL))\r
532         [Explicit]\r
533 #endif\r
534         [Test]\r
535         public void G12_EmptyInsertList()\r
536         {\r
537             Northwind db = CreateDB();\r
538             Region newRegion = new Region() { RegionDescription = "" }; // RegionDescription must be non-null\r
539             db.Regions.InsertOnSubmit(newRegion);\r
540             db.SubmitChanges();\r
541             Assert.IsNotNull(newRegion.RegionID);\r
542             db.Regions.DeleteOnSubmit(newRegion);\r
543             db.SubmitChanges();\r
544         }\r
545 \r
546 #if !DEBUG && (SQLITE || POSTGRES || (MSSQL && !L2SQL))\r
547         [Explicit]\r
548 #endif\r
549         [Test]\r
550         public void G13_ProvidedAutoGeneratedColumn()\r
551         {\r
552             Northwind db = CreateDB();\r
553             Category newCat = new Category();\r
554             newCat.CategoryID = 999;\r
555             newCat.CategoryName = "test";\r
556             db.Categories.InsertOnSubmit(newCat);\r
557             db.SubmitChanges();\r
558             // CategoryID is [Column(AutoSync=AutoSync.OnInsert)], so it's \r
559             // value is ignored on insert and will be updated\r
560             Assert.AreNotEqual(999, newCat.CategoryID);\r
561             // then, load our object\r
562             var checkCat = (from c in db.Categories where c.CategoryID == newCat.CategoryID select c).Single();\r
563             Assert.AreEqual(newCat.CategoryID, checkCat.CategoryID);\r
564             // remove the whole thing\r
565             db.Categories.DeleteOnSubmit(newCat);\r
566             db.SubmitChanges();\r
567         }\r
568 \r
569 \r
570         [Test]\r
571         public void G14_AutoGeneratedSupplierIdAndCompanyName()\r
572         {\r
573             Northwind db = CreateDB();\r
574             Supplier supplier = new Supplier()\r
575             {\r
576                 CompanyName = "Test Company",\r
577             };\r
578             db.Suppliers.InsertOnSubmit(supplier);\r
579             db.SubmitChanges();\r
580             Assert.IsNotNull(supplier.SupplierID);\r
581             Assert.AreEqual("Test Company", supplier.CompanyName);\r
582             db.Suppliers.DeleteOnSubmit(supplier);\r
583             db.SubmitChanges();\r
584         }\r
585 \r
586 \r
587         [Test]\r
588         [ExpectedException(typeof(InvalidOperationException))]\r
589         public void G15_CustomerIdUpdate()\r
590         {\r
591             //if you run this against Microsoft Linq-to-Sql, it throws an InvalidOperationEx:\r
592             //{"Value of member 'CustomerID' of an object of type 'Customers' changed. \r
593             //A member defining the identity of the object cannot be changed.\r
594             //Consider adding a new object with new identity and deleting the existing one instead."}\r
595 \r
596             Northwind db = CreateDB();\r
597             Customer c1 = (from c in db.Customers\r
598                            where c.CustomerID == "AIRBU"\r
599                            select c).Single();\r
600             c1.CustomerID = "TEMP";\r
601             db.SubmitChanges();\r
602             Customer c2 = (from c in db.Customers\r
603                            where c.CustomerID == "TEMP"\r
604                            select c).Single();\r
605 \r
606             c2.CustomerID = "AIRBU";\r
607             db.SubmitChanges();\r
608         }\r
609 \r
610         /// <summary>\r
611         /// Quote from MSDN:\r
612         /// If the object requested by the query is easily identifiable as one\r
613         /// already retrieved, no query is executed. The identity table acts as a cache\r
614         /// of all previously retrieved objects\r
615 \r
616         /// From Matt Warren: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=345635&SiteID=1\r
617         /// The cache is checked when the query is a simple table.Where(pred) or table.First(pred) where the \r
618         /// predicate refers only to the primary key.  Otherwise the query is always sent and the cache only checked \r
619         /// after the results are retrieved. \r
620         /// The DLINQ cache is not distributed or shared, it is local and contained within the context.  It is only a \r
621         /// referential identity cache used to guarantee that two reads of the same entity return the same instance. \r
622         /// You are not expected to hold the cache for an extended duration (except possibly for a client scenario), \r
623         /// or share it across threads, processes, or machines in a cluster. \r
624         /// </summary>\r
625 #if !DEBUG && (SQLITE || POSTGRES || (MSSQL && !L2SQL))\r
626         [Explicit]\r
627 #endif\r
628         [Test]\r
629         public void G16_CustomerCacheHit()\r
630         {\r
631             Northwind db = CreateDB();\r
632             Customer c1 = new Customer() { CustomerID = "temp", CompanyName = "Test", ContactName = "Test" };\r
633             db.Customers.InsertOnSubmit(c1);\r
634             db.SubmitChanges();\r
635             db.ExecuteCommand("delete from \"Customers\" WHERE \"CustomerID\"='temp'");\r
636 \r
637             var res = db.Customers.First(c => c.CustomerID == "temp");\r
638             Assert.IsNotNull(res);\r
639         }\r
640 \r
641 \r
642 \r
643 #if !DEBUG && (SQLITE || POSTGRES || MSSQL)\r
644         // L2SQL: System.InvalidOperationException : The type 'Test_NUnit_MsSql_Strict.WriteTest+OrderDetailWithSum' is not mapped as a Table.\r
645         [Explicit]\r
646 #endif\r
647         [Test]\r
648         public void G17_LocalPropertyUpdate()\r
649         {\r
650             Northwind dbo = CreateDB();\r
651             NorthwindLocalProperty db = new NorthwindLocalProperty(dbo.Connection);\r
652             var det = db.OrderDetailWithSums.First();\r
653             det.ChangeQuantity();\r
654             Assert.AreEqual(0, db.GetChangeSet().Updates.Count);\r
655             db.SubmitChanges();\r
656         }\r
657 \r
658 \r
659         class NorthwindLocalProperty : Northwind\r
660         {\r
661             internal NorthwindLocalProperty(System.Data.IDbConnection connection)\r
662                 : base(connection) { }\r
663 \r
664             internal Table<OrderDetailWithSum> OrderDetailWithSums\r
665             {\r
666                 get\r
667                 {\r
668                     return GetTable<OrderDetailWithSum>();\r
669                 }\r
670             }\r
671 \r
672         }\r
673 \r
674         class OrderDetailWithSum : OrderDetail, INotifyPropertyChanged\r
675         {\r
676             public event PropertyChangedEventHandler PropertyChanged;\r
677             protected virtual void OnPropertyChanged(string propertyName)\r
678             {\r
679                 if (PropertyChanged != null)\r
680                 {\r
681                     PropertyChanged(this, new PropertyChangedEventArgs(propertyName));\r
682                 }\r
683             }\r
684 \r
685             internal decimal? Sum\r
686             {\r
687                 get\r
688                 {\r
689                     return Quantity * UnitPrice;\r
690                 }\r
691             }\r
692 \r
693             internal void ChangeQuantity()\r
694             {\r
695                 OnPropertyChanged("Sum");\r
696             }\r
697         }\r
698 \r
699 #if !DEBUG && (!(MSSQL && L2SQL))\r
700         [Explicit]\r
701 #endif\r
702         // L2SQL: System.NotSupportedException : An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext.  This is not supported.\r
703         [Test]\r
704         [ExpectedException(typeof(NotSupportedException))]\r
705         public void G18_UpdateWithAttach()\r
706         {\r
707             List<Order> list;\r
708             using (Northwind db = CreateDB())\r
709                 list = db.Orders.ToList();\r
710 \r
711             using (Northwind db = CreateDB())\r
712             {\r
713                 var tbl = db.GetTable<Order>();\r
714                 foreach (var order in list)\r
715                 {\r
716                     if (order.Freight == null)\r
717                         continue;\r
718                     tbl.Attach(order);\r
719                 }\r
720                 db.SubmitChanges();\r
721             }\r
722         }\r
723 \r
724 \r
725 #if !DEBUG && (SQLITE || POSTGRES || (MSSQL && !L2SQL))\r
726         [Explicit]\r
727 #endif\r
728         [Test]\r
729         public void G19_ExistingCustomerCacheHit()\r
730         {\r
731             Northwind db = CreateDB();\r
732             string id = "ALFKI";\r
733             Customer c1 = (from c in db.Customers\r
734                            where id == c.CustomerID\r
735                            select c).Single();\r
736 \r
737             db.Connection.ConnectionString = null;\r
738 \r
739             var x = db.Customers.First(c => id == c.CustomerID);\r
740         }\r
741 \r
742 \r
743         [Test]\r
744         public void G20_CustomerCacheHitComparingToLocalVariable()\r
745         {\r
746              Northwind db = CreateDB();\r
747              try\r
748              {\r
749                 Customer c1 = new Customer() { CustomerID = "temp", CompanyName = "Test", ContactName = "Test" };\r
750                 db.Customers.InsertOnSubmit(c1);\r
751                 db.SubmitChanges();\r
752 \r
753                 string id = "temp";\r
754                 var res = from c in db.Customers\r
755                           where c.CustomerID == id\r
756                           select c;\r
757 \r
758                 Assert.AreEqual(1, res.Count(), "#1");\r
759 \r
760                 db.ExecuteCommand("DELETE FROM \"Customers\" WHERE \"CustomerID\"='temp'");\r
761 \r
762                 res = from c in db.Customers\r
763                       where c.CustomerID == id\r
764                       select c;\r
765                 Assert.AreEqual(0, res.Count(), "#2");\r
766             }\r
767             finally\r
768             {\r
769                 db.ExecuteCommand("DELETE FROM \"Customers\" WHERE \"CustomerID\"='temp'");\r
770             }\r
771         }\r
772 \r
773         #endregion\r
774 \r
775         [Test]\r
776         public void Update01()\r
777         {\r
778             var db = CreateDB();\r
779             Employee p = db.Employees.First(r => r.LastName == "Fuller");\r
780 \r
781             DateTime beforeDateTime = p.BirthDate.Value;\r
782             DateTime now = beforeDateTime.AddMinutes(10);\r
783 \r
784             p.BirthDate = now;\r
785             db.SubmitChanges();\r
786 \r
787             Employee p2 = db.Employees.First(r => r.LastName == "Fuller");\r
788             Assert.AreEqual(p2.BirthDate, now);\r
789 \r
790             //undo changes\r
791             p.BirthDate = beforeDateTime;\r
792             db.SubmitChanges();\r
793         }\r
794 \r
795 #if !DEBUG && SQLITE\r
796         [Explicit]\r
797 #endif\r
798         [Test]\r
799         public void InsertAndDeleteWithDependencies()\r
800         {\r
801             const string newCategoryName  = "temp Category";\r
802             const string newProduct1 = "temp First Test Product";\r
803             const string newProduct2 = "temp Second Test Product";\r
804 \r
805             var db = CreateDB();\r
806 \r
807             var product = new Product\r
808             {\r
809 #if INGRES\r
810                 Discontinued = "Y",\r
811 #else\r
812                 Discontinued = true,\r
813 #endif\r
814                 ProductName = newProduct1,\r
815             };\r
816 \r
817             var category = new Category\r
818             {\r
819                 CategoryName = newCategoryName,\r
820                 Description  = "Insert Description Here",\r
821             };\r
822             category.Products.Add(product);\r
823 \r
824             Assert.AreEqual(0, category.CategoryID);\r
825             Assert.AreEqual(0, product.CategoryID.Value);\r
826 \r
827             db.Categories.InsertOnSubmit(category);\r
828             db.SubmitChanges();\r
829 \r
830             Assert.AreEqual(1, db.Categories.Where(c => c.CategoryName == newCategoryName).Count());\r
831             Assert.AreNotEqual(0, category.CategoryID);\r
832             Assert.AreEqual(1, db.Products.Where(p => p.ProductName == newProduct1).Count());\r
833             Assert.AreEqual(category.CategoryID, product.CategoryID.Value);\r
834 \r
835             var p2 = new Product\r
836             {\r
837 #if INGRES\r
838                 Discontinued = "Y",\r
839 #else\r
840                 Discontinued = true,\r
841 #endif\r
842                 ProductName = newProduct2\r
843             };\r
844             category.Products.Add(p2);\r
845             db.SubmitChanges();\r
846 \r
847             Assert.AreEqual(1, db.Products.Where(p => p.ProductName == newProduct2).Count());\r
848 \r
849             db.Products.DeleteOnSubmit(product);\r
850             db.Products.DeleteOnSubmit(p2);\r
851             db.Categories.DeleteOnSubmit(category);\r
852             db.SubmitChanges();\r
853 \r
854             Assert.AreEqual(0, db.Categories.Where(c => c.CategoryName == newCategoryName).Count());\r
855             Assert.AreEqual(0, db.Products.Where(p => p.ProductName == newProduct1).Count());\r
856             Assert.AreEqual(0, db.Products.Where(p => p.ProductName == newProduct2).Count());\r
857         }\r
858     }\r
859 }\r