Saturday, April 30, 2011

Postgresql pain point on ORMs

Is it a breaking changes if Postgresql will make their table and field names case-insensitive? Postgresql table and field cases automatically folded to lowercase hurts badly on ORMs

Use this for the meantime:

public static string ToLowercaseNamingConvention(this string s, bool toLowercase)
{
    if (toLowercase)
    {
        var r = new Regex(@"
        (?<=[A-Z])(?=[A-Z][a-z]) |
         (?<=[^A-Z])(?=[A-Z]) |
         (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);

        return r.Replace(s, "_").ToLower();
    }
    else
        return s;
}


Sample here: http://code.google.com/p/fluent-nhibernate-lowercase-system/source/checkout

Wednesday, April 27, 2011

Javascript object-based programming for C# object-oriented programmers

<script>

    
    function individual(msg) // class individual
    {
        this.mx = msg;    // mx is a public property of class individual instance
        var zuper = this.mx + '!'; // zuper is a private property of class individual instance
        
        this.show = function() { // public method
            alert(zuper);
        }
        
        this.showSomething = function() { // public method
            alert(this.something);
            quick();
        }
        
        function quick() { // private method
            alert('quick');
        }
    }

    var x = new individual("Hello");
    var y = new individual("World");
    
    alert(x.mx); // shows Hello
    alert(y.mx); // shows World
    
    alert(x.zuper); // shows undefined    
    y.zuper = "xxx"; // but this one creates a different instance of outside zuper on y's instance, but this is different from y's inside zuper
    alert(y.zuper); // shows xxx
    
    
    x.show(); // shows "Hello!"
    y.show(); // to prove that the outside zuper instance on y is different from inside(acts like a private property), this will not show "xxx", this shows "World!"
    
    y.something = "George"; // you can attach properties on javascript's object on whim
    y.showSomething(); // shows "George"
    
    y.quick(); // this will make javascript terminate silently
    alert("Not shown"); // won't get executed 
    
</script>

Monday, April 25, 2011

Update on ASP.NET MVC Helper for jQuery Ajax ComboBox (Cascading Functionality added)

To use, clear the cascading destination upon selecting from the cascading source. The event of cascading source is on_selected event.

Then on cascading destination use cascaded_word property.

On View:
<div class="editor-label">
    @Html.LabelFor(model => model.PurchasedDto.CategoryId, "Category")
</div>
<div class="editor-field">
    <table>
    <tr>
    <td style="width: 250px">@Html.AjaxComboBoxFor(model => model.PurchasedDto.CategoryId, "/Category/Lookup", "/Category/Caption", 
        new { style="width: 250px" },
        new {
            on_selected = @"$('#PurchasedDto\\.ProductId').ajc().clearValue();" 
            })</td>
    <td>@Html.ValidationMessageFor(model => model.PurchasedDto.CategoryId)</td>
    </tr>
    </table>
</div>

<div class="editor-label">
    @Html.LabelFor(model => model.PurchasedDto.ProductId, "Product")
</div>
<div class="editor-field">
    <table>
    <tr><td style="width: 250px">
    @Html.AjaxComboBoxFor(model => model.PurchasedDto.ProductId, "/Product/Lookup", "/Product/Caption",
    new { style="width: 250px" },
    new
    {
        sub_info = true,
        cascaded_word = "$('input[name=PurchasedDto.CategoryId]').val()"
    })
    </td>           
    <td>@Html.ValidationMessageFor(model => model.PurchasedDto.ProductId)</td>
    </tr>
    </table>        
</div>



On Controller:
[HttpPost]
public JsonResult Lookup(string cascaded_word, string q_word, string primary_key, int per_page, int page_num)
{


    using (var svc = SessionFactoryBuilder.GetSessionFactory().OpenSession())
    {

        int categoryId = 0;

        bool isNumber = int.TryParse(cascaded_word, out categoryId);




        var FilteredProduct = svc.Query<Product>()
                                .Where(x =>
                                    (

                                        categoryId == 0
                                        ||
                                        (categoryId != 0 && x.Category.CategoryId == categoryId)

                                    )

                                    &&

                                    (q_word == "" || x.ProductName.Contains(q_word))

                                    );


        var PagedFilter = FilteredProduct.OrderBy(x => x.ProductName)
                          .LimitAndOffset(per_page, page_num)
                          .Fetch(x => x.Category)
                          .ToList();

        return Json(
            new
            {
                cnt = FilteredProduct.Count()

                ,primary_key = PagedFilter.Select(x => x.ProductId)

                ,candidate = PagedFilter.Select(x => x.ProductName)

                ,cnt_page = PagedFilter.Count()

                ,attached = PagedFilter.Select(x =>
                       new[]
                        {
                            new string[] { "Product Code", x.ProductCode },                                    
                            new string[] { "Category Code", x.Category.CategoryCode },
                            new string[] { "Category", x.Category.CategoryName }
                        }
                   )
            }
            );

    }//using
}

Download the latest to see cascading capability in action: http://code.google.com/p/jquery-ajax-combobox-aspnet-mvc-helper/downloads/list

Get the code from SVN http://code.google.com/p/jquery-ajax-combobox-aspnet-mvc-helper/source/checkout

Sunday, April 24, 2011

Put prefix to a property

<script>


String.prototype.splice = function( idx, rem, s ) {
    // sourced from: http://stackoverflow.com/questions/4313841/javascript-how-can-i-insert-a-string-at-a-specific-index
    return (this.slice(0,idx) + s + this.slice(idx + Math.abs(rem)));
};

String.prototype.putPrefixToProperty = function(prefix) {
    ndx = -1;
    for(i = this.length - 1; i > 0; --i) {
        if (this[i] == '.') {
            ndx = i;
            break;
        }
    }    
    return this.splice(++ndx,0,prefix)        
}


alert("ProductId".putPrefixToProperty("txt_"));
alert("PurchasedDto.ProductId".putPrefixToProperty("txt_"));
alert("PurchasedDto.LineItem.ProductId".putPrefixToProperty("txt_"));

</script>

Output:
txt_ProductId
PurchasedDto.txt_ProductId
PurchasedDto.LineItem.txt_ProductId

Trivia: Did you know you can copy alert's text(or any dialog for that matter) by pressing Ctrl+C

Saturday, April 23, 2011

MVC cardinal rule, View doesn't have any logic

The View of MVC...

public ViewResult List()
{
    using (var s = SessionFactoryBuilder.GetSessionFactory().OpenSession())
    {
        var products = s.Query<Product>().Fetch(x=>x.Category).ToList()
        if (Browser.IsDesktop)
            return View(products);
        else if (Browser.IsMobileSafari)
            return View("ListUsingMobileSafari", 
                new ProductMobileViewModel 
                {
                    Products = products,
                    IsRetina = Browser.IsRetina
                });
    }
}

...renders any Model to its proper presentation, View doesn't need to handle(and must not) any logic, so as to keep proper separation of concerns. The UI(View) team for mobile Safari, could merrily do their approach without bugging the logic(Controller) team for other informations, as the business of gathering those informations are promptly prepared by the controller team, which in turn are driven by business requirements and user specifications.

Never in an ideal development shop that the View should deal with disparate models and other informations by themselves. The Model(and ViewModel) is the contract between the Controller and View.

Friday, April 22, 2011

My Cookbook on DTO and ViewModel

Load DTO, pass it to ViewModel(either by composition or inheritance), pass the ViewModel to View.



DTO has no behavior, it's just data; ViewModel not only has data, it also has behavior, i.e. anything seen or interacted by the user, e.g. paging, dropdown's data , and other miscellaneous information(e.g. user can see the most selling product while he/she is in data entry page, that information are passed to ViewModel) seen by users are orchestrated in ViewModel



I'm starting to believe that ASP.NET MVC should be called ViewModel-View-Controller. VMVC, any takers? View doesn't interact with pure Model anymore, View has many concerns too(e.g. paging, alert message) that if it pull all this informations by itself, the program won't look cohesive anymore.


The Controller manages this complexity by assembling all the information needed by View in one cohesive model, which is differently termed(ViewModel), so developers won't have a misconception that a View is ought to deal with several raw Model by itself.



If the ViewModel pattern is not adhered to, an unwitting developer could badly stash all Models and miscellaneous information to ViewData dictionary or ViewBag

Debugging Fluent NHibernate mappings

Debugging NHibernate is tricky sometimes. It's confusing if you're looking in the wrong places. If you have this kind of error...

Could not determine type for: JqueryAjaxComboBoxAspNetMvcHelperDemo.Models.Product, JqueryAjaxComboBoxAspNetMvcHelperDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, for columns: NHibernate.Mapping.Column(ProductId)

...don't be stucked at your Product and ProductMap class, find (Ctrl+F) this: Column("ProductId")

So in our code, the problem lies in (line 57): Map(x => x.Product).Column("ProductId");, must change that to References(x => x.Product).Column("ProductId")

public class Product
{
    public virtual int ProductId { get; set; }
    public virtual string ProductCode { get; set; }
    public virtual string ProductName { get; set; }
    public virtual Category Category { get; set; }
}

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Id(x => x.ProductId);
        Map(x => x.ProductCode);
        Map(x => x.ProductName);
        References(x => x.Category).Column("CategoryId");                
    }

}



