Carpool Project: Part #8

I am working on the Update features of the Carpool Factory. The biggest problem with using POCOs that are not automatically hooked up with EF classes is that you have to do the mapping back to the EF classes. Going from EF to POCO is straight forward – putting them back in is a different story.

I had 3 different challenges

#1) Assign properties to the main class. That was straight forward:

1 private static void MapCarpool_Carpool(Carpool_Carpool carpool_carpool, Carpool carpool) 2 { 3 carpool_carpool.CarPoolDate = carpool.Date; 4 carpool_carpool.SwimmerCapacity = carpool.SwimerCapacity; 5 carpool_carpool.TimeBack = carpool.ReturnTime; 6 carpool_carpool.TimeLeaving = carpool.LeaveTime; 7 } 8  

#2) Assign properties to another one-to-one class in the graph. The was also straight forward, with the caveat that you need to use the same EF conext for the entire graph so you need to pass that into the function:

1 private static void MapCarpool_CarpoolDriver(Carpool_Carpool carpool_carpool, Carpool carpool, CarpoolEntities carpoolEntity) 2 { 3 var selectedDriver = (from driver in carpoolEntity.Carpool_Driver 4 where driver.DriverID == carpool.Driver.Id 5 select driver).First(); 6 carpool_carpool.Carpool_Driver = selectedDriver; 7 } 8

#3) Assign properties to a collection of one-to-many classes in the graph. I tried a couple of different ways to do this with the least amount of code. The problem is that the collection could have had adds and deletes on the client that need to be synched up to the server:

Client   Server
    SwimmerA
SwimmerB   SwimmerB
SwimmerC   SwimmerC
SwimmerD    

My first thought was to clear the EF Collection and then then add in the POCOs like so:

1 carpoolToUpdate.Carpool_CarpoolPractice.Clear(); 2 3 Carpool_CarpoolPractice carpool_carpoolPractice = null; 4 5 foreach (Practice practice in carpool.Practices) 6 { 7 carpool_carpoolPractice = new Carpool_CarpoolPractice(); 8 carpool_carpoolPractice.CarpoolId = carpool.Id; 9 carpool_carpoolPractice.PracticeId = practice.Id; 10 carpoolToUpdate.Carpool_CarpoolPractice.Add(carpool_carpoolPractice); 11 } 12

 

The problem is that I could not clear the collection b/c of a referential constraint, even though I immediately re-added new objects before the Update method to the server.

1System.InvalidOperationException was unhandled by user code 2 Message=The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted. 3 Source=System.Data.Entity 4

Some digging found this article which explained why.

So then I thought to enumerate though the collection and remove each one and then the POCOs in. A couple more lines of code but that did the trick for adding the practice. Here is the code:

1 //Remove 2 foreach (Carpool_CarpoolPractice carpool_carpoolPracticeToDelete in carpoolEntity.Carpool_CarpoolPractice) 3 { 4 carpoolEntity.DeleteObject(carpool_carpoolPracticeToDelete); 5 } 6 7 //Add 8 Carpool_CarpoolPractice carpool_carpoolPracticeToAdd = null; 9 foreach (Practice practice in carpool.Practices) 10 { 11 carpool_carpoolPracticeToAdd = new Carpool_CarpoolPractice(); 12 carpool_carpoolPracticeToAdd.CarpoolId = carpool.Id; 13 carpool_carpoolPracticeToAdd.PracticeId = practice.Id; 14 carpoolToUpdate.Carpool_CarpoolPractice.Add(carpool_carpoolPracticeToAdd); 15 } 16

And here is the test:

1 [TestMethod()] 2 public void AddCarpoolPracticeTest() 3 { 4 Carpool carpool = CarpoolFactory.GetCarpool(1); 5 int notExpcted = carpool.Practices.Count; 6 7 Practice practice = PracticeFactory.GetPractice(2); 8 carpool.Practices.Add(practice); 9 CarpoolFactory.UpdateCarpool(carpool); 10 11 carpool = CarpoolFactory.GetCarpool(1); 12 int actual = carpool.Practices.Count; 13 14 Assert.AreNotEqual(notExpcted, actual); 15 } 16

 

The problem is the removal of the practice. I wrote this test:

1 [TestMethod] 2 public void DeleteCarpoolPracticeTest() 3 { 4 Carpool carpool = CarpoolFactory.GetCarpool(1); 5 int notExpcted = carpool.Practices.Count; 6 7 Practice practice = PracticeFactory.GetPractice(2); 8 carpool.Practices.Remove(practice); 9 10 CarpoolFactory.UpdateCarpool(carpool); 11 12 carpool = CarpoolFactory.GetCarpool(1); 13 int actual = carpool.Practices.Count; 14 15 Assert.AreNotEqual(notExpcted, actual); 16 } 17

 

And got the following fail:

carpool29

I need to add a comparable to the practice so that the remove recognize practices with the same PracticeId as the same.

1 public class Practice : ValidationBase, IEquatable<Practice> 2 { 3 public int Id { get; set; } 4 public DateTime Date { get; set; } 5 public DateTime StartTime { get; set; } 6 public DateTime EndTime { get; set; } 7 public bool DryLandIndicator { get; set; } 8 public List<SwimGroup> SwimGroups { get; set; } 9 10 public bool Equals(Practice other) 11 { 12 if (other.Id == this.Id) 13 return true; 14 else 15 return false; 16 17 } 18 } 19

 

And then the remove worked like a champ. This led me to my next (and last of the morning) thought – should I implement IEquiatable on the base abstract class (Validation Base) since all of the derived classes have a PK. If so, how would I implement that? I’ll do some research. Until then, my Carpool class now looks like it is ready for Updates. Unfortunately, looks are deceiving…

I started making my UI a bit more user-friendly. I put on a jQuery date picker for the carpool start date. I verified that the new date was being passed into the controller via the FormCollection (it was), but then the UpdateModel is reverting the change:

carpool30

And

carpool31

Oddly, the Update work for date/time values. I guess it cannot handle having a date without a time. I added a new line of code to handle this case:

1 try 2 { 3 Carpool.Domain.Carpool carpool = CarpoolFactory.GetCarpool(carpoolId); 4 UpdateModel(carpool); 5 carpool.Date = DateTime.Parse(collection[2].ToString()); 6 CarpoolFactory.UpdateCarpool(carpool); 7 return RedirectToAction("Index"); 8 } 9

 

Yuck, but it is the easiest way. Perhaps in the UI I can format the input?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: