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.


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:


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:


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:


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…