Friday, August 22, 2014

Why I love yield return

Aside from it's memory efficient as compared to eagerly populating list: http://ideone.com/QxU7Sn

..it saves us a lot of boilerplate codes too, there was once in C#'s life that there's no yield return magic yet, we have to contend with iterator design pattern, and that entails a lot of boilerplates code: http://www.ienablemuch.com/2010/12/lazy-loading-fibonacci.html


Long and short of why yield return is so awesome:
http://www.ienablemuch.com/2012/08/use-components-that-uses-yield-return.html


Use yield return when returning IValidatableObect, or any list for that matter. There's no need to create a List<ValidationResult>
http://www.ienablemuch.com/2011/07/ivalidatableobject-client-side.html

Thursday, August 21, 2014

Find changeset number by comment

Use VS commandline tool:
Start > Programs > Microsoft Visual Studio 2012 > Developer Tools > Developer Command Prompt for VS2012


How to find broken promises:



For some strange reason, the Visual Studio 2012 plugin Find Changeset By Comment has installation error when I add it on Visual Studio, so I have to use a commandline tool

So that's how I manage to find codes I can't remember the changeset number

That's also how I find the changesets of a code review when the engineer forgot to include the changeset numbers of their code

To automate that task install AutoHotkey, then include this script. #c means Windows+C

#c::
InputBox, UserInput, View Changeset List, Please enter a comment,,,,,,,,div.*by.*zero
Run %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Tools\VsDevCmd.bat" & tf history $/ /noprompt /recursive | findstr /i /r /c:"%UserInput%""
return


So when you press Windows+C this will appear:




The script then runs the TFS commandline tool. The VS plugin can't be installed on my dev machine, but at least I can find changeset anytime even Visual Studio is not open, so I got that goin' for me, which is nice

Wednesday, August 6, 2014

Programming without the programming language

I agree with Jon Skeet's assertion that it's better to know the idiomatic way to program with the programming language. There are cases though that using something fancy language operation like compounding a value to another variable, makes the solution look non-intuitive




I forgot how my old Fibonacci solution was intuitive to me:

static IEnumerable<int> Fibonacci()
{
    int a = 0,  b = 1;
                         
    for(;;)
    {        
        yield return a;
        int n = a;
        a += b;
        b = n;          
    }
}


Perhaps making a language-driven solution e.g., increment, makes something non-intuitive in the long run and hard to reason out


When I tried to plot the values of that old fibonacci solution, this is how a bit jumbled-looking the values are, read this from up to down, then left to right

A 0 1 1 2 3 5
B 1 0 1 1 2 3
Y 0 1 1 2 3 5
N 0 1 1 2 3 5




Then when I wanted to recall that fibonacci code off the top of my head, sadly I can't, so I try solve it with pencil-and-paper, following is what I came up with, and it's a little different from the old solution I've made before. This is one of few instances where not having eidetic or retentive memory is good, the brain is flushing out old memories and it is stimulated to be creative on coming up with new and elegant approaches. Read the following from up to down, then left to right


Pencil-and-paper solution:


A 0 1 1 2 3 5
B 1 1 2 3 5 8
Y 0 1 1 2 3 5
N 1 2 3 5 8 13


The values' progression look symmetrical and it maps nicely to code too:

static IEnumerable<int> Fibonacci()
{
    int a = 0, b = 1;
      
    for(;;) 
    {      
        yield return a;
        int n = a + b;
        a = b;
        b = n;   
    }       
}


The only drawback of not having eidetic memory is your stock knowledge tend to decrease or get rusty. But who needs eidetic memory when you can store your knowledge to blog? Another advantage of having a blog is you can compare if your new approach improved

Wednesday, July 23, 2014

Making stringly-typed code palatable via implicit operator

Strongly-typed code is all the rage now, but some of us still manages to stash various information to string instead of structuring the information to a class


If you can't avoid stringly-typed code, just eliminate its boilerplate codes. Use implicit operator to eliminate them


using System;

using System.Collections.Generic;


using System.Linq;


namespace Craft
{
    class MainClass
    {

