Tuesday, May 31, 2011

Learn to put up with Visual Studio, it's not perfect. Nothing is

An anecdote:

In VS, click Project (next to File,Edit,View), select Properties

then in Application tab (you'll notice you're already in 3.5), select the Target Framework to 2.0, then compile (it will error). then put it back again to 3.5, then compile again, the error will disappear

i think it is just a small glitch in Visual Studio, just fool the IDE :-)

Stupid if you may ask.

source: http://stackoverflow.com/questions/205644/error-when-using-extension-methods-in-c/383517#383517

And when clicking Update Service reference is a no joy undertaking; sometimes you have to remove the service reference, and then re-add it again. Sometimes you have to restart Visual Studio to make things take in effect, ah.. the dev's life! :-)

Another anecdote(from me, a colleague experienced it too), the first time one installed a nuget on his/her Visual Studio, his/her Visual Studio will become very slow. So when the colleague installed nuget on his Visual Studio for the first time, he noticed Visual Studio became very slow; and even he restarted Visual Studio, it's still very slow, I told him to restart his computer. Voila! his Visual Studio became snappy again.


First refuge of those who easily give up: http://stackoverflow.com/questions/205644/error-when-using-extension-methods-in-c/338452#338452

When it comes to choosing a jQuery component, don't be a sheeple

Sharing my same sentiment. Should selectively download which jQuery UI is needed on application, so far we only use datepicker, tab, accordion, dialog, draggable(for dialog need), resizable(for dialog need too). --> http://www.redfrogconsulting.com/love-jquery-hate-the-jquery-ui.php


Too many bloat on jQuery UI, there's an exploding, bouncing, clip, shake, pulsate animation in jQuery UI to name a few, you don't need them, there's also: droppable, position, progress bar, etc, you also don't need them.


Selectively download which ones you need, jQuery UI customizable download is user-friendly anyway, just uncheck then check which ones you need



If few years down the road and the whole jQuery UI become too bloated (say almost 300+ KB) to the point that it is heavier than your own content, I would call it far from being a standard. We're not sheeple folks, we don't need to put up with their boatload of bloat they're injecting in their jQuery components, especially if we don't use them. Let's be happy that we can selectively download (jquery-ui-1.8.12.custom.tab+accordion+datepicker+dialog+draggable+resizable.min.js) which ones we need on jQuery UI website; if there's no customized download facility on jQuery UI website, jQuery UI could receive flaks more than it deserves, and everybody will quickly find other jQuery components that is more lightweight than jQuery UI. Selectively choosing which jQuery UI you only need is the standard, downloading the whole package is silly.


jQuery Tools vs jQuery UI 14 KB(jQuery Tools) vs 209 KB(jQuery UI). jQuery Tools has the only most commonly used features a web program need, thus cutting down the bloat.

And the father(John Resig, see comment #5 of last link) of jQuery weigh in:
jQuery UI Tabs is only 6KB minified and gzipped, jQuery Tools Tabs is 1.5KB minified and gzipped – and that’s saying nothing of the features supported by both plugins.



See jQuery Tools in action


Download jQuery Tools. For future projects :-)

Sunday, May 29, 2011

When it comes to ORM, be mapping-agnostic

Why we need to be mapping-agnostic, especially when we are using a strongly-typed language? One way or another, the classes themselves are a form of mapping.


If you are using a non-strongly-typed language, mapping things explicitly is the way things are ought to be done. This hypothetical non-strongly-typed language warrants explicit mapping:

class Country
{
 CountryId;

 CountryName;
 Population;
 People;
}


class Band
{
 BandId;
  
 BandName;
 Fans;
}


class Person
{
 PersonId;

 PersonName;
 Country;
 FavoriteBand;
}

But the following classes and properties already has all the necessary information that your ORM need to automatically jumpstart mapping your classes to tables, your properties to fields.

public class Country
{
 public virtual int CountryId { get; set; }

 public virtual string CountryName { get; set; }
 public virtual int Population { get; set; }
 public virtual IList<Person> People { get; set; }
}


public class Band
{
 public virtual int BandId { get; set; }
  
 public virtual string BandName { get; set; }
 public virtual IList<Person> Fans { get; set; }
}



public class Person
{
 public virtual int PersonId { get; set; }

 public virtual string PersonName { get; set; }
 public virtual Country Country { get; set; }
 public virtual Band FavoriteBand { get; set; }
}

Aside from your properties has a type already, class reference on another class is already a clue for your ORM to map your class as many-to-one to another class, the IList is already a clue to your ORM that your class is one-to-many to the other class.


So don't let yourselves get caught up with the brewing tension between James Gregory and Fabio Maulo. Your strongly-typed code is already a form of mapping. NHibernate 3.2's built-in Fluent^H^H^H^H^H^HLoquacious-mapper is indeed loquacious. Maybe it's just me, but I've got a feeling that Loquacious mapper won't take off.


That being said, I still highly recommend James Gregory's Fluent mapper instead and its Auto Mapping; by far, Fluent NHibernate is still the simplest way to override some minor things that are not ought to be automapped. Still though, I want James Gregory to make the next Fluent NHibernate not internally process mappings as XMLs. Fluent NHibernate 2.0 FTW! go go go! 加油!

Saturday, May 28, 2011

Sql Server concurrency handling using its rowversion field type and Fluent NHibernate Auto Mapping

The model:
public class Product
{        
    public virtual int ProductId { get; set; }

    public virtual string ProductName { get; set; }
    public virtual string WarehouseLocation { get; set; }
    public virtual string LastAuditedBy { get; set; }
    public virtual int Quantity { get; set; }        
    public virtual byte[] TheRowversion { get; set; }
}


