EF et N-Tiers
Même si les scenarii N-Tiers sont maintenant plus facile avec EF4 et les Self-Tracking entities, je pense qu’on est encore loin de la solution idéale.
Dans un post précédent, j’expliquais comment en utilisant T4, je pouvais complètement générer mon service WCF. Maintenant, qu’en est-il du tiers client ?
Dans ce même post, j’expliquais comment je pouvais “traduire” les requêtes LINQ par des paramètres de méthodes de mon service WCF.
J’ai procédé à quelques améliorations de cette partie. Cependant, mon objectif principal consistait à avoir un vrai contexte côté client. J’avais déjà fait cela pour ADO.NET Data Services en utilisant T4, J’en ai maintenant fait un pour WCF (toujours en utilisant T4 bien sûr).
Un de mes clients reproche à ADO.NET Data Services le fait que par défaut, quand on accède aux collections du contexte, on a systématiquement une requête vers le serveur. Par défaut, il voulait utiliser le cache. Avec ADO.NET Data Services, l’utilisation du cache est vraiment pas top (idem pour EF d’ailleurs).
Avec mon contexte, j’utilise par défaut le cache et j’utilise l’extension method AsQueryable pour générer une requête côté serveur.
Plutôt qu’un long discours, rien de tel que du code pour comprendre ce que fait mon contexte et en l’occurrence, les tests unitaires qui m’ont permis de valider le bon fonctionnement de mon code.
[TestClass]
public class UnitTest
{
[TestMethod]
public void TestService()
{
INorthwindService context = new NorthwindClientContext();
Assert.AreNotEqual(0, context.GetCustomers().Count);
}
[TestMethod]
public void TestFilter()
{
INorthwindService context = new NorthwindClientContext();
Assert.AreEqual(1, context.GetCustomers(null, "it.CustomerID='ALFKI'", null, null, null).Count);
}
[TestMethod]
public void TestLINQWhere()
{
using (var context = new NorthwindClientContext())
{
Assert.AreEqual(1, (from c in context.Customers.AsQueryable()
where c.CustomerID == "ALFKI"
select c).Count());
}
}
[TestMethod]
public void TestLINQWhere2()
{
using (var context = new NorthwindClientContext())
{
var customerID = "ALFKI";
Assert.AreEqual(1, (from c in context.Customers.AsQueryable()
where c.CustomerID == customerID
select c).Count());
}
}
[TestMethod]
public void TestLINQWhere3()
{
using (var context = new NorthwindClientContext())
{
var customer = new Customer { CustomerID = "ALFKI" };
Assert.AreEqual(1, (from c in context.Customers.AsQueryable()
where c.CustomerID == customer.CustomerID
select c).Count());
}
}
[TestMethod]
public void TestLINQWhere4()
{
using (var context = new NorthwindClientContext())
{
Assert.AreNotEqual(0, (from o in context.Orders.AsQueryable()
where o.OrderDate > new DateTime(1997, 1, 31)
select o).Count());
}
}
[TestMethod]
public void TestLINQWhere5()
{
using (var context = new NorthwindClientContext())
{
var d = new DateTime(1997, 1, 31);
Assert.AreNotEqual(0, (from o in context.Orders.AsQueryable()
where o.OrderDate > d
select o).Count());
}
}
[TestMethod]
public void TestLINQTake()
{
using (var context = new NorthwindClientContext())
{
Assert.AreEqual(2, (from c in context.Customers.AsQueryable()
select c).Take(2).Count());
}
}
[TestMethod]
public void TestFirstAndInclude()
{
using (var context = new NorthwindClientContext())
{
var order = (from o in context.Orders.AsQueryable().Include(Order.CUSTOMER_NAME).Include(Order.ORDERDETAILS_NAME)
where o.ShipCity == "PARIS"
orderby o.OrderDate
select o).Skip(2).First();
Assert.IsNotNull(order.Customer);
Assert.AreEqual(1, context.Customers.Count);
Assert.AreEqual(order.Customer, context.Customers[0]);
Assert.AreEqual(1, context.Orders.Count);
Assert.AreEqual(order, context.Orders[0]);
Assert.AreNotEqual(0, order.OrderDetails);
}
}
[TestMethod]
public void NoTracking()
{
using (var context = new NorthwindClientContext())
{
context.MergeOption = MergeOption.NoTracking;
var l = context.Customers.AsQueryable().ToList();
Assert.AreEqual(0, context.Customers.Count);
Assert.AreNotEqual(0, l.Count);
}
}
[TestMethod]
public void AppendOnly()
{
using (var context = new NorthwindClientContext())
{
context.MergeOption = MergeOption.AppendOnly;
var l = context.Customers.AsQueryable().ToList();
Assert.AreEqual(l.Count, context.Customers.Count);
}
}
[TestMethod]
public void AppendOnly2()
{
using (var context = new NorthwindClientContext())
{
context.MergeOption = MergeOption.AppendOnly;
var c = new Customer { CustomerID = "ALFKI" };
context.Customers.Attach(c);
context.Customers.AsQueryable().ToList();
Assert.IsNull(c.CompanyName);
Assert.AreEqual(0, c.ChangeTracker.ModifiedProperties.Count);
}
}
[TestMethod]
public void OverwriteChanges()
{
using (var context = new NorthwindClientContext())
{
context.MergeOption = MergeOption.OverwriteChanges;
var l = context.Customers.AsQueryable().ToList();
Assert.AreEqual(l.Count, context.Customers.Count);
}
}
[TestMethod]
public void OverwriteChanges2()
{
using (var context = new NorthwindClientContext())
{
context.MergeOption = MergeOption.OverwriteChanges;
var c = new Customer { CustomerID = "ALFKI" };
context.Customers.Attach(c);
context.Customers.AsQueryable().ToList();
Assert.IsNotNull(c.CompanyName);
Assert.AreEqual(0, c.ChangeTracker.ModifiedProperties.Count);
}
}
[TestMethod]
public void PreserveChanges()
{
using (var context = new NorthwindClientContext())
{
context.MergeOption = MergeOption.PreserveChanges;
var l = context.Customers.AsQueryable().ToList();
Assert.AreEqual(l.Count, context.Customers.Count);
}
}
[TestMethod]
public void PreserveChanges2()
{
using (var context = new NorthwindClientContext())
{
context.MergeOption = MergeOption.PreserveChanges;
var c = new Customer { CustomerID = "ALFKI" };
context.Customers.Attach(c);
context.Customers.AsQueryable().ToList();
Assert.IsNull(c.CompanyName);
Assert.AreNotEqual(0, c.ChangeTracker.ModifiedProperties.Count);
Assert.IsTrue(c.ChangeTracker.ModifiedProperties.Contains("CompanyName"));
}
}
[TestMethod]
public void Save()
{
using (var context = new NorthwindClientContext())
{
//Add
var psCount = context.Products.AsQueryable().Count();
var p = new Product { ProductName = "p" };
context.Products.Add(p);
context.SaveChanges();
Assert.AreNotEqual(0, p.ProductID);
Assert.AreEqual(ObjectState.Unchanged, p.ChangeTracker.State);
Assert.AreEqual(psCount + 1, context.Products.AsQueryable().ToList().Count);
//Update
p.ProductName = "p2";
Assert.AreEqual(1, p.ChangeTracker.ModifiedProperties.Count);
Assert.AreEqual("ProductName", p.ChangeTracker.ModifiedProperties[0]);
context.SaveChanges();
context.MergeOption = MergeOption.NoTracking;
var p2 = context.Products.AsQueryable().Where(pr => pr.ProductID == p.ProductID).First();
Assert.AreNotEqual(p, p2);
Assert.AreEqual("p2", p2.ProductName);
//Remove
context.Products.Remove(p);
Assert.AreEqual(ObjectState.Deleted, p.ChangeTracker.State);
context.SaveChanges();
Assert.AreEqual(psCount, context.Products.AsQueryable().ToList().Count);
}
}
[TestMethod]
public void Save2()
{
using (var context = new NorthwindClientContext())
{
var csCount = context.Categories.AsQueryable().Count();
var c1 = new Category { CategoryName = "cn" };
context.Categories.Add(c1);
var psCount = context.Products.AsQueryable().Count();
var p1 = new Product { ProductName = "p1" };
var p2 = new Product { ProductName = "p2" };
context.Products.Add(p1);
context.Products.Add(p2);
context.SaveChanges();
using (var context2 = new NorthwindClientContext())
{
Assert.AreEqual(csCount + 1, context2.Categories.AsQueryable().Count());
Assert.AreEqual(psCount + 2, context2.Products.AsQueryable().Count());
}
context.Categories.Remove(c1);
context.Products.Remove(p1);
p2.ProductName = "p2Bis";
context.SaveChanges();
using (var context2 = new NorthwindClientContext())
{
Assert.AreEqual(csCount, context2.Categories.AsQueryable().Count());
Assert.AreEqual(psCount + 1, context2.Products.AsQueryable().Count());
Assert.AreEqual("p2Bis", context2.Products.Last().ProductName);
}
context.Products.Remove(p2);
context.SaveChanges();
using (var context2 = new NorthwindClientContext())
{
Assert.AreEqual(psCount, context2.Products.AsQueryable().Count());
}
}
}
[TestMethod]
public void TestSaveManyToMany()
{
CustomerDemographic cd;
using (var context = new NorthwindClientContext())
{
cd = new CustomerDemographic { CustomerTypeID = "CD", CustomerDesc = "cd desc" };
context.CustomerDemographics.Add(cd);
context.SaveChanges();
}
using (var context = new NorthwindClientContext())
{
var c = context.Customers.AsQueryable().First();
c.CustomerDemographics.Add(cd);
Assert.AreEqual(ObjectState.Unchanged, cd.ChangeTracker.State);
Assert.AreEqual(1, context.CustomerDemographics.Count);
Assert.AreEqual(1, cd.Customers.Count);
context.SaveChanges();
}
using (var context = new NorthwindClientContext())
{
var c = context.Customers.AsQueryable().Include(Customer.CUSTOMERDEMOGRAPHICS_NAME).First();
Assert.AreNotEqual(0, context.CustomerDemographics.Count);
Assert.AreNotEqual(0, cd.Customers.Count);
context.CustomerDemographics.Remove(context.CustomerDemographics.First(cd2 => cd2.CustomerTypeID.TrimEnd() == "CD"));
context.SaveChanges();
}
}
[TestMethod]
public void TestAddViaCollection()
{
using (var context = new NorthwindClientContext())
{
int psCount;
using (var context2 = new NorthwindClientContext())
{
psCount = context2.Products.AsQueryable().Count();
}
var c = context.Categories.AsQueryable().First();
var p = new Product { ProductName = "pn" };
c.Products.Add(p);
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(1, context.Products.Count);
Assert.AreEqual(context.Products[0], p);
Assert.AreEqual(p.Category, c);
Assert.AreEqual(p.CategoryID, c.Id);
Assert.AreEqual(ObjectState.Added, p.ChangeTracker.State);
context.SaveChanges();
using (var context2 = new NorthwindClientContext())
{
Assert.AreEqual(psCount + 1, context2.Products.AsQueryable().Count());
}
Assert.AreEqual(1, c.Products.Count);
context.Products.Remove(p);
Assert.AreEqual(0, c.Products.Count);
context.SaveChanges();
}
}
[TestMethod]
public void TestAddViaCollection2()
{
using (var context = new NorthwindClientContext())
{
int psCount;
using (var context2 = new NorthwindClientContext())
{
psCount = context2.Products.AsQueryable().Count();
}
var c = context.Categories.AsQueryable().First();
var p = new Product { ProductName = "pn", Category = c };
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(1, context.Products.Count);
Assert.AreEqual(context.Products[0], p);
Assert.AreEqual(p.Category, c);
Assert.AreEqual(p.CategoryID, c.Id);
Assert.AreEqual(ObjectState.Added, p.ChangeTracker.State);
context.SaveChanges();
using (var context2 = new NorthwindClientContext())
{
Assert.AreEqual(psCount + 1, context2.Products.AsQueryable().Count());
}
Assert.AreEqual(1, c.Products.Count);
context.Products.Remove(p);
Assert.AreEqual(0, c.Products.Count);
context.SaveChanges();
}
}
[TestMethod]
public void TestAddViaCollection3()
{
using (var context = new NorthwindClientContext())
{
var c = new Category { CategoryName = "cn" };
context.Categories.Add(c);
var p = new Product { ProductName = "pn", Category = c };
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(1, context.Products.Count);
Assert.AreEqual(context.Products[0], p);
Assert.AreEqual(c, p.Category);
Assert.AreEqual(c.Id, p.CategoryID);
Assert.AreEqual(1, context.Categories.Count);
Assert.AreEqual(c, context.Categories[0]);
context.SaveChanges();
Assert.AreEqual(c, p.Category);
Assert.AreEqual(c.Id, p.CategoryID);
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(p, c.Products[0]);
context.Categories.Remove(c);
Assert.IsNull(p.Category);
Assert.IsNull(p.CategoryID);
Assert.AreEqual(ObjectState.Modified, p.ChangeTracker.State);
Assert.AreEqual(1, p.ChangeTracker.ModifiedProperties.Count);
Assert.AreEqual("CategoryID", p.ChangeTracker.ModifiedProperties[0]);
context.SaveChanges();
context.Products.Remove(p);
context.SaveChanges();
}
}
[TestMethod]
public void TestAddViaCollection4()
{
using (var context = new NorthwindClientContext())
{
var c = new Category { CategoryName = "cn" };
var p = new Product { ProductName = "pn", Category = c };
context.Categories.Add(c);
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(1, context.Products.Count);
Assert.AreEqual(context.Products[0], p);
Assert.AreEqual(p.Category, c);
Assert.AreEqual(p.CategoryID, c.Id);
Assert.AreEqual(1, context.Categories.Count);
Assert.AreEqual(c, context.Categories[0]);
}
}
[TestMethod]
public void TestAddViaCollection5()
{
using (var context = new NorthwindClientContext())
{
var c = new Customer { CustomerID = "A" };
var cd = new CustomerDemographic();
c.CustomerDemographics.Add(cd);
context.Customers.Attach(c);
Assert.AreEqual(1, context.Customers.Count);
Assert.AreEqual(1, context.CustomerDemographics.Count);
Assert.AreEqual(c, context.Customers[0]);
Assert.AreEqual(cd, context.CustomerDemographics[0]);
Assert.AreEqual(1, cd.Customers.Count);
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void TestEntitySetAttachWithSameKey()
{
using (var context = new NorthwindClientContext())
{
context.Categories.Attach(new Category { Id = 1 });
context.Categories.Attach(new Category { Id = 1 });
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void TestEntitySetAddWithSameKey()
{
using (var context = new NorthwindClientContext())
{
context.Customers.Add(new Customer { CustomerID = "C" });
context.Customers.Add(new Customer { CustomerID = "C" });
}
}
[TestMethod]
public void TestEntitySetAddWithSameKeyIdentity()
{
using (var context = new NorthwindClientContext())
{
context.Categories.Add(new Category { Id = 0 });
context.Categories.Add(new Category { Id = 0 });
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void TestNavigationPropertyManyAttachWithSameKey()
{
using (var context = new NorthwindClientContext())
{
var cd = new CustomerDemographic { CustomerTypeID = "CD" };
context.CustomerDemographics.Attach(cd);
context.Customers.Attach(new Customer { CustomerID = "C" });
cd.Customers.Attach(new Customer { CustomerID = "C" });
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void TestNavigationPropertyManyAddWithSameKey()
{
using (var context = new NorthwindClientContext())
{
var cd = new CustomerDemographic { CustomerTypeID = "CD" };
context.CustomerDemographics.Attach(cd);
context.Customers.Attach(new Customer { CustomerID = "C" });
cd.Customers.Add(new Customer { CustomerID = "C" });
}
}
[TestMethod]
public void MultipleAddAttachOfSameObject()
{
using (var context = new NorthwindClientContext())
{
var c = new Customer { CustomerID = "C" };
context.Customers.Add(c);
context.Customers.Add(c);
context.Customers.Attach(c);
new CustomerDemographic { CustomerTypeID = "CD" }.Customers.Add(c);
Assert.AreEqual(1, context.Customers.Count);
}
}
[TestMethod]
public void MultipleRelationAddAttachOfSameObject()
{
using (var context = new NorthwindClientContext())
{
var c = new Customer { CustomerID = "C" };
var cd = new CustomerDemographic { CustomerTypeID = "CD" };
c.CustomerDemographics.Add(cd);
c.CustomerDemographics.Add(cd);
c.CustomerDemographics.Attach(cd);
Assert.AreEqual(1, c.CustomerDemographics.Count);
Assert.AreEqual(1, cd.Customers.Count);
}
}
[TestMethod]
public void DeleteCascade()
{
using (var context = new NorthwindClientContext())
{
var o = new Order();
var od = new OrderDetail { Order = o };
Assert.AreEqual(ObjectState.Detached, o.ChangeTracker.State);
Assert.AreEqual(ObjectState.Detached, od.ChangeTracker.State);
context.Orders.Add(o);
Assert.AreEqual(ObjectState.Added, o.ChangeTracker.State);
Assert.AreEqual(ObjectState.Added, od.ChangeTracker.State);
context.Orders.Remove(o);
Assert.AreEqual(ObjectState.Detached, o.ChangeTracker.State);
Assert.AreEqual(ObjectState.Detached, od.ChangeTracker.State);
}
}
[TestMethod]
public void DeleteCascade2()
{
using (var context = new NorthwindClientContext())
{
var o = new Order();
var od = new OrderDetail { Order = o, Product = context.Products.AsQueryable().First(), Discount = 0, Quantity = 1, UnitPrice = 10 };
context.Orders.Add(o);
context.SaveChanges();
var od2 = new OrderDetail { Order = o };
context.Orders.Remove(o);
Assert.AreEqual(ObjectState.Deleted, o.ChangeTracker.State);
Assert.AreEqual(ObjectState.Deleted, od.ChangeTracker.State);
Assert.AreEqual(ObjectState.Detached, od2.ChangeTracker.State);
context.SaveChanges();
}
}
[TestMethod]
public void AttachRelationInLoad()
{
using (var context = new NorthwindClientContext())
{
var c = new Category { Id = 1 };
context.Categories.Attach(c);
var p = new Product { CategoryID = 1 };
context.Products.Attach(p);
Assert.AreEqual(c, p.Category);
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(p, c.Products[0]);
}
}
[TestMethod]
public void AttachRelationInLoad2()
{
using (var context = new NorthwindClientContext())
{
var c = new Category { Id = 1 };
context.Categories.Add(c);
var p = new Product { CategoryID = 1 };
context.Products.Add(p);
Assert.AreEqual(c, p.Category);
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(p, c.Products[0]);
}
}
[TestMethod]
public void AttachRelationInLoad3()
{
using (var context = new NorthwindClientContext())
{
var p = new Product { CategoryID = 1 };
context.Products.Attach(p);
var c = new Category { Id = 1 };
context.Categories.Attach(c);
Assert.AreEqual(c, p.Category);
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(p, c.Products[0]);
}
}
[TestMethod]
public void AttachRelationInLoad4()
{
using (var context = new NorthwindClientContext())
{
var p = new Product { CategoryID = 1 };
context.Products.Add(p);
var c = new Category { Id = 1 };
context.Categories.Add(c);
Assert.AreEqual(c, p.Category);
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(p, c.Products[0]);
}
}
[TestMethod]
public void AttachRelationInLoad5()
{
using (var context = new NorthwindClientContext())
{
context.Products.AsQueryable().ToList();
var c = context.Categories.AsQueryable().First();
Assert.AreEqual(context.Products.Where(p => p.CategoryID == c.Id).Count(), c.Products.Count);
foreach (var p in context.Products.Where(p => p.CategoryID == c.Id))
{
Assert.AreEqual(c, p.Category);
Assert.IsTrue(c.Products.Contains(p));
}
}
}
[TestMethod]
public void AttachRelationInLoad6()
{
using (var context = new NorthwindClientContext())
{
var c = context.Categories.AsQueryable().First();
context.Products.AsQueryable().ToList();
Assert.AreEqual(context.Products.Where(p => p.CategoryID == c.Id).Count(), c.Products.Count);
foreach (var p in context.Products.Where(p => p.CategoryID == c.Id))
{
Assert.AreEqual(c, p.Category);
Assert.IsTrue(c.Products.Contains(p));
}
}
}
[TestMethod]
public void AttachRelationInLoad7()
{
using (var context = new NorthwindClientContext())
{
context.Products.AsQueryable().ToList();
var c = context.Categories.AsQueryable().Include(Category.PRODUCTS_NAME).First();
Assert.AreEqual(context.Products.Where(p => p.CategoryID == c.Id).Count(), c.Products.Count);
foreach (var p in context.Products.Where(p => p.CategoryID == c.Id))
{
Assert.AreEqual(c, p.Category);
Assert.IsTrue(c.Products.Contains(p));
}
}
}
[TestMethod]
public void AttachRelationInLoad8()
{
using (var context = new NorthwindClientContext())
{
context.Products.AsQueryable().ToList();
var c = new Category { Id = 1 };
context.Categories.Attach(c);
var c2 = context.Categories.AsQueryable().Include(Category.PRODUCTS_NAME).First();
Assert.AreEqual(c, c2);
Assert.AreEqual(context.Products.Where(p => p.CategoryID == c.Id).Count(), c.Products.Count);
foreach (var p in context.Products.Where(p => p.CategoryID == c.Id))
{
Assert.AreEqual(c, p.Category);
Assert.IsTrue(c.Products.Contains(p));
}
}
}
[TestMethod]
public void AttachRelationInLoad9()
{
using (var context = new NorthwindClientContext())
{
var c = new Category { CategoryName = "cn" };
var p = new Product { ProductName = "pn", Category = c };
context.Categories.Add(c);
Assert.AreEqual(1, context.Products.Count);
context.SaveChanges();
Product p2;
using (var context2 = new NorthwindClientContext())
{
var c2 = context2.Categories.AsQueryable().Include(Category.PRODUCTS_NAME).Where(c3 => c3.Id == c.Id).First();
p2 = new Product { ProductName = "pn2" };
c2.Products.Add(p2);
context2.SaveChanges();
}
var c4 = context.Categories.AsQueryable().Include(Category.PRODUCTS_NAME).Where(c3 => c3.Id == c.Id).First();
Assert.AreEqual(c, c4);
Assert.IsTrue(c.Products.Contains(p));
Assert.IsFalse(c.Products.Contains(p2));
var p3 = c.Products.First(p4 => p4.ProductID == p2.ProductID);
Assert.IsTrue(c.Products.Contains(p3));
Assert.IsTrue(context.Products.Contains(p3));
context.Products.Remove(p3);
context.Products.Remove(p);
context.Categories.Remove(c);
Assert.AreEqual(c.Id, p.CategoryID);
Assert.AreEqual(c.Id, p3.CategoryID);
context.SaveChanges();
}
}
[TestMethod]
public void AttachRelationInLoad10()
{
using (var context = new NorthwindClientContext())
{
var p = context.Products.AsQueryable().First();
context.Orders.Attach(new Order());
var od = context.OrderDetails.AsQueryable().Where(od2 => od2.ProductID == p.ProductID).First();
var p2 = (from p3 in context.Products.AsQueryable().Include(Product.CATEGORY_NAME).Include(string.Concat(Product.ORDERDETAILS_NAME, ".", OrderDetail.ORDER_NAME))
where p3.ProductID == p.ProductID
select p3).First();
Assert.AreEqual(p, p2);
Assert.IsNotNull(p.Category);
Assert.AreEqual(1, context.Categories.Count);
Assert.AreEqual(p.OrderDetails.Count, context.OrderDetails.Count);
foreach (var od2 in p.OrderDetails)
Assert.IsNotNull(od2.Order);
Assert.AreEqual(p.OrderDetails.Select(od3 => od3.Order).Distinct().Count() + 1, context.Orders.Count);
Assert.AreNotEqual(0, context.Orders.Count);
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void AddSameEntityInDifferentContext()
{
var p = new Product();
using (var context1 = new NorthwindClientContext())
{
context1.Products.Add(p);
using (var context2 = new NorthwindClientContext())
{
context2.Products.Add(p);
}
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void AddSameEntityFromServiceInDifferentContext()
{
Product p;
using (var context1 = new NorthwindClientContext())
{
p = context1.Products.AsQueryable().First();
using (var context2 = new NorthwindClientContext())
{
context2.Products.Add(p);
}
}
}
[TestMethod]
public void AddSameEntityInDifferentContextWithDispose()
{
var p = new Product();
using (var context1 = new NorthwindClientContext())
{
context1.Products.Add(p);
}
using (var context2 = new NorthwindClientContext())
{
context2.Products.Add(p);
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void AddSameEntityInDifferentContextWithDisposeAndConflicts()
{
var c = new Category { Id = 1 };
var p1 = new Product { ProductID = 1, Category = c };
var p2 = new Product { ProductID = 2 , CategoryID = 1};
using (var context1 = new NorthwindClientContext())
{
context1.Categories.Attach(c);
context1.Products.Attach(p2);
Assert.AreEqual(2, context1.Products.Count);
Assert.AreEqual(2, c.Products.Count);
Assert.AreEqual(c, p2.Category);
}
using (var context2 = new NorthwindClientContext())
{
var p3 = new Product { ProductID = 1 , CategoryID = 1};
context2.Products.Attach(p3);
context2.Categories.Attach(c);
}
}
[TestMethod]
public void LoadFromOneToMany()
{
using (var context = new NorthwindClientContext())
{
var c = context.Categories.AsQueryable().First();
Assert.AreEqual(0, c.Products.Count);
Assert.AreEqual(0, context.Products.Count);
var ps = c.LoadProducts();
Assert.AreNotEqual(0, ps.Count);
Assert.AreEqual(ps.Count, c.Products.Count);
Assert.AreEqual(ps.Count, context.Products.Count);
foreach (var p in ps)
Assert.AreEqual(c, p.Category);
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void LoadFromOneToManyDetached()
{
Category c;
using (var context = new NorthwindClientContext())
{
c = context.Categories.AsQueryable().First();
}
var ps = c.LoadProducts();
}
[TestMethod]
public void LoadFromManyToOne()
{
using (var context = new NorthwindClientContext())
{
var p = context.Products.AsQueryable().First();
Assert.IsNull(p.Category);
Assert.AreEqual(0, context.Categories.Count);
var c = p.LoadCategory();
Assert.IsNotNull(c);
Assert.AreEqual(c, p.Category);
Assert.AreEqual(1, context.Categories.Count);
Assert.AreEqual(1, c.Products.Count);
Assert.AreEqual(p, c.Products[0]);
}
}
[TestMethod]
public void LoadFromManyToMany()
{
using (var context = new NorthwindClientContext())
{
var c = (from cust in context.Customers.AsQueryable()
where cust.CustomerID == "VINET"
select cust).First();
Assert.AreEqual(0, c.CustomerDemographics.Count);
Assert.AreEqual(0, context.CustomerDemographics.Count);
c.LoadCustomerDemographics();
Assert.AreNotEqual(0, c.CustomerDemographics.Count);
Assert.AreEqual(c.CustomerDemographics.Count, context.CustomerDemographics.Count);
}
}
[TestMethod]
public void LoadFromOneToOne()
{
using (var context = new NorthwindClientContext())
{
var c = context.Customers.AsQueryable().First();
Assert.IsNull(c.Member);
Assert.AreEqual(0, context.Members.Count);
var m = c.LoadMember();
Assert.IsNotNull(c.Member);
Assert.AreEqual(1, context.Members.Count);
Assert.AreEqual(c, m.Customer);
}
}
[TestMethod]
public void OfType()
{
using (var context = new NorthwindClientContext())
{
var employeesInActivity = context.Employees.AsQueryable().OfType<EmployeeInActivity>().ToList();
Assert.AreEqual(employeesInActivity.Count, context.Employees.Count);
Assert.AreEqual(employeesInActivity.Count, context.EmployeeInActivities.Count);
Assert.AreEqual(0, context.OutEmployees.Count);
}
}
[TestMethod]
public void AddIntoBaseEntitySet()
{
using (var context = new NorthwindClientContext())
{
var firedEmployee = new FiredEmployee();
context.Employees.Attach(firedEmployee);
Assert.AreEqual(1, context.Employees.Count);
Assert.AreEqual(1, context.OutEmployees.Count);
Assert.AreEqual(1, context.FiredEmployees.Count);
}
}
[TestMethod]
public void GetAllEntitiesWithInheritance()
{
using (var context = new NorthwindClientContext())
{
var l = context.Employees.AsQueryable().ToList();
Assert.AreEqual(l.Count, context.Employees.Count);
Assert.AreEqual(l.OfType<OutEmployee>().Count(), context.OutEmployees.Count);
Assert.AreEqual(l.OfType<FiredEmployee>().Count(), context.FiredEmployees.Count);
Assert.AreNotEqual(0, context.FiredEmployees.Count);
}
}
[TestMethod]
public void Detach()
{
using (var context = new NorthwindClientContext())
{
var c = new Category { Id = 1 };
context.Categories.Attach(c);
var p = new Product { CategoryID = 1 };
context.Products.Attach(p);
Assert.AreEqual(c, p.Category);
context.Categories.Detach(c);
Assert.IsNull(p.Category);
Assert.AreEqual(c.Id, p.CategoryID);
}
}
[TestMethod]
public void UpdateFK()
{
using (var context = new NorthwindClientContext())
{
var c1 = new Category { Id = 1 };
context.Categories.Attach(c1);
var c2 = new Category { Id = 2 };
context.Categories.Attach(c2);
var p = new Product { CategoryID = 1 };
context.Products.Attach(p);
Assert.AreEqual(c1, p.Category);
Assert.AreEqual(1, c1.Products.Count);
p.CategoryID = 2;
Assert.AreEqual(c2, p.Category);
Assert.AreEqual(0, c1.Products.Count);
Assert.AreEqual(1, c2.Products.Count);
}
}
}
Pour mes tests, j’ai utilisé l’EDM suivant:
En plus d’avoir un vrai contexte côté client, j’ai également procédé à une petite amélioration de l’update. Avec le template self-tracking par défaut, le SQL généré lors d’un update inclut toutes les colonnes mappées sur l’entité même si une seule a été modifiée. Avec mon implémentation, l’update ne va contenir que les colonnes modifiées. A noter que ceci n’est pas vrai pour les complex types. Si une seule propriété du complex type a été modifiée, l’update généré inclura toute les colonnes mappées sur le complex type (c’est une limitation de la version actuelle d’EF).
Pour réduire l’update généré, j’ai ajouté une liste de string ModifiedProperties dans la classe ObjectChangeTracker (pour cela, j’ai mis à jour le template T4 self-tracking types). Ensuite, j’ai également changé le template T4 self-tracking context en remplaçant :
context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
par
context.ObjectStateManager.ChangeObjectState(entity, EntityState.Unchanged);
var ose = context.ObjectStateManager.GetObjectStateEntry(entity);
ose.SetModified();
foreach (var propertyName in entity.ChangeTracker.ModifiedProperties)
ose.SetModifiedProperty(propertyName);
Si vous voulez en savoir plus sur ces templates, je vous donne rendez-vous à ma session sur EF au prochain Microsoft Tech Days à Paris et / ou au confoo à Montreal (en français également).
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :