Thursday, January 9, 2014

I love the word The

Want to enforce SchemaName.TableName to your domain models (think AdventureWorks)? i.e., you wanted this:

var personList = 
    from p in session.Query<Person.Person>
    select p;

var storeList = 
    from s in session.Query<Sales.Store>
    select s;


You can't use namespace..

namespace Domain.Models
{
    namespace Person
    {
        public class Person
        {
        }
        public class BusinessEntityContact
        {
        }
    }


    namespace Sales
    {
        public class Store
        {
        }
    }
}


..as developers can opt out of Person or Sales namespace by importing the namespace through C#'s using, some would do this:

using Domain.Models.Sales;


.
.
.


var list = 
    from p in session.Query<Store>
    select p;




To achieve enforcement of Schema name on your domain classes, do this instead:

namespace Domain.Models
{
    public static class Person
    {
        public class Person
        {
        }
    
        public class BusinessEntityContact
        {
        }
    }

    public static class Sales
    {
        public class Store
        {
        }
    }
}

However that will not work, it's not allowed for the nested class to have the same name as its containing class, e.g., Person.Person. So we must use some convention to eliminate the compiler error through naming convention, e.g.:


namespace Domain.Models
{
    public static class PersonSchema
    {
        public class Person
        {
        }
    
        public class BusinessEntityContact
        {
        }
    }

    public static class SalesSchema
    {
        public class Store
        {
        }
    }
}

But I prefer prefixing the word The:


namespace Domain.Models
{
    public static class ThePerson
    {
        public class Person
        {
        }
    
        public class BusinessEntityContact
        {
        }
    }

    public static class TheSales
    {
        public class Store
        {
        }
    }
}


Using that convention, reading the code rolls off the tongue quite nicely:


var personList = 
    from p in session.Query<ThePerson.Person>
    select p;

var businessContactList = 
    from c in session.Query<ThePerson.BusinessContact>
    select c;


var storeList = 
    from s in session.Query<TheSales.Store>
    select s;


Sorry Entity Framework, the Set method doesn't cut it:

var list = 
    from s in context.Set<TheSales.Store>
    select s;


Happy Coding! ツ

Wednesday, January 8, 2014

Partial Class Is A Boon For Code Generator Developers

I got this following exception with NHibernate..

Cannot instantiate abstract class or interface: TestInheritance.DomainModels.BusinessEntity

..with these AdventureWorks2012 domain models:

public abstract class BusinessEntity
{
    public virtual int BusinessEntityID { get; set; }
}

public class Person : BusinessEntity
{
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
}

public class Employee : Person
{
    public virtual string NationalIDNumber { get; set; }
    public virtual string JobTitle { get; set; }
}

public class Store : BusinessEntity
{
    public virtual string Name { get; set; }        
}

The code I tried:

var list = s.Query<BusinessEntity>().ToList();


Basically, I just want to get all business entities. Upon reading this..

After suffering this error message for a while the reason turned out to be almost logical: In an @Inheritance of type Joined, there was an entry in the root table but no entry in any of the inheriting tables. -- Kolov



..it became obvious why mapping only the above domain models produces an error, there's some BusinessEntityID in abstract BusinessEntity that is not in any of the domain models above, the fallback of NHibernate is to instantiate the base class when its ID is not in the inheritance tree, hence resulting to an exception, since abstract classes cannot be instantiated. In fact, we can also make the error go away by making the BusinessEntity domain model (an abstract class) a concrete class, however there's no sense making BusinessEntity a concrete class.


Armed with the above knowledge in mind, I queried which tables are referencing the BusinessEntity domain model:

SELECT  
  ForeignTableSchema = KCU1.TABLE_SCHEMA
  ,ForeignConstraintName = KCU1.CONSTRAINT_NAME
  ,ForeignTableName = KCU1.TABLE_NAME 
  ,ForeignColumnName = KCU1.COLUMN_NAME
  ,ForeignOrdinalPosition = KCU1.ORDINAL_POSITION

  ,ReferencedTableSchema = KCU2.TABLE_SCHEMA
  ,ReferencedConstraintName = KCU2.CONSTRAINT_NAME
  ,ReferencedTableName = KCU2.TABLE_NAME 
  ,ReferencedColumnName = KCU2.COLUMN_NAME
  ,ReferencedOrdinalPosition = KCU2.ORDINAL_POSITION

   
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC 

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1 
  ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG  
  AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
  AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU2 
  ON KCU2.CONSTRAINT_CATALOG = RC.UNIQUE_CONSTRAINT_CATALOG  
  AND KCU2.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA 
  AND KCU2.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME 
  AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION 