The concurrent update scenario:
class Program
{
    static void Main(string[] args)
    {
        var userA = Mapper.GetSessionFactory().OpenSession();
        var userB = Mapper.GetSessionFactory().OpenSession();
        
        // User A and User B happen to open the same record at the same time
        var a = userA.Get<Product>(1);
        var b = userB.Get<Product>(1);

        a.ProductName = "New & Improved" + a.ProductName + "!";

        b.WarehouseLocation = "Behind appliances section";
        b.LastAuditedBy = "Linus";
        b.Quantity = 7;

        userA.Save(a);
        userA.Flush();


        // This will fail. As the rowversion of the same record since it was first loaded, had 
        // already changed (the record was changed by User A first) when it's User B's time to save the same record.
        userB.Save(b);
        userB.Flush();

       
    }
}


DDL:
create table Product
(
ProductId int identity(1,1) not null primary key,
ProductName nvarchar(100) not null unique,
WarehouseLocation nvarchar(100) not null,
LastAuditedBy nvarchar(100) not null,
Quantity int not null,
TheRowversion rowversion not null
) 


Boilerplate code for mapping. If you decide to make all your tables' version column use Sql Server's built-in rowversion field type and use your own name for version column, you must do both line 59 and 65 respectively. Also, add the version convention to your ISessionFactory builder, line 36. The default(convention-over-configuration) rowversion column name when you don't implement line 59,65,36 is Version.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

using NHibernate;
using NHibernate.Dialect;

using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Automapping;
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.Instances;

using FluentNHibernate.Conventions.Helpers;

using TestFluentAutomappingWithRowversion.Model;

namespace TestFluentAutomappingWithRowversion
{
    public static class Mapper
    {
        static ISessionFactory _sf = null;
        public static ISessionFactory GetSessionFactory()
        {
            if (_sf != null) return _sf;

            var fc = Fluently.Configure()
                    .Database(MsSqlConfiguration.MsSql2008.ConnectionString(@"Data Source=localhost; Initial Catalog=TestDb; User Id=sa; Password=P@$$w0rd; MultipleActiveResultSets=True"))
                    .Mappings
                    (m =>
                            m.AutoMappings.Add
                            (
                                AutoMap.AssemblyOf<Program>(new CustomConfiguration())
                                    .Conventions.Add<RowversionConvention>()                                
                            )
                    // .ExportTo(@"C:\_Misc\NH")
                    );


            // Console.WriteLine( "{0}", string.Join( ";\n", fc.BuildConfiguration().GenerateSchemaCreationScript(new MsSql2008Dialect() ) ) );
            // Console.ReadLine();

            _sf = fc.BuildSessionFactory();
            return _sf;
        }


        class CustomConfiguration : DefaultAutomappingConfiguration
        {
            IList<Type> _objectsToMap = new List<Type>()
            {
                typeof(Product)
            };
            public override bool ShouldMap(Type type) { return _objectsToMap.Any(x => x == type); }
            public override bool IsId(FluentNHibernate.Member member) { return member.Name == member.DeclaringType.Name + "Id"; }

            public override bool IsVersion(FluentNHibernate.Member member) { return member.Name == "TheRowversion"; }
        }


        class RowversionConvention : IVersionConvention
        {
            public void Apply(IVersionInstance instance) { instance.Generated.Always(); }
        }

    }
}

Entity Framework's Concurrency Handling using Sql Server's rowversion field. And why modal dialog is bad for editing records

The Model:

public class Product
{
 [Key]
 public int ProductId { get; set; }
 public string ProductName { get; set; }
 public string WarehouseLocation { get; set; }
 public string LastAuditedBy { get; set; }
 public int Quantity { get; set; }

 [ConcurrencyCheck]
 public byte[] TheRowversion { get; set; }
}

The concurrent update scenario:

class Program
{
 static void Main(string[] args)
 {
  var userA = new CatalogContext();
  var userB = new CatalogContext();

  // User A and User B happen to open the same record at the same time
  var a = userA.Products.Find(1);
  var b = userB.Products.Find(1);

  
  
  a.ProductName = "New & Improved" + a.ProductName + "!";
     
  b.WarehouseLocation = "Behind appliances section";
  b.LastAuditedBy = "Linus";
  b.Quantity = 7;

  

  userA.SaveChanges();

  // This will fail. As the rowversion of the same record since it was first loaded, had 
  // already changed (the record was changed by User A first) when it's User B's time to save the same record.
  userB.SaveChanges();

}



Why a modal dialog is bad for editing a record? It's bad when you employ concurrency handling (a must) on records. Imagine your program is in kiosk mode, and let's say due to policy or technology constraints(say IE6), launching multiple instances of your app or using multiple tabs(e.g. IE6) isn't allowed/possible. How can we prevent User B from wasting his edits/time(imagine if there are 20 fields on a given record)? from losing his work? Let him open the latest changes of the record he happened to open at the same time with other users in a new tab(e.g. jQuery tab). With non-modal editing, User B can compare his changes against the latest changes of User A, and then he can copy-paste his changes to the latest changes, not much work will be wasted. You cannot facilitate this sort of thing with modal dialog editor, User B will be compelled to lose all his edits, and will just re-open the latest version from User A and re-input again all his concerning fields.


DDL:

create table Product
(
ProductId int identity(1,1) not null primary key,
ProductName nvarchar(100) not null unique,
WarehouseLocation nvarchar(100) not null,
LastAuditedBy nvarchar(100) not null,
Quantity int not null,
TheRowversion rowversion not null
)