        public static void Main (string[] args)
        {
            var list = new Dictionary<string,decimal> ();
            list.Add ("1_VariablePayBasis", 1337);
            list.Add ("1_DecisionAmount", 168);
            list.Add ("3_BasePay", 5201314);


            foreach (var kv in list) {

                // boilerplate codes
                string[] strings = kv.Key.Split('_');
                int pk = Convert.ToInt32(strings [0]);
                string fieldName = strings [1];


                Console.WriteLine ("{0} {1} - {2}", pk, fieldName, kv.Value);
            }
            Console.WriteLine();


            // via explicit casting, being explicit with implicit :-)
            foreach (var fv in list.Select(x => (FieldValue)x)) {
                Console.WriteLine ("{0} {1} - {2}", fv.PrimaryKey, fv.FieldName, fv.Value);
            }
            Console.WriteLine();


            // neat implicit! it still feel a bit explicit though. we can't use var here
            foreach (FieldValue fv in list) {
                Console.WriteLine ("{0} {1} - {2}", fv.PrimaryKey, fv.FieldName, fv.Value);
            }

        }
    }

    public class FieldValue
    {
        public int PrimaryKey { get; set; }
        public string FieldName { get; set; }

        public decimal Value { get; set; }



        public static implicit operator FieldValue(KeyValuePair<string,decimal> kv)
        {
            string[] strings = kv.Key.Split('_');
            int pk = Convert.ToInt32(strings [0]);
            string fieldName = strings [1];

            return new FieldValue { PrimaryKey = pk, FieldName = fieldName, Value = kv.Value };
        }
    }
   
}


Live Code https://dotnetfiddle.net/qX2UeA


Happy Coding! ツ

Sunday, July 20, 2014

protected internal

Anne Epstein has a great NHibernate article on making an entity with a composite primary key be lazy-loading-capable and cache-ready. Just forgot to hide the ORM low-level plumbing concerns (the composite primary key) from the domain model


Similar to AdventureWorks' EmployeePayHistory. Just use protected internal to hide that ORM low-level plumbing concern
public class PersonPayHistory
{
    PersonPayHistoryCompositePK _pk = new PersonPayHistoryCompositePK();
    protected internal PersonPayHistoryCompositePK PersonPayHistoryCompositePK 
    { 
        get { return _pk; }
        set { _pk = value; }
    }

    Person _person;
    public virtual Person Person 
    { 
        get { return _person; }
        set 
        {
            _person = value;
            _pk.PersonId = _person.PersonId;
        }
    }                    

    public virtual DateTime RateDate
    {
        get { return _pk.RateDate; }
        set { _pk.RateDate = value; }
    }

    public virtual decimal Rate { get; set; }
}


So we will not make the mistake of saving our entity through those composite primary key:

var ph = new PersonPayHistory
{     
    Person = session.Load<Person>(1),
    RateDate = DateTime.Today,

    Rate = 1337M
};


session.Save (ph);
session.Flush ();

Wednesday, July 16, 2014

LEFT JOIN GROUP BY HAVING on NHibernate

EmployeePayHistory payHistory = null;
   
var persons =
    session.QueryOver<Person>()
    .Left.JoinAlias(p => p.PayHistories, () => payHistory)                        
    .Where(
        Restrictions.Eq(
            Projections.Count(() => payHistory.EmployeePayHistoryCompositePK.BusinessEntityId)
        , 0
        )
    )    
    .SelectList(x => x
        .SelectGroup(p => p.BusinessEntityId)
        .SelectGroup(p => p.FirstName)
        .SelectGroup(p => p.LastName)                            
        .SelectCount(p => payHistory.EmployeePayHistoryCompositePK.BusinessEntityId)
    )
    .List<object[]>()
    .Select(cols => new
    {
        Id = (int)cols[0],
        FirstName = (string)cols[1],
        LastName = (string)cols[2],
        Count = (int)cols[3]
    });

persons.ToList();


Generated SQL:
SELECT
         this_.BusinessEntityId as y0_,
         this_.FirstName as y1_,
         this_.LastName as y2_,
         count(payhistory1_.BusinessEntityId) as y3_
     FROM
         Person.Person this_
     left outer join
         HumanResources.EmployeePayHistory payhistory1_
             on this_.BusinessEntityId=payhistory1_.BusinessEntityId
     GROUP BY
         this_.BusinessEntityId,
         this_.FirstName,
         this_.LastName
     HAVING
         count(payhistory1_.BusinessEntityId) = @p0;
     @p0 = 0 [Type: Int32 (0)]


One-stop shop code, complete working code. Just install AdventureWorks2008R2 database:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Criterion;
using NHibernate.Mapping.ByCode.Conformist;
 
using NHibernate.Linq;

 
namespace Craft
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var session = Mapper.SessionFactory.OpenSession())
            {
                
         EmployeePayHistory payHistory = null;

         var persons =
                     session.QueryOver<Person>()
                    .Left.JoinAlias(p => p.PayHistories, () => payHistory)
                    .Where(
                         Restrictions.Eq(
                             Projections.Count(() => payHistory.EmployeePayHistoryCompositePK.BusinessEntityId)
                             , 0
                         )
                     )

                    .SelectList(x => x
                        .SelectGroup(p => p.BusinessEntityId)
                        .SelectGroup(p => p.FirstName)
                        .SelectGroup(p => p.LastName)                            
                        .SelectCount(p => payHistory.EmployeePayHistoryCompositePK.BusinessEntityId)
                    )
                   .List<object[]>()
                   .Select(cols => new
                   {
                      Id = (int)cols[0],
                      FirstName = (string)cols[1],
                      LastName = (string)cols[2],
                      Count = (int)cols[3]
                   });

                persons.ToList();



                Console.ReadLine();
           } // using
        } // Main
    } //class Program
 
 
    public static class Mapper
    {
        static NHibernate.ISessionFactory _sessionFactory = Mapper.GetSessionFactory();
 
 
        public static NHibernate.ISessionFactory SessionFactory
        {
            get { return _sessionFactory; }
        }
 
        static NHibernate.ISessionFactory GetSessionFactory()
        {
            var mapper = new NHibernate.Mapping.ByCode.ModelMapper();
 
            mapper.AddMappings(
                new[] { 
                    typeof(PersonMapping) , typeof(EmployeePayHistoryMapping)
                });
 
 
            var cfg = new NHibernate.Cfg.Configuration();
 
            cfg.DataBaseIntegration(c =>
            {
                c.Driver<NHibernate.Driver.Sql2008ClientDriver>();
                c.Dialect<NHibernate.Dialect.MsSql2008Dialect>();
                c.ConnectionString = "Server=.;Database=AdventureWorks2008R2;Trusted_Connection=True;";
 
                c.LogFormattedSql = true;
                c.LogSqlInConsole = true;
            });
 
 
 
            HbmMapping domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
 
            cfg.AddMapping(domainMapping);
 
 
 
            var sf = cfg.BuildSessionFactory();
 
            return sf;
        }
    }
 
 
    public class PersonMapping : ClassMapping<Person>
    {
        public PersonMapping()
        {
            Table("Person.Person");
            Id(x => x.BusinessEntityId);
 
            Property(x => x.FirstName);
            Property(x => x.LastName);
 
            Bag(list => list.PayHistories, rel => rel.Key(k => k.Column("BusinessEntityId")), relType => relType.OneToMany());
 
        }
    }
 
    public class EmployeePayHistoryMapping : ClassMapping<EmployeePayHistory>
    {
        public EmployeePayHistoryMapping()
        {
            Table("HumanResources.EmployeePayHistory");
 
            ComponentAsId(x => x.EmployeePayHistoryCompositePK, x =>
            {
                x.Property(y => y.BusinessEntityId);
                x.Property(y => y.RateChangeDate);
            });
          
            ManyToOne(x => x.Person, k => 
            { 
                k.Column("BusinessEntityId"); 
                k.Insert(false); 
                k.Update(false); 
            });

            Property(x => x.Rate);
        }
    }
 
    
 
    public class Person
    {
        public virtual int BusinessEntityId { get; set; }
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
 
        public virtual IList<EmployeePayHistory> PayHistories { get; set; }
    }
 
 
    public class EmployeePayHistory
    {
        EmployeePayHistoryCompositePK _pk = new EmployeePayHistoryCompositePK();
        public virtual EmployeePayHistoryCompositePK EmployeePayHistoryCompositePK 
        { 
            get { return _pk; } set { _pk = value; }
        }
 
        Person _person;
        public virtual Person Person 
        { 
            get { return _person; }
            set 
            {
                _person = value;
                _pk.BusinessEntityId = _person.BusinessEntityId;
            }
        }        
 
        public virtual decimal Rate { get; set; }
    }
 
 
    // AdventureWorks is fond of composite primary key. Composite unique is better
    public class EmployeePayHistoryCompositePK
    {
        public virtual int BusinessEntityId { get; set; }
        public virtual DateTime RateChangeDate { get; set; }
 
        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;
 
            var t = obj as EmployeePayHistoryCompositePK;
            if (t == null)
                return false;
 
            if (BusinessEntityId == t.BusinessEntityId && RateChangeDate == t.RateChangeDate)
                return true;
 
            return false;
        }
 
        public override int GetHashCode()
        {
            return (BusinessEntityId + "|" + RateChangeDate).GetHashCode();
        }
    }
}