public class Category
{
    public virtual int CategoryId { get; set; }
    public virtual string CategoryCode { get; set; }
    public virtual string CategoryName { get; set; }
    public virtual int Ranking { get; set; }
}

public class CategoryMap : ClassMap<Category>
{
    public CategoryMap()
    {
        Id(x => x.CategoryId);
        Map(x => x.CategoryCode);
        Map(x => x.CategoryName);
        Map(x => x.Ranking);
    }
}

    
public class Purchased
{
    public virtual int PurchasedId { get; set; }
    public virtual Product Product { get; set; }
    public virtual int Quantity { get; set; }
    public virtual string PurchasedBy { get; set; }
}

    
public class PurchasedMap : ClassMap<Purchased>
{
    public PurchasedMap()
    {
        Id(x => x.PurchasedId);
        Map(x => x.Product).Column("ProductId");
        Map(x => x.Quantity);
        Map(x => x.PurchasedBy);
    }
}

Update on jQuery Ajax ComboBox ASP.NET MVC helper

Added on_selected callback

To use:

<div class="editor-label">
 @Html.LabelFor(model => model.CategoryId, "Category")
</div>
<div class="editor-field">
 <table>
 <tr>                    
  <td>@Html.AjaxComboBoxFor(model => model.CategoryId,
   "/Category/Lookup",
   "/Category/Caption",
   new { style = "width: 300px " },
   new { sub_info = true, on_selected = "thisIsOk();" })
  </td>
  <td>@Html.ValidationMessageFor(model => model.CategoryId)</td>
 </tr>
 </table>
