Monday, December 30, 2013

The proper way to deal with old database design (read: composite keys) on NHibernate

In ideal world, we have database that is devoid of composite primary keys.


create table ProductCategory
(
    ProductCategoryId int identity(1,1) primary key, -- ideally the entity is accessed through surrogate primary key

    ProductId int not null references Product(ProductId),
    CategoryId int not null references Category(CategoryId),

    CustomizedProductCategoryDescription nvarchar(200) not null,

    constraint uk_ProductCategory unique(ProductId, CategoryId) -- ideally on unique
);


create table Model
(
    ModelId int identity(1,1) primary key,
    
    -- ideally the entity referenced is accessed by the key, the whole key and nothing but the key.
    -- hear it loud, not keys! not plural, singular key only. capiche? :-)
    ProductCategoryId int not null references ProductCategory(ProductCategoryId), 

    ModelDescription nvarchar(200) not null
);


However not everyone are afforded of a perfect world, composite keys are pervasive on old database designs:

create table ProductCategory
(
    ProductId int not null references Product(ProductId),
    CategoryId int not null references Category(CategoryId),

    CustomizedProductCategoryDescription nvarchar(200) not null,

    constraint pk_ProductCategory primary key(ProductId, CategoryId) -- what an imperfect world
);


create table Model
(
    ModelId int identity(1,1) primary key,
    
    ProductId int not null,
    CategoryId int not null,

    ModelDescription nvarchar(200) not null,

    constraint fk_Model__ProductCategory foreign key(ProductId, CategoryId) references ProductCategory(ProductId, CategoryId) -- why the world have to be imperfect?
);


Ideally, even when mapping that imperfect design, related entities should still be navigable through object reference:

public class ProductCategory
{

    public virtual Product Product { get; set; }
    public virtual Category Category { get; set; }

    public virtual string CustomizedProductCategoryDescription { get; set; }        

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        var t = obj as ProductCategory;
        if (t == null)
            return false;
        if (Product == t.Product && Category == t.Category)
            return true;
        return false;
    }
    public override int GetHashCode()
    {
        return (Product.ProductId + "|" + Category.CategoryId).GetHashCode();
    }
}


class ProductCategoryMapping : ClassMapping<ProductCategory>
{
    public ProductCategoryMapping()
    {            
        ComposedId(
            c =>
            {                    
                c.ManyToOne(x => x.Product, x => x.Column("ProductId"));
                c.ManyToOne(x => x.Category, x => x.Column("CategoryId"));
            });

        Property(x => x.CustomizedProductCategoryDescription);
    }
}

However, the real problem with that kind of domain modeling is that lazy-loading will be defeated, think of Edit screen, you just need to get the IDs of both Product and Category via ProductCategory, there's no way we can avoid the unnecessary fetching of the whole ProductCategory object when we have the kind of domain model like the above. For a good detail why accessing the ProductId from Product of ProductCategory unnecessarily fetches the whole ProductCategory object, read this: http://devlicio.us/blogs/anne_epstein/archive/2009/11/20/nhibernate-and-composite-keys.aspx


Just a mere reading of ProductId from Product of ProductCategory, the app will unnecessarily fetch the whole ProductCategory object. This kind of problem doesn't happen on applications with no composite keys.

So this code..

public static Model LoadModel(int id)
{
    using (var session = SessionMapper.Mapper.SessionFactory.OpenSession())
    {
        var x = session.Load<Model>(1);
        Console.WriteLine("\nHey! {0} {1}", x.ProductCategory.Product.ProductId, x.ModelDescription);
        
        return x;
    }
}

..produces this SQL:
NHibernate:
    SELECT
        model0_.ModelId as ModelId3_0_,
        model0_.ProductId as ProductId3_0_,
        model0_.CategoryId as CategoryId3_0_,
        model0_.ModelDescription as ModelDes4_3_0_
    FROM
        Model model0_
    WHERE
        model0_.ModelId=@p0;
    @p0 = 1 [Type: Int32 (0)]
NHibernate:
    SELECT
        productcat0_.ProductId as ProductId2_0_,
        productcat0_.CategoryId as CategoryId2_0_,
        productcat0_.CustomizedProductCategoryDescription as Customiz3_2_0_
    FROM
        ProductCategory productcat0_
    WHERE
        productcat0_.ProductId=@p0
        and productcat0_.CategoryId=@p1;
    @p0 = 1 [Type: Int32 (0)], @p1 = 2 [Type: Int32 (0)]

Hey! 1 Viking shoe


Not optimized. As you can see, even we just read the ProductId the whole ProductCategory object is also fetched by our app. It looks amateurish when we are just accessing the ProductId and it's already available right there from the source table, yet our app still insist on loading the whole ProductCategory just to get the ProductId


Another problem with the kind of domain model above, when we persist the Model object, the persistence mechanism will become convoluted:

public static string AddModel()
{
    using (var session = SessionMapper.Mapper.SessionFactory.OpenSession())
    {
        var m = new Model
        {
            ProductCategory = session.Load<ProductCategory>(
                  new ProductCategory { Product = session.Load<Product>(1), Category = session.Load<Category>(2) }),
            ModelDescription = "Bad " + DateTime.Now.ToString()
        };

        session.Save(m);
        session.Flush();

        return m.ModelId + " " +  m.ModelDescription;
    }
}


To rectify that amateurish SQL and hideous persistence code, we must isolate the composite keys to their own class:
[Serializable]
public class ProductCategoryIdentifier
{
    public virtual int ProductId { get; set; }
    public virtual int CategoryId { get; set; }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        var t = obj as ProductCategoryIdentifier;
        if (t == null)
            return false;
        if (ProductId == t.ProductId && CategoryId == t.CategoryId)
            return true;
        return false;
    }
    public override int GetHashCode()
    {
        return (ProductId + "|" + CategoryId).GetHashCode();
    }
}

That class will be the primitive type for the composite key of our ProductCategory:
public class ProductCategory
{
    public virtual ProductCategoryIdentifier ProductCategoryIdentifier { get; set; }
    
    //// To enforce single source-of-truth when creating product category, set both Product and Category properties setter as protected.
    //// When assigning Product and Category, it must be done through the composite key class, i.e. through ProductCategoryIdentifier above

    public virtual Product Product { get; protected set; }
    public virtual Product Category { get; protected set; }
   
    public virtual string CustomizedProductCategoryDescription { get; set; }
}


class ProductCategoryMapping : ClassMapping<ProductCategory>
{
    public ProductCategoryMapping()
    {
        ComponentAsId(
            i => i.ProductCategoryIdentifier, 
            c =>
            {
                c.Property(x => x.ProductId);
                c.Property(x => x.CategoryId);
            });

        ManyToOne(x => x.Product, m =>
        {
            m.Column("ProductId");
            m.Update(false);
            m.Insert(false);                
        });

        ManyToOne(x => x.Category, m =>
        {
            m.Column("CategoryId");
            m.Update(false);
            m.Insert(false);                
        });

        Property(x => x.CustomizedProductCategoryDescription);
    }
}


This will be how our app will fetch the ModelDescription property and ProductId..
public static Model LoadModel(int id)
{
    using (var session = SessionMapper.Mapper.SessionFactory.OpenSession())
    {                
        // Read the ID from Composite Key's separate class(ProductCategoryIdentifier) 
        // ,this way the whole object of ProductCategory won't be unnecessarily fetched.
        var x = session.Load<Model>(1);
        Console.WriteLine("{0} {1}", x.ProductCategory.ProductCategoryIdentifier.ProductId, x.ModelDescription);
        

        return x;
    }        
}

..and the following is the SQL produced by that data access. As expected there's no unnecessary data that was fetched, ProductCategory is not fetched. Very optimized code
NHibernate:
    SELECT
        model0_.ModelId as ModelId3_0_,
        model0_.ProductId as ProductId3_0_,
        model0_.CategoryId as CategoryId3_0_,
        model0_.ModelDescription as ModelDes4_3_0_
    FROM
        Model model0_
    WHERE
        model0_.ModelId=@p0;
    @p0 = 1 [Type: Int32 (0)]

1 Viking shoe

This is how we persist the Model object when it has a composite foreign key..
public static string AddModel()
{
    using (var session = SessionMapper.Mapper.SessionFactory.OpenSession())
    {
        var m = new Model
        {
            ProductCategory = session.Load<ProductCategory>(
                 new ProductCategoryIdentifier { ProductId = 1, CategoryId = 2 }),                    
            ModelDescription = "Good " + DateTime.Now.ToString()
        };

        session.Save(m);
        session.Flush();

        return m.ModelId + " " + m.ModelDescription;
    }
}


..the code looks more clean as compared to the model without a separate class for composite key.


It will be more clean if we don't have composite keys on the database in the first place. Ah legacy systems..!



Complete code: https://github.com/MichaelBuen/TestComposite



Happy Coding! ツ

NHibernate: Foreign key must have same number of columns as the referenced primary key

If you get this kind of error when mapping many-to-one from child to parent, where the parent is using composite key which is mapped using mapping-by-code, e.g. ComponentAsId ..


System.TypeInitializationException was unhandled
  HResult=-2146233036
  Message=The type initializer for 'GoodCompositeMapping.SessionMapper.Mapper' threw an exception.
  Source=GoodCompositeMapping
  TypeName=GoodCompositeMapping.SessionMapper.Mapper
  StackTrace:
       at GoodCompositeMapping.SessionMapper.Mapper.get_SessionFactory()
       at GoodCompositeMapping.SampleLoad.LoadModel(Int32 id) in c:\Users\Michael\Documents\GitHub\TestComposite\TestComposite\GoodCompositeMapping\SampleLoad.cs:line 21
       at TestComposite.Program.Main(String[] args) in c:\Users\Michael\Documents\GitHub\TestComposite\TestComposite\TestComposite\Program.cs:line 15
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: NHibernate.FKUnmatchingColumnsException
       HResult=-2146232832
       Message=Foreign key (FK2F6A0A3BACD3E029:Model [CategoryId])) must have same number of columns as the referenced primary key (ProductCategory [ProductId, CategoryId])
       Source=NHibernate
       StackTrace:
            at NHibernate.Cfg.Configuration.LogAndThrow(Exception exception)
            at NHibernate.Cfg.Configuration.SecondPassCompileForeignKeys(Table table, ISet done)
            at NHibernate.Cfg.Configuration.SecondPassCompile()
            at NHibernate.Cfg.Configuration.BuildSessionFactory()
            at GoodCompositeMapping.SessionMapper.Mapper.GetSessionFactory() in c:\Users\Michael\Documents\GitHub\TestComposite\TestComposite\GoodCompositeMapping\SessionMapper\Mapper.cs:line 58
            at GoodCompositeMapping.SessionMapper.Mapper..cctor() in c:\Users\Michael\Documents\GitHub\TestComposite\TestComposite\GoodCompositeMapping\SessionMapper\Mapper.cs:line 17
       InnerException:  


..chances are you are using a wrong mapping:

ManyToOne(x => x.ProductCategory, pm =>
    {
        pm.Column("ProductId");
        pm.Column("CategoryId");
    });

I saw a solution from stackoverflow that works:
ManyToOne(x => x.ProductCategory,
    c => c.Columns(
        new Action<NHibernate.Mapping.ByCode.IColumnMapper>[]
        {
            x  => x.Name("ProductId"),                        
            x  => x.Name("CategoryId")
        }));

This is the shorthand:
ManyToOne(x => x.ProductCategory, c => c.Columns(x => x.Name("ProductId"), x => x.Name("CategoryId")));


Happy Coding! ツ