Happy Coding! ツ


Related: http://www.ienablemuch.com/2014/07/orm-expectations.html

ORM Expectations




Sometimes it's hard to give clear instruction, especially if you are not inclined to be exact with your instruction:

var persons = 
     from p in session.Query<Person>()
     select new 
     {
         p.BusinessEntityId, p.FirstName, p.LastName, Count = p.PayHistories.Count()
     };


What's the SQL generated by that Linq?

NHibernate-generated SQL:
 
select
    person0_.BusinessEntityId as col_0_0_,
    person0_.FirstName as col_1_0_,
    person0_.LastName as col_2_0_,
    (select
        cast(count(*) as INT)
    from
        HumanResources.EmployeePayHistory payhistori1_
    where
        person0_.BusinessEntityId=payhistori1_.BusinessEntityId) as col_3_0_
from
    Person.Person person0_                    
 
 
Entity Framework-generated SQL:
 
SELECT 
    [Extent1].[BusinessEntityId] AS [BusinessEntityId],
    [Extent1].[LastName] AS [LastName],
    [Extent1].[FirstName] AS [FirstName],
    (SELECT
        COUNT(1) AS [A1]
    FROM 
        [HumanResources].[EmployeePayHistory] AS [Extent2]
    WHERE 
        [Extent1].[BusinessEntityId] = [Extent2].[BusinessEntityId]) AS [C1]
FROM 
    [Person].[Person] AS [Extent1]

"That's not efficient! That's not what I wanted" you told yourself

I've often felt that much of the frustration with ORMs is about inflated expectations -- http://martinfowler.com/bliki/OrmHate.html

There are developers who insists that the above should generate a GROUP BY COUNT. Don't expect a GROUP BY will be generated on the Linq you've made above. Who told you that computers will do what you wanted or hoped them to do? You cannot wish your way around on solving a problem, especially on giving instructions to computers

With that being said, let's be exact with our instructions. Let's cut to the chase, following is how to do efficient aggregation in NHibernate and Entity Framework. Initial step, flatten the hierarchical objects via SelectMany; final step, do a group by on the flattened object. Easy-peasy!

var persons =
    from p in session.Query<Person>()
        .SelectMany(x => x.PayHistories, (person, payHistory) => new {person, payHistory})
    group p by new {p.person.BusinessEntityId, p.person.FirstName, p.person.LastName} into g
    select new {g.Key, Count = g.Count()};

SQL output:
NHibernate-generated SQL:
 
select
    person0_.BusinessEntityId as col_0_0_,
    person0_.FirstName as col_1_0_,
    person0_.LastName as col_2_0_,
    cast(count(*) as INT) as col_3_0_
from
    Person.Person person0_
inner join
    HumanResources.EmployeePayHistory payhistori1_
        on person0_.BusinessEntityId=payhistori1_.BusinessEntityId
group by
    person0_.BusinessEntityId ,
    person0_.FirstName ,
    person0_.LastName
 

Entity Framework-Generated SQL. Go home Entity Framework, you're drunk!

SELECT
    [GroupBy1].[K1] AS [BusinessEntityId],
    [GroupBy1].[K4] AS [C1],
    [GroupBy1].[K3] AS [FirstName],
    [GroupBy1].[K2] AS [LastName],
    [GroupBy1].[A1] AS [C2]
    FROM ( SELECT
        [Join1].[K1] AS [K1],
        [Join1].[K2] AS [K2],
        [Join1].[K3] AS [K3],
        [Join1].[K4] AS [K4],
        COUNT([Join1].[A1]) AS [A1]
        FROM ( SELECT
            [Extent1].[BusinessEntityId] AS [K1],
            [Extent1].[LastName] AS [K2],
            [Extent1].[FirstName] AS [K3],
            1 AS [K4],
            1 AS [A1]
            FROM  [Person].[Person] AS [Extent1]
            INNER JOIN [HumanResources].[EmployeePayHistory] AS [Extent2] ON [Extent1].[BusinessEntityId] = [Extent2].[BusinessEntityId]
        )  AS [Join1]
        GROUP BY [K1], [K2], [K3], [K4]
    )  AS [GroupBy1]