</div>


<script>
    function thisIsOk() {
        alert('This is great!');
    }
</script>


Download it from Google Code

Or get an SVN copy

Thursday, April 21, 2011

NHibernate Error: "Could not initialize proxy - no Session"

If you happen to encounter this kind of error in NHibernate...

Initializing[JqueryAjaxComboBoxAspNetMvcHelperDemo.Models.Category#777]-Could not initialize proxy - no Session.

...even you already have a Fetch clause in your controller code:

public ViewResult Index()
{
 using (var s = SessionFactoryBuilder.GetSessionFactory().OpenSession())
 {
  return View(s.Query<Product>().Fetch(x => x.Category).ToList());
 }
}

Worry not much, if your code has a Fetch clause, the problem lies in the data, your data is inconsistent, your table has a foreign key that has no matching primary key in the table it is referring to. Typical of database with no foreign key capability (e.g. MySQL's MyISAM) or with foreign key but not enforced(I'm using Sqlite when I encountered that error)

In our example, there is no primary key 777 in Category table, so we just need to correct our data

You can also encounter the same error(verbatim) even if your data is correct, it happens when you forgot to include the Fetch clause in your query.


Again, NHibernate does a poor job on stating the root cause of error. Another example of vague error from NHibernate http://www.ienablemuch.com/2010/10/nhibernate-orm-how-to-object-relational.html, scroll the down to the last portion of the article

Visual Studio nifty shortcut

Commenting (keyboard shortcut: Ctrl+KC) is more cool when you are editing a page. When the cursor is inside of tags, it will comment the enclosing tag on both ends(i.e. beginning tag and closing tag) even you didn't highlight the beginning tag and closing tag.

<div class="editor-field">
 <table>
 <tr>                    
  <td>@Html.AjaxComboBoxFor(model => model.CategoryId,
   "/Category/Lookup",
   "/Category/Caption",
   new { style = "width: 300px " },
   new { sub_info = true } )
  </td>
  <td>@Html.ValidationMessageFor(model => model.CategoryId)</td>
 </tr>
 </table>
</div>



If you position your cursor after of <table> then you press Ctrl+KC, Visual Studio will put comment around your table tags


<div class="editor-field">
 @*<table>
 <tr>                    
  <td>@Html.AjaxComboBoxFor(model => model.CategoryId,
   "/Category/Lookup",
   "/Category/Caption",
   new { style = "width: 300px " },
   new { sub_info = true } )
  </td>
  <td>@Html.ValidationMessageFor(model => model.CategoryId)</td>
 </tr>
 </table>*@
</div>

Tuesday, April 19, 2011

Please create a model for your inputs. Model guidelines for ASP.NET MVC

Please create a model for your inputs; even if a FormCollection or Request.Form seems expedient at some pressured moment(e.g. deadline), track down what causes the ASP.NET's MVC engine not populating your models. By using models, our program is more "discoverable" so-to-speak, so any new or existing programmers who will review or continue our code can easily infer the intent of code, they would be able to know what other informations goes with the model, FormCollection and Request.Form doesn't carry any business logic semantics, those who are new to our programs could not easily infer if FormCollection carries a Bonus field, they won't be able to know if we overlooked some fields, they won't be able to know if the program needed to include other fields when performing computations from data before saving the data to database.



What I said is not a draconian rule; really, I'm an old man trapped in a young body. If we still cannot figure out why MVC cannot populate our models well, we will just use FormCollection for the meantime(though not pansamantagal, there's something exhilirating tracking the causes of errors), but eventually we shall have to discover what causes ASP.NET MVC engine not populating our models well