WHERE KCU2.CONSTRAINT_NAME = 'PK_BusinessEntity_BusinessEntityID'
ORDER BY KCU1.TABLE_NAME

Here's the result:






Knowing that I forgot to include the Vendor domain model, I then mapped it, then the exception problem goes away! Just merely looking at the result above, it's not instantly obvious if the BusinessEntityAddress and/or BusinessEntityContact is the table(s) that is also causing the exception above. You can only infer it by looking at their primary key, if their primary key relates one-to-one to BusinessEntity, then those models needed be mapped too. However seeing they are not one-to-one to BusinessEntity, then not mapping them won't cause exception to the abstract BusinessEntity domain model, to wit:




As we can see, they are not an aggregate root, those domain models makes sense only within the domain of an another domain model. This is where things get tricky for the code generator, even if we can indicate that the BusinessEntity is an abstract domain model (hence we can prevent it from becoming the aggregate root to BusinessEntityAddress, BusinessEntityContact or any domain models for that matter), it's impossible for code generator to deduce on which aggregate root the BusinessEntityAddress and BusinessEntityContact belongs to. This is where the code generator needed an intervention from someone with business knowledge of the domain models, these models are meant to be mapped manually, partial class totally empowers this needed manual mapping.



Happy Coding! ツ



Mapping:
public class BusinessEntityMapping : ClassMapping<BusinessEntity>
{
    public BusinessEntityMapping()
    {
        Table("Person.BusinessEntity");
        Id(x => x.BusinessEntityID, m => m.Generator(NHibernate.Mapping.ByCode.Generators.Identity));            

    }
}


public class PersonMapping : JoinedSubclassMapping<Person>
{
    public PersonMapping()
    {

        Table("Person.Person");

        Key(k => k.Column("BusinessEntityID"));

        Property(x => x.FirstName);
        Property(x => x.LastName);
    }
}



public class EmployeeMapping : JoinedSubclassMapping<Employee>
{
    public EmployeeMapping()
    {
        Table("HumanResources.Employee");

        Key(k => k.Column("BusinessEntityID"));


        Property(x => x.NationalIDNumber);
        Property(x => x.JobTitle);
    }
}


public class StoreMapping : JoinedSubclassMapping<Store>
{
    public StoreMapping()
    {
        Table("Sales.Store");

        Key(x => x.Column("BusinessEntityID"));

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


public class VendorMapping : JoinedSubclassMapping<Vendor>
{
    public VendorMapping()
    {
        Table("Purchasing.Vendor");

        Key(x => x.Column("BusinessEntityID"));

        Property(x => x.AccountNumber);
        Property(x => x.Name);
    }
}

Tuesday, January 7, 2014

Polyfill: Web Developer's Version of "There's an app for that"™

Placeholder is not working on IE9 and below. Fortunately there's an app.. er.. "There's a polyfill for that!"™

To use placeholder on IE, just drop this polyfill to your site: http://jamesallardice.github.io/Placeholders.js/


Friday, January 3, 2014

Want to try out some piece of .NET code yet you don't want to accumulate clutters of solutions in your recent projects in Visual Studio?

I saw some answer on stackoverflow I need to try out:

static void Main() {
 
    string s1 = Regex.Replace("abcdefghik", "e",
        match => "*I'm a callback*");
 
    string s2 = Regex.Replace("abcdefghik", "c", Callback);
}
static string Callback(Match match) {
    return "*and so am i*";
}

But I don't want to create a new solution just for that smallish code. .NET fiddle to the rescue!
Example: http://dotnetfiddle.net/FSqLmM

And what's cooler with .NET Fiddle, is that it has auto-complete, unlike ideone

If only I can try snippets of NHibernate, Entity Framework, ASP.NET MVC or SignalR on .NET Fiddle, my folders will be a lot more tidy :D



Happy Coding! ツ

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! ツ