With the exact instructions, the computer will do what we told it to do, NHibernate generated what we wanted, a COUNT via efficient GROUP BY, instead of subquery in SELECT. However, even giving an exact instruction is not a guarantee that the computer will do what we told it to do, look at how stubborn Entity Framework is; though also it doesn't generate a subquery for COUNT, the approach and efficiency of Entity Framework-generated SQL is questionable and hard to reason about


A keen developer shall observe, the GROUP BY we made is not exactly the same as the subquery approach; the subquery approach could report persons without employee pay history while the INNER JOIN could not. We should do a LEFT JOIN and make a conditional count on non-null. Entity Framework solution:


var query = 
    from p in db.Set<Person>()
        .SelectMany(x => x.PayHistories.DefaultIfEmpty(), (person, payHistory) => new {person, payHistory })
    group p by new { p.person.BusinessEntityId, p.person.FirstName, p.person.LastName } into g
    select new { g.Key, Count = g.Sum(x => x.payHistory != null ? 1 : 0) };


Entity Framework-generated SQL:
SELECT
    [GroupBy1].[K1] AS [BusinessEntityId],
    [GroupBy1].[K4] AS [C1],
    [GroupBy1].[K3] AS [FirstName],
    [GroupBy1].[K2] AS [LastName],
    [GroupBy1].[A1] AS [C2]
    FROM ( SELECT
        [Join1].[K1] AS [K1],
        [Join1].[K2] AS [K2],
        [Join1].[K3] AS [K3],
        [Join1].[K4] AS [K4],
        SUM([Join1].[A1]) AS [A1]
        FROM ( SELECT
            [Extent1].[BusinessEntityId] AS [K1],
            [Extent1].[LastName] AS [K2],
            [Extent1].[FirstName] AS [K3],
            1 AS [K4],
            CASE WHEN ( NOT (([Extent2].[BusinessEntityId] IS NULL) AND ([Extent2].[RateChangeDate] IS NULL))) THEN 1 ELSE 0 END AS [A1]
            FROM  [Person].[Person] AS [Extent1]
            LEFT OUTER JOIN [HumanResources].[EmployeePayHistory] AS [Extent2] ON [Extent1].[BusinessEntityId] = [Extent2].[BusinessEntityId]
        )  AS [Join1]
        GROUP BY [K1], [K2], [K3], [K4]
    )  AS [GroupBy1]

Unfortunately, though it's a relatively easy fix on Entity Framework, we just added a DefaultIfEmpty and do a conditional count on non-null, the same won't work on NHibernate. As of the time of this writing, NHibernate Linq doesn't support DefaultIfEmpty, it can't produce a LEFT JOIN on collection nor on manual joins. NHibernate has an API for that trivial task, and its API is more complex and longer than the problem it is solving :-)


EmployeePayHistory payHistory = null;
var persons =
    session.QueryOver<Person>()
    .Left.JoinAlias(p => p.PayHistories, () => payHistory)                        
    .SelectList(x => x
        .SelectGroup(p => p.BusinessEntityId)
        .SelectGroup(p => p.FirstName)
        .SelectGroup(p => p.LastName)                            
        .SelectCount(p => payHistory.EmployeePayHistoryCompositePK.BusinessEntityId)
    )
    .List<object[]>()
    .Select(cols => new
        {
            Id = (int)cols[0],
            FirstName = (string)cols[1],
            LastName = (string)cols[2],
            Count = (int)cols[3]
        });


NHibernate-generated SQL:
SELECT
    this_.BusinessEntityId as y0_,
    this_.FirstName as y1_,
    this_.LastName as y2_,
    count(payhistory1_.BusinessEntityId) as y3_
FROM
    Person.Person this_
left outer join
    HumanResources.EmployeePayHistory payhistory1_
        on this_.BusinessEntityId=payhistory1_.BusinessEntityId
GROUP BY
    this_.BusinessEntityId,
    this_.FirstName,
    this_.LastName


With clear instructions and reasonable expectations, computers will do what you wanted it to do


Happy Coding! ツ