"Young men know the rules, but old men know the exceptions." -- Oliver Wendell Holmes



One of the causes why ASP.NET MVC cannot populate the object's property well is when the field source is in invalid format. Example, passing Feb 31, 1976 to a birthday field. Another example is passing 1,234 to a decimal type, whoa..! wait! wait! 1,234 is a valid decimal, and a quick trip to SnippetCompiler showed me that Convert.ToDecimal("1,234") doesn't causes any runtime error, and it returns 1234. Unfortunately for us, web is a different beast, it is public-facing most of the time, so there's the multi-culture(i.e. different nations uses different money format) issues. For instance, a German string input(every inputs on web are strings) of 1,234 means 1 dollar(or euro) and 234 cents; 1.234 is one thousand two hundred thirty four bucks for them. So ASP.NET MVC team didn't make an assumption that a 1,234 string has a universal meaning for a decimal type.


There's a two solution on that issue, one is to clean the data prior to submitting:

$(function () {
    $('#theFormIdHere').submit(function() {
        var uxSalary = $('input[name=Salary]');
        uxSalary.val(uxSalary.val().replace(',', ''));
    });
});

But that causes an ugly artifact on UI, the decimal type's formatting on textbox will be altered. So this is a no-go proposition for some developers.


Another solution is to use a ModelBinder for decimal. In this case, we don't reinvent the wheel, let's just use Phil Haack's code. Get it here: http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx


To see things in action and make 1,234 worked, download the code here: http://code.google.com/p/test-aspnetmvc-decimal-binding-problem/downloads/list

And do either of the following:

Uncomment line 22 to 27 of Index.cshtml
/*$(function () {
        $('#theDataHolder').submit(function() {
            var uxSalary = $('input[name=Salary]');
            uxSalary.val(uxSalary.val().replace(',', ''));
        });
    });*/

Or uncomment line 36 of Global.asax
// ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());



