Wednesday, March 10, 2010

PLINQO @ Houston DNUG

The CodeSmith Tools (Shannon and Tom) are back on the road and delivering their first presentation of the new decade, in Houston!

If you or any developers that you know will be in the Houston area on Thursday, March 11th, you should come see us and learn more about PLINQO, the replace and enhance alternative for LINQ to SQL!

Houston Dot Net User Group
Topic: PLINQO - Supercharged LINQ To SQL
Speakers: Shannon Davidson & Tom DuPont
Date: March 11th @ 6:30 PM
Where: Microsoft Houston Meeting Facility
Address: One Briar Lake Plaza 2000 W. Sam Houston Pkwy. S. #350 Houston, TX 77042

Wednesday, February 17, 2010

Advanced PLINQO Future Queries, Part 2

The immediate uses of PLINQO Future Queries are readily apparent: Do you have multiple queries that need to be executed back to back? Add future to the back of them and save yourself a few database trips.

What might not be quite as easy to spot, are those places where using a more advanced design pattern can really enhance your application's performance. Here is an example of one of those patters.

Part 2: Pipeline Loader Patter

There are many times when an application needs to process a series of independent actions, each requiring its own set of database objects. If using LINQ to SQL (prior to PLINQO), this would mean that you need to either hard code the loading of all the necessary data in one place, or allow each action to load its own data in succession; thus leaving you with the options of bad abstraction, or lack of optimization; neither of which are very desirable.

Using the PLINQO Future Queries in conjunction with some simple interfaces, you can create a pipeline system that allows your actions to share one single data loading session. As usual, I feel that code narrates this best: 

Use Case

[Test]
public void Test()
{
   var actions = new List<IPipelineLoader>
   {
       new CaseAction { CaseId = "A", Title = "First New Title" },
       new CaseAction { CaseId = "A", Title = "Second New Title" },
       new UserAction { UserId = 1, Title = "Senior Tester" },
       new UserAction { UserId = 2, Title = "Junior Tester" }
   };

   using (var db = new DemoDataContext())
   {
       actions.ForEach(a => a.Load(db));
       db.ExecuteFutureQueries();
       actions.ForEach(a => a.Process());
       db.SubmitChanges();
   }
}

Interface

public interface IPipelineLoader
{
   void Load(DemoDataContext db);
   void Process();
}

Implementation

public class CaseAction : IPipelineLoader
{
   private FutureValue<Case> _futureCase;

   public string CaseId { get; set; }
   public string Title { get; set; }

   public void Load(DemoDataContext db)
   {
       _futureCase = db.Case.ById(CaseId).FutureFirstOrDefault();
   }

   public void Process()
   {
       _futureCase.Value.Title = Title;
   }
}

public class UserAction : IPipelineLoader
{
   private FutureValue<User> _futureUser;

   public int UserId { get; set; }
   public string Title { get; set; }

   public void Load(DemoDataContext db)
   {
       _futureUser = db.User.ById(UserId).FutureFirstOrDefault();
   }

   public void Process()
   {
       _futureUser.Value.Title = Title;
   }
}

Wednesday, February 10, 2010

Advanced PLINQO Future Queries, Part 1

The immediate uses of PLINQO Future Queries are readily apparent: Do you have multiple queries that need to be executed back to back? Add future to the back of them and save yourself a few database trips. What might not be quite as easy to spot, are those places where using a more advanced design pattern can really enhance your application's performance. Here is an example of one of those patters.

Part 1: Entity Loaders

When retrieving entities from the database you can not always use DataLoadOptions to populate the complete object model in a single trip to the database. Having to make multiple trips to populate one type of entity can be costly, and this can be compounded by the need to populate a series of different entities at the same time.

One solution is to create a loader class for your entities that use future queries to get their data, as this is a very reliable means with which to ensure that no extra unnecessary database calls are execute. Also, by creating an interface for these loader classes, you can use a generic piece of code to load any number of entities of any number of data types.