Wednesday, December 18, 2013

Say No to ViewData and ViewBag

We've all been there, we got a perfect Model/ViewModel for the view…


public class HomeController : Controller
{

    public ActionResult Index()
    {

        var people = new[]
        {
            new Person { Firstname = "Ely", Lastname = "Buendia"},
            new Person { Firstname = "Raymund", Lastname = "Marasigan"},
            new Person { Firstname = "Buddy", Lastname = "Zabala"},
            new Person { Firstname = "Marcus", Lastname = "Adoro"},
        };

        return View(people);

    } // Index Action

} //Home Controller    


View:

@model IEnumerable<TestAdhocViewModel.Models.Person>

 
<table>    
@foreach (var p in Model)
{
    <tr>
        <td>@p.Firstname</td>
        <td>@p.Lastname</td>
    </tr>
}
</table>


...and then one day, there's a new requirement to bring new info on the view.

You can either put it in ViewData or ViewBag. However, you reluctantly wanted to put those info on ViewData/ViewBag. It pains you to see the contract(Model/ViewModel) between the controller and the view is being violated in the broad daylight, the various information are located in disparate sources, some of them are stored in strongly-typed Model/ViewModel but some are in ViewData/ViewBag. ViewData/ViewBag mars the beauty of operating exclusively within the domain of Model/ViewModel.


You can serialize/deserialize the anonymous types with JSON, but you will lose the benefit of autocomplete. Dynamic types are not navigable. Just because you could doesn't mean you should


So it's safe to say we all love our strongly-typed language. C#, a language so strongly-typed so we don't have to type strongly, thanks autocomplete! :D


We can introduce a view model, but it's too ceremonial when we just wanted to bring only a few new info to view. Scratch that, there's nothing ceremonial with view model when it's done on an ad hoc approach. Whether or not there is really a place for adhocly things to occur on a very formalized system(system that leads to class explosions(read: gazillion of classes), tends to be rampant on strongly-typed language) is up for another contentious discussion; we will not go into that.


When an approach is too ceremonial(read: tedious), we tend to forego that approach, we tend to use the duct tape approach, e.g., we tend to use ViewData/ViewBag, Session


What we really don't want is a view model that is just being used on one part of the system only, yet it pollutes the global namespace; classes in global namespace tends to give the illusion that a view model is very reusable. We wanted that ad hoc view model to be local on one part of the system only, that is that view model should be visible on that part only.


Without further ado, just declare the ViewModel right on the controller only

public class HomeController : Controller
{

    public ActionResult Index()
    {

        var people = new[]
            {
                new Person { Firstname = "Ely", Lastname = "Buendia"},
                new Person { Firstname = "Raymund", Lastname = "Marasigan"},
                new Person { Firstname = "Buddy", Lastname = "Zabala"},
                new Person { Firstname = "Marcus", Lastname = "Adoro"},
            };


        var band = new Band
            {
                BandName = "Eraserheads",
                Members = people
            };
        
        return View(band);

    } // Index Action


    public class Band
    {
        public string BandName { get; set; }
        public IEnumerable<Person> Members { get; set; }
    }

} //Home Controller



View:


@model TestAdhocViewModel.Controllers.HomeController.Band

 
@Model.BandName

 
<table>        
    @foreach (var p in Model.Members)
    {
        <tr>
            <td>@p.Firstname</td>
            <td>@p.Lastname</td>
        </tr>
    }
</table>


If it still feels like you violated a contract between your controller and view, as there's a big impact on your code when the shape of your object changes, i.e., the code changed to: foreach(var p in Model.Members) instead of retaining the old code: foreach(var p in Model), and you wanted a lesser change in your code, tap the features of your language. In C#, you can provide an enumerator for your class instance. Redefine your class to this:


public class Band : IEnumerable<Person>
{
    public string BandName { get; set; }
    // using internal, Members property is accessible to controller only, is not visible on views
    internal IEnumerable<Person> Members { get; set; }

