MVC2 && EF4.0 Cascading Drop Down List

I am trying to create a cascading drop down in MVC2. This is a simple application so I am using Entity Framework 4.0 classes in my User Layer (instead of the usual POCOs).

I looked at Steve’s Walther’s solution(s) here: the problem is that it doesn’t work – you get an object null reference b/c the page isn’t done loading (I think). I tried putting it into JQuery, which I know waits to fire until the DOM is loaded, but I started getting too deep into the port.

I then looked at other people’s attempts like here and here – lots of code, little explanation and it doesn’t work without modifications.

I then went back to a project that I created does an Ajax call for the second drop down and tried to create my own solution.

Here is the initial controller:

1 public JsonResult GetDoctrinesForAnIssue(int issueId) 2 { 3 IDoctrineFactory doctrineFactory = new DoctrineFactory(); 4 List<Doctrine> doctrines = doctrineFactory.GetDoctrines(issueId); 5 return Json(doctrines.ToList()); 6 } 7  

The problem is that I am using an EF class directly in the JSON return. I am getting a missing object context because the entire graph is not loading and the context is disposed when it is going back to rehydrate – one of limitations of EF is that the instantiated class has to exist with the object context that created it so when that context goes away, you are stuck.

image

When I put the entire graph in to see, I got a circular reference error. Ugh

1 var doctrineQuery = (from doctrine in patentEntities.Doctrines 2 .Include("Issue") 3 .Include("Comment") 4 .Include("Comment.Claim") 5 .etc…. 6 select doctrine).ToList<Doctrine>(); 7 return doctrineQuery; 8  

I then thought about some of my other projects that I have worked on lately. I used POCOs extensively so this kind of problem didn’t surface – the downside is that I would then need to code up the POCOs, the Factories, and the mapping between the POCOs and EF classes – which is a bit overkill for this project. I then thought of a third way of using a dynamic object just for this drop down lists – outside of the factory, inside the controller:

1 public JsonResult GetDoctrinesForAnIssue(int issueId) 2 { 3 IDoctrineFactory doctrineFactory = new DoctrineFactory(); 4 var query = (from doctrine in doctrineFactory.GetDoctrines(issueId) 5 select new { doctrine.DoctrineId, doctrine.DoctrineName }).ToList(); 6 7 return Json(query); 8 } 9  

Add a little LINQ and boom goes the dynamite…

TDD using Interfaces

One of the tenants of TDD is that the tests are written, well, first.  The biggest problem I have with writing the tests first is one of developer productivity.  Call me a slave to tooling, but I really use intellisense when I code, so much to the point that I don’t even realize that I am using it.  With TDD, I can’t use Intellisense because the object has not been written yet.  As a way out of this problem, I thought of using interfaces.  I write the interface, write the test, then write the class under test.  I thought I would put my theory to the test with a basic example.  I created an interface like so:

1 using System; 2  using System.Collections.Generic; 3  using System.Linq; 4  using System.Text; 5  using Com.Tff.Patent.Data; 6 7  namespace Com.Tff.Patent.Domain 8 { 9 public interface IDoctrineFactory 10 { 11 static Doctrine GetDoctrine(int doctrineId); 12 static List<Doctrine> GetDoctrines(); 13 static List<Doctrine> GetDoctrines(int issueId); 14 } 15 } 16  

I then created a test like so:

1 [TestMethod] 2 public void GetDoctineReturnsCorrectValue() 3 { 4 IDoctrineFactory.GetDoctrine(1); 5 string expected = "aaa"; 6 string actual = doctrine.DoctrineName; 7 Assert.AreEqual(expected, actual); 8 9 } 10

However, I got a compiler error:

1 Error 1 The modifier 'static' is not valid for this item 2 3 Error 2 The modifier 'static' is not valid for this item 4 5 Error 3 The modifier 'static' is not valid for this item 6 7

That’s right – interfaces can’t be marked as static.  So then I thought of newing up a class in my test:

1 IDoctrineFactory doctrineFactory = new IDoctrineFactory(); 2 doctrineFactory.GetDoctrine(1); 3

The fact that I didn’t get intellisense was my first clue. The compiler error was my second:

1 Error 3 Cannot create an instance of the abstract class or interface

So then I created a concrete class using the refactoring tools in VS2010:

1 public class DoctrineFactory: IDoctrineFactory 2 { 3 public Data.Doctrine GetDoctrine(int doctrineId) 4 { 5 throw new NotImplementedException(); 6 } 7

This is better – I will get red b/c I have not implemented my methods yet – and I get intellisense in my unit tests. So for me, TDD is:

  • Write interface
  • Implement interfaces via VS2010
  • Write tests to get red
  • Write code logic to get to green

That way I get the intent behind TDD with modern tooling support.

Carpool Project: Part #15

I finished the carpool website – here is a quick summary of things I learned:

· Unit tests can’t depend on db data – refactoring violate data sucks

· I need to refactor my Unit Tests

· I need to learn more about MVC gators

· I need to learn more on LINQ

· Flattened POCOs are not needed in MVC

I also realized:

· Only having 5-6 custom categories in Live.Spaces sucks

· You need unique names for your photos in Live.Spaces. I was overwriting earlier posts’ pictures when I added new posts that had the same picture name

My next project will be taking the carpool project and making it a WM application.

Note that my Live.Spaces blog was moved to WordPress in October.  The formatting was so screwed up I just re-published the content.  I am using Live.Writer with a couple of plug-ins – which works well enough.

Carpool Project: Part #14

I had a new requirement pop up today. Seems that some users only want to see the carpools/practices that their kids are in – versus the entire set. Using my Alot based design, I wanted a function where the userName came in and the week’s carpools came out. I added the needed table (DriverSwimmer) to make the association between the user and swimmers and then though about my LINQ. I first coded up this solution:

1 public static List<Carpool> GetCarpools(DateTime startDate, DateTime endDate, string userName) 2 { 3 List<Carpool> carpools = new List<Carpool>(); 4 5 using (CarpoolEntities carpoolEntity = new CarpoolEntities()) 6 { 7 var carpoolQuery = (from carpool in carpoolEntity.Carpool_Carpool 8 .Include("Carpool_Driver") 9 .Include("Carpool_Driver.Carpool_DriverSwimmer") 10 .Include("Carpool_CarpoolSwimmer") 11 .Include("Carpool_CarpoolSwimmer.Carpool_Swimmer") 12 .Include("Carpool_CarpoolPractice") 13 .Include("Carpool_CarpoolPractice.Carpool_Practice") 14 .Include("Carpool_CarpoolPractice.Carpool_Practice.Carpool_SwimGroupPractice") 15 .Include("Carpool_CarpoolPractice.Carpool_Practice.Carpool_SwimGroupPractice.Carpool_SwimGroup") 16 .Include("Carpool_CarpoolPractice.Carpool_Practice.Carpool_SwimGroupPractice.Carpool_SwimGroup.Carpool_SwimTeam") 17 where carpool.CarPoolDate >= startDate 18 && carpool.CarPoolDate <= endDate 19 && carpool.Carpool_Driver.UserName == userName 20 orderby carpool.CarPoolDate 21 select carpool); 22 foreach (Carpool_Carpool carpool_carpool in carpoolQuery) 23 { 24 carpools.Add(MapCarpool(carpool_carpool)); 25 } 26 string s = EntityExtensionMethods.CustomExtensions.ToTraceString(carpoolEntity); 27 28 } 29 return carpools; 30 31 32 } 33  

The problem is that nothing is coming back. When I looked at the SQL being generated, it was null. I wonder if there are some phrases that are so complex that EF can’t figure it out. I thought of a great product/tool – you put in the sql you want and out comes the Linq. In any event, I decided to take a shortcut – I would get a large result set back and just parse it down for the user info.

1 var query = (from s in swimmers 2 select s.SwimGroup).Distinct(); 3 List<SwimGroup> swimGroups = query.ToList<SwimGroup>(); 4  

I combined to:

1 List<SwimGroup> swimGroups = ((from s in swimmers 2 select s.SwimGroup).Distinct()).ToList<SwimGroup>(); 3  

And then I wrote this:

1 var x = (from c in carpools 2 select c.Practices).ToList<Practice>(); 3  

and got the following error:

1 'System.Collections.Generic.IEnumerable<>' does not contain a definition for 'ToList' and the best extension method overload 'System.Linq.ParallelEnumerable.ToList<TSource>(System.Linq.ParallelQuery<TSource>)' has some invalid arguments

Apparently, ToList<>() does not have a ToList<>() method. I changed it to:

1 List<Practice> practices = (List<Practice>)(from c in carpools 2 select c.Practices); 3  

And the compiler was happy

I then completed my 1st attempt: note that I have 2 sets of swimgroups – those associated with the drivers (via their swimmers) and those associated with the practices (via their carpool):

1 public static List<Carpool> GetCarpools(DateTime startDate, DateTime endDate, string userName) 2 { 3 List<Swimmer> swimmers = DriverFactory.GetDriver(userName).Swimmers; 4 List<SwimGroup> driverSwimGroups = ((from s in swimmers 5 select s.SwimGroup).Distinct()).ToList<SwimGroup>(); 6 7 8 List<Carpool> carpools = GetCarpools(startDate, endDate); 9 List<Practice> practices = (List<Practice>)(from c in carpools 10 select c.Practices); 11 List<SwimGroup> practiceSwimGroups = (List<SwimGroup>)((from p in practices 12 select p.SwimGroups).Distinct()); 13 14 return null; 15 16 } 17  

 

I then needed to compare the swimGroup list – if they are in both, then the carpool should be returned like this:

1 List<SwimGroup> commonSwimGroups = (List<SwimGroup>)practiceSwimGroups.Union(driverSwimGroups);

However, I didn’t use this. I kludged up a 5-deep for..each nest of spaghetti code:

1 public static List<Carpool> GetCarpools(DateTime startDate, DateTime endDate, string userName) 2 { 3 List<Swimmer> swimmers = DriverFactory.GetDriver(userName).Swimmers; 4 List<SwimGroup> driverSwimGroups = ((from s in swimmers 5 select s.SwimGroup).Distinct()).ToList<SwimGroup>(); 6 7 List<Carpool> carpools = GetCarpools(startDate, endDate); 8 9 10 List<Carpool> returnValue = new List<Carpool>(); 11 foreach(Carpool carpool in carpools) 12 { 13 foreach (Practice practice in carpool.Practices) 14 { 15 foreach (SwimGroup practiceSwimGroup in practice.SwimGroups) 16 { 17 foreach (SwimGroup driverSwimGroup in driverSwimGroups) 18 { 19 if (practiceSwimGroup == driverSwimGroup) 20 { 21 returnValue.Add(carpool); 22 } 23 } 24 } 25 } 26 } 27 28 return returnValue; 29  

I have to believe there is a better way with some LINQ. I will investigate – until then, at least it is working…

Carpool Project: Part #13

I am closer to the end of the development cycle than the beginning and I have run into a new problem. I created a method that Inserts new practices in the PracticeFactory. When I test it against the server, I get the following error

1 Test method Com.Tff.Carpool.Domain.Tests.PracticeFactoryTest.InsertPracticeTest threw exception: 2 System.Data.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value. 3 The statement has been terminated. 4  

I searched MSDN/StackOverflow and I came up with the EF needing to be 2005, not 2008 (here) I switched it and got the same problem. This solution doesn’t make sense to me – b/c the data server is 2008. I then decided to look at the SQL that EF is generating to see if I can find an error in that code. There is a method called ToTraceString() that I can use to inspect the SQL generated – the trick is to locate what object the method belongs to – since it is not part of ObjectContext. The MSDN example here is not much help – I wonder if EF does not expose the method? In addition, I can’t set up tracing on the remote server – it is hosted on WinHost. I then found this post which solved the problem – it is just a feature gap in EF.

Once I had this code up and running, I looked at the results:

1 insert [dbo].[Carpool_Practice]([PracticeDate], [PracticeStartTime], [PracticeEndTime], [DrylandIndicator]) 2 values (@0, @1, @2, @3) 3 select [PracticeId] 4 from [dbo].[Carpool_Practice] 5  where @@ROWCOUNT > 0 and [PracticeId] = scope_identity() 6 @0 = 9/13/2010 7:17:53 AM 7 @1 = 1/1/0001 12:00:00 AM 8 @2 = 1/1/2010 7:00:00 PM 9 @3 = True 10  

And here is the bug:

1 private static void MapPractice_Practice(Carpool_Practice practiceToInsert, Practice practice) 2 { 3 practiceToInsert.DrylandIndicator = practice.DryLandIndicator; 4 practiceToInsert.PracticeDate = practice.Date; 5 practiceToInsert.PracticeEndTime = practice.EndTime; 6 practiceToInsert.PracticeStartTime = practiceToInsert.PracticeStartTime; 7 } 8  

I changed it to this:

1 practiceToInsert.PracticeStartTime = practice.StartTime;

And it ran. I was assigning the EF value to itself.

<Sound of me slapping my forehead>

Carpool Project: Part #12

I am working though the basic CRUD of EF/Factory and I ran into an issue. I coded

1 public static void DeleteCarpool(Carpool carpool) 2 { 3 using (CarpoolEntities carpoolEntity = new CarpoolEntities()) 4 { 5 var carpoolToDelete = (from cp in carpoolEntity.Carpool_Carpool 6 where cp.CarPoolId == carpool.Id 7 select cp).First(); 8 9 carpoolEntity.DeleteObject(carpoolToDelete); 10 carpoolEntity.SaveChanges(); 11 } 12 } 13  

 

And I got the following error in my unit test:

Carpool68

I then realized I didn’t cascade the changes on the server. I thought EF handled that for me – I guess not. I changed it in SQL Server:

Carpool69

And things ran like a champ….

Carpool Project: Part #11

I wanted to have a list of all of the swimmers NOT associated with a carpool. I got a list of all swimmers and then a list of all swimmers in carpool. I first started doing some nested For..Each and quickly realized I was doing something wrong. I went to 101 LINQ Samples and got a much better implementation (sample #52). I whipped this code:

1 public static List<Swimmer> GetNonCarpooledSwimmers(int carpoolId) 2 { 3 List<Swimmer> allSwimmers = SwimmerFactory.GetAllSwimmers(); 4 List<Swimmer> carpooledSwimmers = CarpoolFactory.GetCarpool(carpoolId).Swimmers; 5 return allSwimmers.Except(carpooledSwimmers).ToList<Swimmer>(); 6 } 7  

and ran a test:

Carpool67

Red! Dangnabbit.

I went to the definition of Except and realized that I did not implement a custom GetHashCode or Equals() for Swimmer. I popped this code into my Swimmer class:

1 2 public override int GetHashCode() 3 { 4 return this.Id; 5 } 6 7 public override bool Equals(object obj) 8 { 9 Swimmer other = obj as Swimmer; 10 if (other == null) 11 { 12 return base.Equals(obj); 13 } 14 else 15 { 16 if (other.Id == this.Id) 17 { 18 return true; 19 } 20 else 21 { 22 return false; 23 } 24 25 } 26 } 27  

 

And things ran like a champ…

Carpool Project: Part #10

I went back to the update of the Carpool Controller and changed the view to include the Driver like so:

Carpool62

I then updated the driverId to see if the changes propagate. The new value is in the form collection:

Carpool63

But after running UpdateView(), the new value is dropped.

Carpool64

Apparently, only the top-level properities are affected by UpdateView? Ugh – between the date/time conflict the nested properties, UpdateView only is useful for the most basic scenarios. I’ll replace UpdateView with a method that I write.

I thought about using Reflection like so (this is not right):

1 private void UpdateCarpoolFromFormCollection(Carpool.Domain.Carpool carpool, FormCollection collection) 2 { 3 4 PropertyInfo[] propertyInfos = carpool.GetType().GetProperties(); 5 foreach (PropertyInfo propertyInfo in propertyInfos) 6 { 7 for (int i = 0; i < collection.Count; i++) 8 { 9 if (propertyInfo.Name == collection[i].ToString()) 10 { 11 propertyInfo.SetValue(carpool,collection[i],null); 12 } 13 } 14 } 15 16 } 17  

I realized I really don’t understand the FormCollection object and how to enumation (or write some LINQ) to pull the correct value out of it. I then realized that I am being stupid. Of course the MVC creators would allow for next properities. I wrote a quick hello world app and sure enough, the changes are coming down:

Carpool65

The difference is the “.”. In my carpool solution, the Carpool.Drver is somehow turning into CarpoolDriver:

Carpool66

Changing this

1 <div class="editor-label"> 2 <%: Html.LabelFor(model => model.Driver.Id) %> 3 </div> 4 <div class="editor-field"> 5 <%= Html.TextBox("carpoolDriverId", Model.Driver.Id)%> 6 <%: Html.ValidationMessageFor(model => Model.Driver.Id)%> 7 </div> 8  

To This

1 2 <div class="editor-label"> 3 <%: Html.LabelFor(model => model.Driver.Id) %> 4 </div> 5 <div class="editor-field"> 6 <%: Html.TextBoxFor(model => model.Driver.Id)%> 7 <%: Html.ValidationMessageFor(model => model.Driver.Id)%> 8 </div> 9  

 

And boom goes the dynamite…

Carpool Project: Part #9

I started with the View a bit more and I ran into an issue that cuts to the heart of D3 and SOC. On my Carpool page, I want a grid of all practices that are associated with the car pool (usually 1, but could be more). In the view, I wrote this (headers omitted for brevity):

1 <% foreach (Com.Tff.Carpool.Domain.Practice practice in Model.Practices) 2 { %> 3 <tr> 4 <td> 5 <%: practice.Id%> 6 </td> 7 <td> 8 <%: practice.Date%> 9 </td> 10 <td> 11 <%: practice.DryLandIndicator%> 12 </td> 13 <td> 14 <%: practice.EndTime%> 15 </td> 16 <td> 17 <%: practice.StartTime%> 18 </td> 19 <td> 20 <% foreach (Com.Tff.Carpool.Domain.SwimGroup swimGroup in practice.SwimGroups) 21 { %> 22 <%: swimGroup.Name%> 23 <% } %> 24 </td> 25 <td> 26 <%: Html.ActionLink("Edit", "Edit", new { practiceId = practice.Id })%> 27 <%: Html.ActionLink("Delete", "Delete", new { PracticeId = practice.Id })%> 28 </td> 29 </tr> 30 31 <% } %> 32  

And it comes out with the expected HTML:

carpool32

Notice how the Swim Group is joined together using that secondary loop. This got me thinking, part of the reason I crated the ViewModel POCOs was to do this kind of flattening. If the UI can handle it easily, why not use EF-enabled POCOs and save the who Domain Layer step of mapping the EF Classes to the POCO ones? If all I had to worry about was the flattening of Swim Groups to practices, perhaps writing that join in the UI is better than the Domain Layer. Then I thought – NO. The domain layer should be responsible for serving objects, even if the UI can handle it. I would say that is analogous to “we can put the code in the code-behind in Web Forms.” Eventually, the code needs to be written – so I would rather have it in the Domain layer where I have exact control and can add in any custom logic. If any custom logic for the flattening happens, the UI will quickly become a morass of spaghetti. On a side note, I find writing C# is much much better than writing WebForms View Engine code – those gators drive me nuts.

Saying that, I realized I don’t need a carpool controller, I need a CarpoolSummary controller and view -> for the simple reason that Carpools don’t have PracticeSummaries – CarpoolSummaries do. Time to do some re-writing!

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?