Use Cases

[Test]
public static Case Test(int id)
{
    var loader = new CaseTagLoader(id);
    loader.Load();
    return loader.Entity;
}

[Test]
public static List<Case> Test(int[] ids)
{
    var loaders = new List<CaseTagLoader>();
    foreach (var id in ids)
        loaders.Add(new CaseTagLoader(id));

    using (var db = new BlogDataContext())
    {
        loaders.ForEach(l => l.Load(db));
        db.ExecuteFutureQueries();
    }

    return loaders.Select(l => l.Entity).ToList();
}

Interface

public interface ILoader<T>
{
    void Load();
    void Load(BlogDataContext db);
    T Entity { get; }
    bool IsLoaded { get; }
}

Implementation

public class CaseTagLoader : ILoader<Case>
{
    private readonly int _caseId;
    private FutureValue<Case> _futureCase;
    private IEnumerable<CaseTag> _caseTags;
    private IEnumerable<Tag> _tags;
    private Case _case;

    public Case Entity
    {
        get
        {
            if (!IsLoaded)
                return null;

            if (_case == null)
                CreateCase();

            return _case;
        }
    }

    public bool IsLoaded { get; private set; }

    public CaseTagLoader(int caseId)
    {
        _caseId = caseId;
        IsLoaded = false;
    }

    public void Load()
    {
        if (IsLoaded)
            return;

        using (var db = new BlogDataContext())
        {
            db.ObjectTrackingEnabled = false;
            Load(db);
            db.ExecuteFutureQueries();
        }
    }

    public void Load(BlogDataContext db)
    {
        if (IsLoaded)
            return;

        _futureCase = db.Case.ById(_caseId).FutureFirstOrDefault();
        var caseTagQuery = db.CaseTag.ByCaseId(_caseId);
        _caseTags = caseTagQuery.Future();
        _tags = db.Tag
            .Join(caseTagQuery, t => t.Id, ct => ct.TagId, (t, ct) => t)
            .Future();

        IsLoaded = true;
    }

    private void CreateCase()
    {
        _case = _futureCase.Value;
        _case.CaseTags.AddRange(_caseTags);

        foreach (var caseTag in _caseTags)
            caseTag.Tag = _tags.First(t => t.Id == caseTag.TagId);
    }
}

Monday, October 26, 2009

PLINQO Query Extension Updates

The Problem

Unfortunately the previous query extensions, while great at querying by a particular value, did not support simple operations such as getting by a nullable value type (where you know it can be null or just a value).

Example: If you want to query by a nullable column, you had to use a a lambda expression.

context.Product.Where(p => !p.OwnerId.HasValue || p.OwnerId.Value == 5);

Our Solution

Add an overload that for each "By" extension method that accepts a params list of values.

Example: Now you can look for null OR a certain value without using where statement.

context.Product.ByOwnerId(null, 5);

New PLINQO Feature

Here at CodeSmith we love generic solutions. So, forget just supporting ByValueOrNull scenarios, now all "By" query extensions have an overload to support or statements!

Example: Ummm, every single "By" query extension method generated by PLINQO?

context.Task.ByPriority(Priority.High, null, Priority.Medium);
context.Person.ByFirstName("Eric", null, "Shannon", String.Empty);
context.Product.ByName("Scribblenauts", "Bowser's Inside Story").ByRating(Rating.Excellent, Rating.AboveAverage);

Implementation Details

To see how the overloads are implemented you need only take a look at the template, QueryExtension.Generated.cst. If you are curious to see how all of this comes together under the hood, where we build up the parametrized query string and then parse the lambda, this code is located in DynamicQuery.cs

Fun Little FYI Facts: Unfortunately Linq to SQL does not support doing a IEnumerable.Contains against a nullable value type collection to identify null values. Also, when building a string expression, you cant just say where a primitive is equal to a null, that will cause a parsing exception. So once we jumped those hurdles, the rest was relatively easy; just check for null params arrays in the overloads and know when to treat them as a null vs an empty param, and you're all set!