    public IEnumerator<Person> GetEnumerator() { return Members.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}

With that, you can use the old code on foreach, i.e., you can just use the Model directly on foreach:


@model TestAdhocViewModel.Controllers.HomeController.Band

 
@Model.BandName

 
<table>        
    @foreach (var p in Model)
    {
        <tr>
            <td>@p.Firstname</td>
            <td>@p.Lastname</td>
        </tr>
    }
</table>


For single object, you can apply the same concept above, just use inheritance, if you have this code..

public ViewResult Detail(int id)
{
    var p = new Person
        {
            Firstname = "Ely",
            Lastname = "Buendia"
        };
    
    return View(qp);
} 

View:
@model TestAdhocViewModel.Models.Person

 
<p>Firstname: @Model.Firstname</p>
<p>Lastname: @Model.Lastname</p>


..and you wanted just to bring another information to view, create a derived class inside the controller and inherit the existing Model/ViewModel:

public class HomeController : Controller
{
    public ViewResult Detail(int id)
    {
        var p = new Person
            {
                Firstname = "Ely",
                Lastname = "Buendia"
            };
        var qp = new QualifiedPerson();
        qp.Firstname = p.Firstname;
        qp.Lastname = p.Lastname;
        qp.IsQualified = true;
        
        return View(qp);
    } 

    public class QualifiedPerson : Person
    {
        public bool IsQualified { get; set; }
    }
    
} //Home Controller

This is now your view with minimal modification, just change the model on model directive:


@model TestAdhocViewModel.Controllers.HomeController.QualifiedPerson
 
<p>Firstname: @Model.Firstname</p>  @* Look Ma! No Changes! *@
<p>Lastname: @Model.Lastname</p> @* Look Pa! No Changes! *@
<p>Qualified: @Model.IsQualified</p>

Assigning each values from base class to derived class is tedious though. Just use the awesome ValueInjecter, a.k.a. Omu Value Injecter



public class HomeController : Controller
{
    public ViewResult Detail(int id)
    {
        var p = new Person
            {
                Firstname = "Ely",
                Lastname = "Buendia"
            };
        var qp = new QualifiedPerson();
        qp.InjectFrom(p);
 
        qp.IsQualified = true;

        return View(qp);
    } 

    public class QualifiedPerson : Person
    {
        public bool IsQualified { get; set; }
    }
    
} //Home Controller


Then just use the InjectFrom extension method to copy the values from base class to derived class


Another beauty of placing the new information to their adhoc model/viewmodel, when the model/viewmodel doesn't feel adhocly anymore (e.g., it can be reused, merging multiple model/viewmodel service calls into one), it's easy to move that model/viewmodel to global namespace (e.g., to WCF), and it will only incur minimal adjustments to your controller and view. Contrast that to passing your related information to view in a non-cohesive manner, i.e., some of the info are in model/viewmodel and some are in ViewData/ViewBag, it will incur more adjustments to your code to use the refactored related info. Use ViewData and ViewBag sparingly.


Can we say goodbye to ViewData and ViewBag now?


Happy Coding! ツ

Sunday, December 8, 2013

Pragmatic Domain-Driven Design

There's a DDD, then there's a pragmatic DDD. When we say pragmatic, it means the application must not sacrifice performance


You wanted to get the count of the person's hobbies and you wanted your code to be performant.

public class Person
{
    public virtual int PersonId { get; set; }    
    public virtual string Name { get; set; }
    