Regarding the duplication of model, one in WCF Data Services project, another in our web project. We are just being pragmatic, we are not able find a way to make WCF Data Services' models carry other semantics(e.g. validation attributes). I tried Scott Gu's buddy-class approach, but for the life of me I don't know why WCF Data Services can't carry data validation attributes I added to an entity in a WCF Data Services. The duplicity, as evident on FbPerson module, I'm not using WCF Data Services' FbPerson model on FbPerson's form; instead, I created a separate FbPerson model on our web project's Models folder and uses that model on FbPerson's form. Using that approach, in its barest essence, WCF Data Services merely acts as a data access layer, it can't (or we just can't figure it out yet) carry semantics loaded to models like Required, Range, etc.



Perhaps we have a better chance of loading semantics to models if we do a code-first(instead of using designers, just do POCOs) models on WCF Data Service, don't want? :-)


Another approach is to use WCF Service and also do a code-first of models, i.e. POCO; and let the ORM(say Entity Framework or NHibernate) persist those models to database. We can load semantics(lol I'm not contented with the word attribute/validation) to models using this approach; also by using this approach we can tap the full potential of an ORM, we can get server-generated id(e.g. newsequentialid) for example, and better handling of concurrency(of which I know NHibernate is capable of including rowversion field on UPDATE statement's WHERE clause, on Entity Framework I have yet to google it), I noticed we didn't introduce a rowversion field (for concurrency stuff) on all our tables :-)


Speaking of NHibernate stuff, did you know we can just merely do one statement for both insert and update with NH? We just push the model to it and it will do its job well. That method is Merge. And when NH's Merge is doing an UPDATE, it includes the rowversion(for handling concurrent update) field to WHERE clause as well, neat :-)

Example WCF Service using NHibernate:
public KeyAndRowversion FbPerson_Save(FbPerson fromInput)
{
    using(var s = OurSystem.SessionFactory.OpenSession())
    {
        // NHibernate doesn't alter the model you passed to it; instead, it returns a new object which contains the current state of your model
        FbPerson currentValues = (FbPerson) s.Merge(fromInput);
        
        return new KeyAndRowversion { HasError = false, GeneratedGuid = currentValues.PersonId, CurrentRowversion = currentValues.TheRowVersion };
    }
}

Contrast that with Entity Framework approach.

Example WCF Service using EntityFramework:
public KeyAndRowversion FbPerson_Save(FbPerson fromInput)
{
    using(var s = new OurSystem.ErpDbContext())
    {
        FbPerson fromExisting = s.FbPersons.Find(fromInput.PersonId);

        if (fromExisting == null)
        {
            s.Persons.Add(fromInput);
        }
        else
        {
            fromExisting.Firstname = fromInput.Firstname;
            fromExisting.Lastname = fromInput.Lastname;
            fromExisting.Age = fromInput.Age;
            fromExisting.CountryId = fromInput.CountryId;
        }

        s.SaveChanges();

        // Entity Framework alters the model you passed to it, example: primary key; I haven't checked yet if EF also loads the current rowversion  on altered model
        return new KeyAndRowversion { HasError = false, GeneratedGuid = fromInput.PersonId };        
    }
}

Monday, April 18, 2011

Added Html and Json attributes on ASP.NET MVC Helper for jQuery Ajax ComboBox

On view:

<div class="editor-label">
 @Html.LabelFor(model => model.CategoryId, "Category")
</div>
<div class="editor-field">
 <table>
 <tr>                    
  <td>@Html.AjaxComboBoxFor(model => model.CategoryId,
   "/Category/Lookup",
   "/Category/Caption",
   new { style = "width: 300px " } // html attributes for span
   new { sub_info = true } ) // other json attributes for jQuery Ajax ComboBox 
  </td>
  <td>@Html.ValidationMessageFor(model => model.CategoryId)</td>
 </tr>
 </table>
</div>

On controller:

[HttpPost]
public JsonResult Lookup(string q_word, string primary_key, int per_page, int page_num)
{


    using (var svc = SessionFactoryBuilder.GetSessionFactory().OpenSession())
    {

        var FilteredCategory = svc.Query<Category>()
                                .Where(x => q_word == "" || x.CategoryName.Contains(q_word));


        var PagedFilter = FilteredCategory.OrderBy(x => x.CategoryName)
                          .LimitAndOffset(per_page, page_num)
                          .ToList();

        return Json(
            new
            {
                cnt = FilteredCategory.Count()

                ,primary_key = PagedFilter.Select(x => x.CategoryId)

                ,candidate = PagedFilter.Select(x => x.CategoryName)

                ,cnt_page = PagedFilter.Count()

                // these are the sub info:
                ,attached = PagedFilter.Select(x =>                    
                        new[]
                        {
                            new string[] { "Code", x.CategoryCode } ,
                            new string[] { "Ranking", x.Ranking.ToString() }
                        }
                    )
            }
            );

    }//using
}//Lookup


[HttpPost]
public string Caption(string q_word)
{
    using (var svc = SessionFactoryBuilder.GetSessionFactory().OpenSession())
    {
        if (string.IsNullOrEmpty(q_word))
            return "";
        else
            return 
                svc.Query<Category>()
                .Where(x => x.CategoryId == int.Parse(q_word))
                .Select(x => x.CategoryName)
                .SingleOrDefault();
    }

}


Working code available on: http://code.google.com/p/jquery-ajax-combobox-aspnet-mvc-helper/downloads/list

Sunday, April 17, 2011

Linq nuances with WCF Data Service

Don't assume all Linq providers are the same, Linq provider for Entity Framework is different from Linq provider for WCF Data Service

public static IQueryable<T> LimitAndOffset<T>(this IQueryable<T> q,
                    int pageSize, int pageOffset)
{
    // while this Linq works on both Entity Framework and WCF Data Services...
    // return q.Skip((pageOffset - 1) * pageSize).Take(pageSize);
    
    // ...this Linq doesn't work on WCF Data Service
    return q.Take(pageSize).Skip((pageOffset - 1) * pageSize);
}

I answered a colleague that Skip and Take's order doesn't matter (i.e. can call Take then Skip also) because it is deferredly executed, felt a little stupid for naturally assuming it applies to all Linq Providers :-) Linq for WCF Data Services doesn't allow Take then Skip. Don't assume anything when it comes to Linq.