In Conclusion

Linq rocks. PLINQO just keeps getting better. Check out our new nightly builds, or wait for PLINQO 3.2, coming soon to our Google Code repository near you!

Tuesday, October 20, 2009

PLINQO @ Fort Worth DNUG

The CodeSmith Tools (Shannon and Tom) are continuing their PLINQO presentation tour! Second stop: Fort Worth

If you or any developers that you know will be in the Forth Worth area on October 20th, you should come see us and learn more about PLINQO, the replace and enhance alternative for LINQ to SQL!

Forth Worth DNUG
Topic: PLINQO - Supercharged LINQ To SQL
Speaker: Shannon Davidson & Tom DuPont
Date: October 20th @ 6:00 PM
Where: 610 W. Daggett - Fort Worth, TX 76104

Thursday, October 8, 2009

PLINQO @ North Houston DNUG

The CodeSmith Tools (Shannon and Tom) are taking their PLINQO presentation on the road! First stop: North Houston

If you or any developers that you know will be in the Houston area on October 15th, you should come see us and learn more about PLINQO, the replace and enhance alternative for LINQ to SQL!

North Houston Dot Net User Group
Topic: PLINQO - Supercharged LINQ To SQL
Speaker: Shannon Davidson & Tom DuPont
Date: October 15th @ 6:30 PM
Where: Lone Star College - Montgomery

Monday, August 10, 2009

MVC JSON Model Binder Attribute

Here it is folks: the Ultimate Ultimate* ASP.NET MVC JSON Model Binder!

Moving complex data structures from client to server used to be difficult, but not anymore! Just add the JsonBinder attribute to your action parameters, and this Custom ModelBinder will automatically detect the type and parameter name, and deserialize your complex JSON object to the data structure of your choice.

No configuration required, it works every time, it's PFM!**

* Yes, I said Ultimate twice.
** Pure Friendly Magic

JsonBinderAttribute

public class JsonBinderAttribute : CustomModelBinderAttribute
{
    public override IModelBinder GetBinder()
    {
        return new JsonModelBinder();
    }
 
    public class JsonModelBinder : IModelBinder
    {
        public object BindModel(
            ControllerContext controllerContext, 
            ModelBindingContext bindingContext)
        {
            try
            {
                var json = controllerContext.HttpContext.Request
                           .Params[bindingContext.ModelName];
 
                if (String.IsNullOrWhitespace(json))
                    return null;
 
                // Swap this out with whichever Json deserializer you prefer.
                return Newtonsoft.Json.JsonConvert
                       .DeserializeObject(json, bindingContext.ModelType);
            }
            catch
            {
                return null;
            }
        }
    }
}

Controller Action

public class PersonController : Controller
{
    // Note: The JsonBinder attribute has been added to the person parameter.
    [HttpPost]
    public ActionResult Update([JsonBinder]Person person)
    {
        // Both the person and its internal pet object have been populated!
        ViewData["PetName"] = person.Pet.Name;
        return View();
    }
}

Sample Models

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    // Note: This property is not a primitive!
    public DomesticAnimal Pet { get; set; }
}
 
public class DomesticAnimal
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Species { get; set; }
}

jQuery Method

function sendToServer() {
    var person = {
        Name : 'Tom',
        Age : 27,
        Pet : {
            Name : 'Taboo',
            Age : 2,
            Species : 'Shiba Inu'
        }
    };
 
    // {"Name":"Tom","Age":27,Pet:{"Name":"Taboo",Age:2,Species:"Shiba Inu"}}
    var personJson = JSON.stringify(person);
 
    $.ajax({
        url: 'Person/Update', 
        type: 'POST',
        data: { 
            person: personJson 
        }
    });
}
Shout it

Enjoy,
Tom

Real Time Web Analytics