LINQ: Many paths to the same end

One of the real draws to using LINQ is that it affords many solutions to a single problem.  This can be good when finding the most performant code, and this flexibility helped me around an error with another API.

I have a Entity Framework data model of a swim team with 1 Gender and 1 Family having many swimmers and 1 swimmer being a part of many seasons.  Entity framework has some pluses (what with that cool designer, a unified model for all data sources, etc…) but what it does not do well is respond to change.  In this case, GenderId and FamilyId started as scaler properties of the Swimmer Class but then I changed them into association properties on the server using foreign keys.  Updating the model via the designer worked well enough (though you do need to remove the properties of any field you drop by hand) but the problem came in the LINQ.

I wanted to query all swimmers who were in a certain season.  I wrote the query like so: 

            var query = (from ss in CurrentContext.tblSwimmerSeasons

                         .Include("tblSwimmers")

                         .Include("tblSwimmers.tblGenders")

                         .Include("tblSwimmers.tblFamily")

                         where ss.tblSeason.SeasonID == 1

                         select ss.tblSwimmer);

Notice that I am using eager loading on the lookup tables.  The problem was that tblGenders and tblFamily come back null every time for every record.  Since I have done this exact query before, my guess is that the designer somehow is screwing up the SQL that it is generating because of the changes I made.   

The first way out of the problem is to use lazy loading like this: 

            foreach (var item in query)

            {

                item.tblFamilyReference.Load();

                item.tblGenderReference.Load();

                //etc…

            }

However, the performance problems with the multiple server round-trips makes this an unrealistic solution with a data set of any size. My next though was to use Entity-SQL but I really don’t want to mix languages in my solution for the sake of consistency.  I then realized that the select statement was forcing the data load in the Select in the SQL being generated so all I had to do was be explicit in the tables I wanted:

            var query = (from ss in CurrentContext.tblSwimmerSeasons

                         where ss.tblSeason.SeasonID == currentSeason

                         select new { ss.tblSwimmer, ss.tblSwimmer.tblGender,

                         ss.tblSwimmer.tblFamily });

 

worked like a charm.

After reading up a bit, my understanding is that the new Entity Designer in 4.0 will be more capable with changes – let’s hope so.

Advertisements

Where to place the code?

I had a theoretical discussion with a development team lead yesterday that had some practical implications.  He has a class like so:

    public class Person

    {

        public int PersonId { get; set; }

        public string PersonName { get; set; }

        public string LastUpdateUser { get; set; }

        public DateTime LastUpdateDate { get; set; }

 

    }

And a Factory (Builder, really) with the usual get and update interface like so:

    public class PersonFactory

    {

        public static Person GetPerson()

        {

            //Implementation

        }

 

        public static void UpdatePerson(Person person)

        {

            //Implementation

        }

    }

He then had a webpage with an ObjectDataSource and DetailsView. 

The crux of the discussion surrounding the LastUpdateId and LastUpdateTime and where to populate that value.  On one hand, the business layer is responsible for controlling the data so  it makes sense for the lastUpdateDate to be popualted in the Update Method of the Factory like so:

person.LastUpdateDate = DateTime.Now;

However, how do you update the LastUpdateUser in the business layer?   You would need to change the interface of the Update method to be something like this:

        public static void UpdatePerson(Person person, string lastUpdateUser)

        {

            //Implementation

        }

Which smells like Interface polution and certainly more regid than I would want.

On the other hand, you can populate the Person object in the UI via the code behind fairly easily:

protected void ObjectDataSource1_Updating(object sender,

            ObjectDataSourceMethodEventArgs e)

        {

            Person person = e.InputParameters[0] as Person;

            person.LastUpdateId = User.Identity.Name;

            person.LastUpdateDate = DateTime.Now;

 

        }

And I love easy.  In addition, just because you don’t code it doesn’t mean it doesn’t exist.  In this case, the Details View and ODS are responsible for hydrating the values of the Person object from the values in the controls (persisted across sessions by the view state) so it actually is more consistent to populate the values in the code-behind on the UI than in the data layer.

The point is, the code has to be written somewhere so why not put it in a place that is both consistant and keeps your Business Layer’s API clean?

Validation Block – Conditional Validation Redux

You can see my initial thoughts on conditional validation here.  I have a follow-up problem that required a different approach (and a Kludge).  The regular expression solution attribution validation solution only works for the single property.  What about validation for Two (or many) properties?  For example, assume you have a Person Class like so:

    public class Person

    {

        public int PersonId { get; set; }

        public string PersonName { get; set; }

        public DateTime DateOfBirth { get; set; }

        public DateTime DateOfDeath { get; set; }

 

 

        public override string ToString()

        {

            return PersonName;

        }

    }

Adding some simple attribute validation gives us this:

    public class Person

    {

        public int PersonId { get; set; }

        [StringLengthValidator(10, MessageTemplate = "Name is 10 characters")]

        public string PersonName { get; set; }

        [DateTimeRangeValidator(DateTime.Today, MessageTemplate = "Can’t be born in the future")]

        public DateTime DateOfBirth { get; set; }

        public DateTime DateOfDeath { get; set; }

 

 

        public override string ToString()

        {

            return PersonName;

        }

    }

But I have one more validation I need to implement – a person can not have a DateOfDeath before their DateOfBirth.

My First thought was to in-line a DateTimeRangeValidator like so

        [DateTimeRangeValidator(this.DateOfBirth, MessageTemplate = "You Can’t Die Before You are Born")]

        public DateTime DateOfDeath { get; set; }