    public virtual IList<Hobby> Hobbies { get; set; }
}


This is not DDD. DDD must encapsulate, if we access Hobbies count directly we "can't" add any further condition(say only count the active hobbies) on it and expect the code to be performant, see further comments below.

var p = session.Load<Person>(1);
Console.WriteLine("Count: {0}", p.Hobbies.Count());


This is DDD, intelligence are encapsulated by the domain model. And this is also performant, the list is not eagerly-loaded, the count is performed directly by the database

public virtual int FavoriteHobbiesCount
{
    get
    {
        // Thanks Extra Lazy! This is on PersonMapping:
        //    rel.Lazy(NHibernate.Mapping.ByCode.CollectionLazy.Extra);

        // With Extra Lazy, counting will be performed at the database-side instead of counting the in-memory objects
        return this.Hobbies.Count();
    }
}

// On Main()
var p = session.Load<Person>(1);
var count = p.FavoriteHobbiesCount;
Console.WriteLine("Count: {0}", count);    

Output:


NHibernate:
    SELECT
        person0_.person_id as person1_0_0_,
        person0_.first_name as first2_0_0_,
        person0_.last_name as last3_0_0_
    FROM
        person person0_
    WHERE
        person0_.person_id=:p0;
    :p0 = 1 [Type: Int32 (0)]
NHibernate:
    SELECT
        count(favorite_hobby_id)
    FROM
        favorite_hobby
    WHERE
        person_id=:p0;
    :p0 = 1 [Type: Int32 (0)]
Count: 10





However, that code is not future-proof, Extra Lazy won't work efficiently when you add a condition on the list. i.e., the collection will be eagerly-loaded when you add a condition on it.

public virtual int FavoriteHobbiesCount
{
    get
    {
        // Thanks Extra Lazy! This is on PersonMapping
        //     rel.Lazy(NHibernate.Mapping.ByCode.CollectionLazy.Extra);

        // Hobbies' items will be eagerly-loaded when we add a condition on its Count even we use Extra Lazy
        return this.Hobbies.Count(x => x.IsActive); 
    }
}

// On Main()
var p = session.Load<Person>(1);
var count = p.FavoriteHobbiesCount;
Console.WriteLine("Count: {0}", count);    

Output:

NHibernate:
    SELECT
        person0_.person_id as person1_0_0_,
        person0_.first_name as first2_0_0_,
        person0_.last_name as last3_0_0_
    FROM
        person person0_
    WHERE
        person0_.person_id=:p0;
    :p0 = 1 [Type: Int32 (0)]
NHibernate:
    SELECT
        favoriteho0_.person_id as person2_1_,
        favoriteho0_.favorite_hobby_id as favorite1_1_,
        favoriteho0_.favorite_hobby_id as favorite1_1_0_,
        favoriteho0_.person_id as person2_1_0_,
        favoriteho0_.hobby as hobby1_0_,
        favoriteho0_.is_active as is4_1_0_
    FROM
        favorite_hobby favoriteho0_
    WHERE
        favoriteho0_.person_id=:p0;
    :p0 = 1 [Type: Int32 (0)]
Count: 9


The Count(x => x.IsActive) happens on application-side only, instead of being run on database.


To fix the slow performance, we must directly query the database. Pass an IQueryable to Person:


public virtual int GetFavoriteActiveHobbiesCountFromQueryable(IQueryable<FavoriteHobby> fh)
{            
    return fh.Count(x => x.Person == this && x.IsActive);            
}

    
// On Main()
var p = session.Load<Person>(1);
var count = p.GetFavoriteActiveHobbiesCountFromQueryable(s.Query<FavoriteHobby>()); 
Console.WriteLine("Count: {0}", count);    


Output:

NHibernate:
    SELECT
        person0_.person_id as person1_0_0_,
        person0_.first_name as first2_0_0_,
        person0_.last_name as last3_0_0_
    FROM
        person person0_
    WHERE
        person0_.person_id=:p0;
    :p0 = 1 [Type: Int32 (0)]
NHibernate:
    select
        cast(count(*) as int4) as col_0_0_
    from
        favorite_hobby favoriteho0_
    where
        favoriteho0_.person_id=:p0
        and favoriteho0_.is_active=TRUE;
    :p0 = 1 [Type: Int32 (0)]
Count: 9


However, you'll notice that even we don't access any of the property of Person, the Person model is still eagerly-loaded from database. NHibernate will eagerly-load the model when we access any of its properties/methods, regardless of being mapped or unmapped.


To really fix that slow performance, move the model's behavior to extension method:

public static class PersonMethodsWithPerformanceConcerns
{
    public static int GetActiveFavoriteHobbies(this Person p, IQueryable<FavoriteHobby> fh)
    {            
        Console.WriteLine("Extension method version");
        return fh.Count(x => x.Person == p && x.IsActive);
    }
}


// On Main()
var p = session.Load<Person>(1);
var count = p.GetActiveFavoriteHobbies(s.Query<FavoriteHobby>()); 
Console.WriteLine("Count: {0}", count);

Output:

Extension method version
NHibernate:
    select
        cast(count(*) as int4) as col_0_0_
    from
        favorite_hobby favoriteho0_
    where
        favoriteho0_.person_id=:p0
        and favoriteho0_.is_active=TRUE;
    :p0 = 1 [Type: Int32 (0)]
Count: 9


That's it, performance must not be compromised on the altar of DDD


Full code: https://github.com/MichaelBuen/TestAggregate


Update 2018-May-20

On NHibernate 5, the collection will not be eager-loaded anymore when adding a condition on collection. It will perform a real database query instead. Prior to 5, this:

public virtual int FavoriteHobbiesCount
{
    get
    {
        // Thanks Extra Lazy! This is on PersonMapping
        //     rel.Lazy(NHibernate.Mapping.ByCode.CollectionLazy.Extra);

        // Hobbies' items will be eagerly-loaded when we add a condition on its Count even we use Extra Lazy
        return this.Hobbies.Count(x => x.IsActive); 
    }
}

will run this query, and perform the Count on application instead.
NHibernate:
    SELECT
        favoriteho0_.person_id as person2_1_,
        favoriteho0_.favorite_hobby_id as favorite1_1_,
        favoriteho0_.favorite_hobby_id as favorite1_1_0_,
        favoriteho0_.person_id as person2_1_0_,
        favoriteho0_.hobby as hobby1_0_,
        favoriteho0_.is_active as is4_1_0_
    FROM
        favorite_hobby favoriteho0_
    WHERE
        favoriteho0_.person_id=:p0;
    :p0 = 1 [Type: Int32 (0)]


With NHibernate 5, just add AsQueryable() on an entity's collection property, and NHibernate will happily run the query from the database instead, even if there's a condition on collection's query.


public virtual int FavoriteHobbiesCount
{
    get
    {
        // Hobbies' items will not be be eagerly-loaded anymore on NHibernate 5 even when we add a condition on its Count.
        return this.Hobbies.AsQueryable().Count(x => x.IsActive); 
    }
}

The resulting query would be like:
NHibernate:
    SELECT
        cast(count(*) as int4) as col_0_0_
    FROM
        favorite_hobby favoriteho0_
    WHERE
        favoriteho0_.person_id=:p0
        and favoriteho0_.is_active=:p1;
    :p0 = 1 [Type: Int32 (0)], :p1 = true [Type: Boolean]


Happy Computing! ツ

Thursday, December 5, 2013

Let the API do the heavy lifting

Instead of concatenating directory and filename manually:

string dir = @"C:\Windows";
string filename = "notepad.exe";
Console.WriteLine(dir + @"\" + filename);


Use Path.Combine:

string dir = @"C:\Windows";
string filename = "notepad.exe";
Console.WriteLine(Path.Combine(dir, filename));


Output: C:\Windows\notepad.exe


Aside from it take care of the nuances of platform differences(slash for *nix-based systems (e.g. Mono on Linux), backslash for Windows-based), it also takes care of trailing slash/backslash of the directory


The output of the following is still: C:\Windows\notepad.exe

string dir = @"C:\Windows\";
string filename = "notepad.exe";
Console.WriteLine(Path.Combine(dir, filename));


C# on Unix: http://ideone.com/rTACSJ

C# on Windows: http://dotnetfiddle.net/kxVNW5



Happy Coding! ツ