Monday, October 31, 2011

Not all Linq provider approaches are the same

Whereas NHibernate Linq don't have a problem immediately reaching C#'s functions..

public JsonResult GetUpdated(Guid id)
{
    var js = new JsonResult();

    js.Data =
        new
        {
            Record = (from p in _person.All
                      where p.PersonId == id
                      select new { 
                          p.PersonId, 
                          p.Username, 
                          p.Firstname, 
                          p.Lastname, 
                          p.FavoriteNumber, 
                          p.Country,
                          RowVersion = CustomStringFunctionHere(p.RowVersion ?? new byte[] { })
                      } ).Single()
        };

    return js;
}

string CustomStringFunctionHere(byte[] a)
{
    return "AAA" + Convert.ToBase64String(a) + "BBB";
}

..Entity Framework does:

LINQ to Entities does not recognize the method 'System.String CustomStringFunctionHere(Byte[])' method, and this method cannot be translated into a store expression.


NHibernate do the projection differently, its select expression is not being translated to its store equivalent.

Sunday, October 23, 2011

Updates on jQuery Ajax ComboBox ASP.NET MVC Helper

Added string-based name on the helpers.

Download the code from: http://code.google.com/p/ienablemuch-jquery-ajax-combobox-aspnetmvc/downloads/list

Get the demo code at: http://code.google.com/p/jquery-ajax-combobox-aspnet-mvc-helper/downloads/list


Example:

@Html.AjaxComboBox("CategoryId", 
    "/Category/Lookup",
    "/Category/Caption",
    new { style = "width: 300px " },
    new { sub_info = true })


Nothing was changed on strongly-typed helpers, it's still the preferred way:
@Html.AjaxComboBoxFor(model => model.CategoryId,
  "/Category/Lookup",
  "/Category/Caption",
  new { style = "width: 300px " },
  new { sub_info = true })

Wednesday, October 12, 2011

Sample ASP.NET Ajax Leaky Abstraction

Below is the work-around for problem on non-working ASP.NET UpdateProgress(with AssociatedUpdatePanelID) when the control(e.g. Button) that causes the post-back is outside of the UpdatePanel. This is the cause of the error:

http://stackoverflow.com/questions/1187953/updateprogessbar-is-not-working-when-setting-associatedupdatepanelid


This is the solution for ASP.NET AJAX leaky abstraction :-)

http://stackoverflow.com/questions/996957/why-does-update-progress-does-not-fire-when-associatedupdatepanelid-is-set


An implementation:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication7._Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script type="text/JavaScript" language="JavaScript">
        function pageLoad() {
            var manager = Sys.WebForms.PageRequestManager.getInstance();
            manager.add_beginRequest(OnBeginRequest);
        }
        function OnBeginRequest(sender, args) {
            var postBackElement = args.get_postBackElement();
            if (postBackElement.id == 'MainContent_Button1') {
                var up = $get('MainContent_UpdateProgress1');
                up.style.display = "block";
            }
        }
    </script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
        Welcome to ASP.NET!
    </h2>
    <p>
        To learn more about ASP.NET visit <a href="http://www.asp.net" title="ASP.NET Website">
            www.asp.net</a>.
    </p>
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="Button1" />
        </Triggers>
        <ContentTemplate>
            <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
        </ContentTemplate>
    </asp:UpdatePanel>
    <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
    <asp:UpdateProgress ID="UpdateProgress1" AssociatedUpdatePanelID="UpdatePanel1" runat="server">
        <ProgressTemplate>
            Loading ...</ProgressTemplate>
    </asp:UpdateProgress>
</asp:Content>


This sort of leaky abstraction on ASP.NET of simulating states in an otherwise stateless protocol is making me embrace MVC+jQuery combo even more.

And someday, you won't get any answer on this type of question on forums, as it will be deemed too localized a few years from now. Five years or more, give or take, most developers will be using MVC+jQuery or node.js+jQuery already, and you will hardly find someone able to answer this ASP.NET type of question.

Monday, October 10, 2011

When is null is not a null? This is not a philosophical SQL question :-)

Answer: When it is still inside of Linq Expression


Linq operation is one of the rare occasion where C# semantics is not of WYSIWYG one.


var employees =
from x in db.Employees
where x.Manager == null
orderby x.LastName
select new { x.FirstName, x.LastName, x.Manager, ManagerName = x.Manager.LastName };
 
GridView1.DataSource = employees;
GridView1.DataBind();



Given the code above, even if x.Manager is null (or just look like one) the code x.Manager.LastName is not an absurd one. x.Manager == null has no bearing on C# nullability. As far as an ORM is concerned, x.Manager == null needed be translated to its equivalent relational syntax, i.e. that code needed be translated to table2.EmployeeId IS NULL. An ORM is able to do that, as the ORM's mappings contains info on what columns connect one table to another table. The x.Manager.LastName in Linq's select clause is also being translated by Linq Expression provider(e.g. ORM), that's why there won't be any null runtime error on x.Manager.LastName when the LastName is being accessed.


Continuing the code above, when using AsEnumerable this code's null..

var z =
from y in employees.AsEnumerable()
where y.Manager == null
select new { y.FirstName, y.LastName, y.Manager, ManagerName = y.Manager.LastName };

GridView1.DataSource = z;
GridView1.DataBind();


..is now a C#'s null. This code will have a null runtime exception on y.Manager.LastName then.



Perhaps to make code analysis a lot simpler, any code that is still in scope of Linq's Expression should be thought of not as a C#'s construct, and as such, are still subject for translation to whatever SQL syntax it needed be translated, C#'s language rules doesn't come into play when an Expression is still in scope. Linq Expression provider could even translate y.Manager == null to any kind of code; much like C++/C# operator overloading, a plus operator could mean minus, a minus could mean plus. And as far as Linq Expression provider is concerned, the code select new { y.FirstName, y.LastName, y.Manager, ManagerName = y.Manager.LastName } could be translated up to the Linq provider's liking and such can be translated to any kind of code, y.Lastname could be automatically translated to an expression that automatically lowercases, e.g. SELECT Lastname = LCASE(LastName), to even a random one :-)


C# rules could only take effect when things are materialized to objects already, e.g. when using AsEnumerable, ToArray, ToList.


This is the ideal Linq code for properties(e.g. FullName from concatenation in C#) in classes that are not present in database:

var employees =
    (from x in db.Employees
    where x.Manager == null
    orderby x.LastName
    select x) // code here and up are being translated to back-end equivalent, i.e. SQL
 
 
    // code here and below, be it Linq-style or Lambda-style, now follows the normal C# rules,
    // note the null coalesce (??) operator
    .AsEnumerable()
    .Select(y => new
        {
        y.FullName, // Lastname and Firstname is concatenated on C# getter
        ManagerName = (y.Manager ?? new NorthwindModel.Employee()).FullName
    });