However, you get this error – Keyword this is not available in the Current Context

 Note that you CAN do it for static fields, but that won’t help with 95% of the DTOs out there because DTOs are usually implemented as instance members – especially in a web solution.

 

My next thought was to use Self-Validation like so:

    [HasSelfValidation]

    public class Person

    {

        public int PersonId { get; set; }

        [StringLengthValidator(10, MessageTemplate = "Name is 10 characters")]

        public string PersonName { get; set; }

        [DateTimeRangeValidator(DateTime.Today, MessageTemplate = "Can’t be born in the future")]

        public DateTime DateOfBirth { get; set; }

        public DateTime DateOfDeath { get; set; }

 

        [SelfValidation]

        public void CheckDates(ValidationResults results)

        {

            if (DateOfBirth > DateOfDeath)

            {

                ValidationResult validationResult = new ValidationResult("DOB > DOD",

                    this, string.Empty, string.Empty, null);

                results.AddResult(validationResult);

            }

        }

 

        public override string ToString()

        {

            return PersonName;

        }

    }

This works fine in unit testing.  The problem is that the PropertyProxyValidation in ASP.NET solutions do not work with conditional validation – they only work with Attribute-based validation.  I seemed to be stuck (and I still am, really) so I came up with a Kludge.

I added a validator to the DateOfDeath Property like so:

        [DateTimeRangeValidator("1900-01-01T00:00:00", MessageTemplate = "You Can’t Die Before You are Born", Ruleset

        = "Zombie")]

        public DateTime DateOfDeath { get; set; }

 

Note the addition of the ruleset.

I then added a PropertyProxyValidator to the DateOfDeath field with the enabled Property set to false:

 

I then created a method in the code-behind of the web-page creates a new instance of the Person class using the fields from the web form and runs validation.   You need to run this validation before any data binding to keep in align with the Page lifecycle.

 

        private void BirthDeathDateValidation()

        {

            TextBox textBoxPersonId = this.DetailsView1.FindControl("TextBox4") as TextBox;

            TextBox textBoxPersonName = this.DetailsView1.FindControl("TextBox2") as TextBox;

            TextBox textBoxPersonDOB = this.DetailsView1.FindControl("TextBox1") as TextBox;

            TextBox textBoxPersonDOD = this.DetailsView1.FindControl("TextBox3") as TextBox;

 

 

                Person person = new Person();

                person.PersonId = Int32.Parse(textBoxPersonId.Text);

                person.PersonName = textBoxPersonName.Text;

                person.DateOfBirth = DateTime.Parse(textBoxPersonDOB.Text);

                person.DateOfDeath = DateTime.Parse(textBoxPersonDOD.Text);

 

                Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults results =

                    new Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults();

                person.CheckDates(results);

 

                if (results.Count > 0)

                {

                    PropertyProxyValidator propertyProxyValidator =

                        this.DetailsView1.FindControl("PropertyProxyValidator3") as PropertyProxyValidator;

                    propertyProxyValidator.RulesetName = "Zombie";

                    propertyProxyValidator.Enabled = true;

                }

            }

 

        }

 

Now, if the DateOfDeath happensbefore DateOfBirth, the ruleset is switched to the appropriate ruleset and the validator is enabled.

 

Like I said, a Kludge, but I don’t see a better option.

Unit Testing and DTOs

I have been studying for the MCPD-Enterprise 3.5 exam this last week so I have been going though MSFT’s training materials.  I started with the 70-561 book and I noticed that each of the examples include a Unit Test.  I thought this was really cool – it is the 1st training kit I have seen that integrated Unit Tests.

 

MCTS Self-Paced Training Kit (Exam 70-561): Microsoft .NET Framework 3.5 - ADO.NET

Speaking of Unit Tests, I also have been playing around with Unit Testing in a side project that I have.  I built a dedicated DTO class (complete with Ent Lib validation), built my 1st factory method that serves up the DTO (CRUD and collections), and then created a Unit Test to test the Get Method.

I figured out quickly that reference types do not work like this:

            int AgeGroupId = 1;

AgeGroup expected = new AgeGroup(1, "Boys 6 And Under", "6 And Under", 1, "15 Yards", 1, "Male", 1);

            AgeGroup actual = AgeGroupFactory.GetAgeGroup(AgeGroupId);

Assert.AreEqual(expected, actual);

 

Because they are two different pointers pointing to two different locations on the heap.  I then thought about comparing each property like so:

 

            Assert.AreEqual(expected.AgeGroupId, actual.AgeGroupId);

            Assert.AreEqual(expected.AgeGroupDesc, actual.AgeGroupDesc);

            //ETC…

 

But that seemed like a huge pain to code each property.

Next, I thought about implementing the IEquatable<T> interface and build something like:

Assert.IsTrue(expected.Equals(actual));

But then I am still coding each property – though it is in a better place.  Finally, I thought about using the ToString() method that I already implemented in the DTO.  That worked the best for me – primarily because I had already coded it and I only added in the properties that are unique/important.

Assert.AreEqual(expected.ToString(), actual.ToString());

I might go back to the IEquatable<T> interface in the future – just to make the API more predictable.

I wonder how Mocking handles this – I will know more about that once I implement MOQ in my project (next month hopefully…)

ASP Menu Trimming

I am on vacation this week but I wanted to share something that I found regarding ASP.NET Menu Trimming.  I was having a hard time understanding how the sitemap and the authorization section of the web.config work togeather.  This post gave the best explination of how it all works togeather.