Lesson learned, not all Linq providers are created equal. Lest I forgot, I already encountered one of many Linq's nuances a long time ago, example: http://www.ienablemuch.com/2010/12/performing-order-by-on-distinct-on-linq.html

I should have known better :-)

A null was returned after calling the 'GetService' method on a store provider instance of type 'System.Data.SQLite.SQLiteFactory'

If you encounter this error:

A null was returned after calling the 'GetService' method on a store provider instance of type 'System.Data.SQLite.SQLiteFactory'. The store provider might not be functioning correctly.


Add System.Data.SQLite.Linq.dll to your project's References

The type or namespace name 'ModelBuilder' does not exist

If you encountered this error:


The type or namespace name 'ModelBuilder' does not exist in the namespace 'System.Data.Entity.ModelConfiguration' (are you missing an assembly reference?)

Just change...

System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder

...to:

System.Data.Entity.DbModelBuilder modelBuilder

Friday, April 15, 2011

ASP.NET MVC Helper for jQuery Ajax ComboBox

View's code:

<div class="editor-label">
 @Html.LabelFor(model => model.CategoryId, "Category")
</div>
<div class="editor-field">
 <table>
 <tr>                    
  <td>@Html.AjaxComboBoxFor(model => model.CategoryId, "/Category/Lookup", "/Category/Caption")</td>
  <td>@Html.ValidationMessageFor(model => model.CategoryId)</td>
 </tr>
 </table>
</div>

Controller's code:

[HttpPost]
public JsonResult Lookup(string q_word, string primary_key, int per_page, int page_num)
{


 using (var svc = SessionFactoryBuilder.GetSessionFactory().OpenSession())
 {

  var FilteredCategory = svc.Query<Category>()
        .Where(x => q_word == "" || x.CategoryName.Contains(q_word));


  var PagedFilter = FilteredCategory.OrderBy(x => x.CategoryName)
        .LimitAndOffset(per_page, page_num)
        .ToList();

  return Json(
   new
   {
    cnt = FilteredCategory.Count()

    ,primary_key = PagedFilter.Select(x => x.CategoryId)

    ,candidate = PagedFilter.Select(x => x.CategoryName)

    ,cnt_page = PagedFilter.Count()

   }
   );

 }//using
}//List


[HttpPost]
public string Caption(string q_word)
{
 using (var svc = SessionFactoryBuilder.GetSessionFactory().OpenSession())
 {
  if (string.IsNullOrEmpty(q_word))
   return "";
  else
   return 
    svc.Query<Category>()
    .Where(x => x.CategoryId == int.Parse(q_word))
    .Select(x => x.CategoryName)
    .SingleOrDefault();
 }

}

Please do note that I modify the jQuery Ajax ComboBox's code a bit, so as to make the combobox's emitted name be compatible to ASP.NET MVC's Model

Get the code from SVN !

Or download it from google code

Sunday, April 10, 2011

Boilerplate code for Fluent NHibernate

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Cfg;
using FluentNHibernate.Conventions.Helpers;

namespace FnhNavigationTesting
{
    public static class SessionFactoryBuilder
    {
        static ISessionFactory _sf = null;
        public static ISessionFactory GetSessionFactory()
        {
            // Building SessionFactory is costly, should be done only once, making the backing variable static shall prevent creation of multiple factory
            try
            {
                if (_sf != null) return _sf;

                _sf = 
                    Fluently.Configure()
                    .Database(
                        MsSqlConfiguration.MsSql2008
                        .ConnectionString(
                            @"Data Source=localhost;Initial Catalog=OkSystem;User id=sa;Password=opensesame"))
                    .Mappings( x => x.FluentMappings.AddFromAssemblyOf<Program>())
                    .BuildSessionFactory();

                return _sf;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.InnerException.Message + "\n" + ex.InnerException.StackTrace);
            }
        }
    }//SessionFactoryBuilder
}