Sunday, October 31, 2010

Configuring Virtual Directory for ASP.NET on Apache

Just add the necessary entry on /etc/apache2/httpd.conf:

Alias /test "/Users/Michael/Projects/TestAspNetMvc/TestAspNetMvc/"
<Directory "/Users/Michael/Projects/TestAspNetMvc/TestAspNetMvc/">
    Options Indexes FollowSymLinks MultiViews
    AllowOverride None

    Order allow,deny
    Allow from all
</Directory>
AddMonoApplications default "/test:/Users/Michael/Projects/TestAspNetMvc/TestAspNetMvc/"
<Location /test>
 SetHandler mono
</Location>

Using that example, you can browse your TestAspNetMvc on http://127.0.0.1/test



The How-To Video:



Saturday, October 30, 2010

Troubleshooting for porting an ASP.NET 4 MVC app from .NET to Mono on Mac OS X

If you received this kind of error while porting a fully functioning existing ASP.NET 4 MVC app to Mono on Mac OS X or other *nix ...

Server Error in '/htmlencoder' Application

Compilation Error
Description: Error compiling a resource required to service this request. Review your source file and modify it to fix this error.
Compiler Error Message: CS0246: The type or namespace name `Dictionary' could not be found. Are you missing a using directive or an assembly reference?
Source Error:
Line 8: 
Line 9:     Input
Line 10:     <p><%: Html.TextArea("Encode","", new Dictionary<string,object> { { "cols", 120 }, { "rows", 12 } }) %></p>
Line 11: 
Line 12:     

Source File: /Library/WebServer/Documents/HtmlEncoder/Views/Encoder/Index.ascx  Lines: 10, 27

Version information: Mono Runtime Version: 2.8 (tarball Thu Oct 7 12:23:27 MDT 2010); ASP.NET Version: 4.0.30319.1


...then add the necessary namespace to root Web.config of your app(On why it works without including the concerned namespace on .NET is beyond me. Might be some namespace in .NET is automatically included on an ASP.NET MVC app, or Mono is more consistent):

<add namespace="System.Collections.Generic" />

Sample Web.config for adding a namespace in it:

<?xml version="1.0"?>

<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=152368
  -->

<configuration>
  <system.web>
    <httpRuntime requestValidationMode="2.0" />
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>
    </compilation>

    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>

    <pages>
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Collections.Generic" /> <!-- add this -->
      </namespaces>
    </pages>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Troubleshooting ASP.NET 4 MVC app in Mono on Mac OS X

If you received this kind of error in your ASP.NET MVC application in Mono...

Server Error in '/portal' Application

Compilation Error
Description: Error compiling a resource required to service this request. Review your source file and modify it to fix this error.
Compiler Error Message: : at (wrapper managed-to-native) System.Reflection.MonoMethodInfo:get_method_info (intptr,System.Reflection.MonoMethodInfo&)
~/Global.asax



...then add this at the end of your httpd.conf:

MonoServerPath /Library/Frameworks/Mono.framework/Commands/mod-mono-server4

...and add this after your AddHandler:

MonoAutoApplication disabled

Complete sample entry in httpd.conf:
Include /etc/apache2/mod_mono.conf


AddHandler mono .aspx .ascx .asax .ashx .config .cs .asmx .axd
MonoAutoApplication disabled


MonoApplications "/:/Library/WebServer/Documents/"


Alias /portal "/Library/WebServer/Documents/HtmlEncoder/"
AddMonoApplications default "/portal:/Library/WebServer/Documents/HtmlEncoder/"
<Location /portal>
  SetHandler mono
</Location>


MonoServerPath /Library/Frameworks/Mono.framework/Commands/mod-mono-server4

Tuesday, October 26, 2010

Bit and boolean fundamentals

Teaching my brother :-)

Decimal to binary

#include <stdio.h>



int main (int argc, char *argv[])
{
 unsigned long number_to_test = 42; 
 unsigned long mask;  
 
 
 printf("\nFirst: ");
 for (mask = 1 << 31; mask != 0; mask >>= 1) 
  printf("%d " , (number_to_test & mask));
  
 printf("\nSecond: ");
 for (mask = 1 << 31; mask != 0; mask >>= 1) 
  printf("%d", !(number_to_test & mask));

 
 printf("\nThird: "); 
 for (mask = 1 << 31; mask != 0; mask >>= 1) 
 {  
  putchar('0' + !!(number_to_test & mask));
  // printf("%d", !!(number_to_test & mask));
 }
 
 printf("\nFourth: ");
 for (mask = 1 << 31; mask != 0; mask >>= 1) 
 {
  if (number_to_test & mask)  
   putchar('1');
  else
   putchar('0');
 }

     
 printf("\nFifth: "); 
 for (mask = 1 << 31; mask != 0; mask >>= 1) 
  putchar( (number_to_test & mask) ? 'Y' : 'N' );
          

    
     
 puts("\n\nTesting boolean logic not");  
 
 printf("\n%d", ! 4);
 
 printf("\n%d", ! 7);
 
 printf("\n%d", ! 0);

 
 puts("\n\nTesting boolean logic not not");  
 
 printf("\n%d", ! ! 4);
 
 printf("\n%d", ! ! 7);
 
 printf("\n%d", ! ! 0);
 
  
 return 0;
}



Output
First: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 0 8 0 2 0 
Second: 11111111111111111111111111010101
Third: 00000000000000000000000000101010
Fourth: 00000000000000000000000000101010
Fifth: NNNNNNNNNNNNNNNNNNNNNNNNNNYNYNYN

Testing boolean logic not

0
0
1

Testing boolean logic not not

1
1
0

Monday, October 25, 2010

ASP.NET on Mac OS X Snow Leopard at one fell swoop using mod_mono

Enable Apache first by ticking the checkbox for Web Sharing(System Preferences > Sharing > Web Sharing)




Type 127.0.0.1 in browser's address bar, then it should show:




Install gettext first: https://gist.github.com/1647940


Install Mono, get it at: http://www.go-mono.com/mono-downloads/download.html

Verify on Terminal if you have installed Mono...

mono -V

...should show this:
Mono JIT compiler version 2.10.9 (tarball Mon May  7 20:25:51 EDT 2012)
Copyright (C) 2002-2011 Novell, Inc, Xamarin, Inc and Contributors. www.mono-project.com
 TLS:           normal
 SIGSEGV:       normal
 Notification:  kqueue
 Architecture:  x86
 Disabled:      none
 Misc:          debugger softdebug 
 LLVM:          yes(2.9svn-mono)
 GC:            Included Boehm (with typed GC)


Paste this in your terminal(the next swoop will still have the effect of sudo(i.e. no need to re-enter password)) :
sudo mv /Library/WebServer/Documents/index.html.en /Library/WebServer/Documents/x_index.html.en

And this(so that makes it two swoop ;-)) :
mkdir ~/swoop
cd ~/swoop
sudo ln -s /Library/Frameworks/Mono.framework/Commands/pkg-config /usr/bin/pkg-config
curl -O http://origin-download.mono-project.com/sources/mono/mono-2.10.9.tar.bz2
tar xzf mono-2.10.9.tar.bz2
cd mono-2.10.9
./configure
make 
sudo make install
sudo sh -c "echo '\n\nInclude /etc/apache2/mod_mono.conf' >> /etc/apache2/httpd.conf"
echo "<center><img src='PoweredByMacOSXLarge.gif'><br><% int a = 7 * 6;%><%=a%> <%=new System.Random().Next()%></center>" > /Library/WebServer/Documents/index.aspx 
sudo /usr/sbin/apachectl restart
echo 'Done'


Then refresh the 127.0.0.1 in your browser, you shall be able to see the the answer to life, the universe and everything




This is the how-to video ...

Saturday, October 23, 2010

NHibernate troubleshooting a proper hbm.xml file

If you received this kind of error even though you are sure all your filenamehere.hbm.xml file has proper values...

Unhandled Exception: NHibernate.MappingException: Could not configure datastore from input stream AwesomeNHibernate.RecordCompanyDatabase.hbm.xml ---> System.Xml.XmlException: XML declaration cannot appear in this state. Line 2, position 40.

..., just remove all the white space before your <?xml version tag

NHibernate hbm.xml file troubleshooting

If you received this kind of error while running your NHibernate program even though you already have the proxyfactory.factory_class in your app.config...


Unhandled Exception: NHibernate.Bytecode.ProxyFactoryFactoryNotConfiguredException: The ProxyFactoryFactory was not configured.
Initialize 'proxyfactory.factory_class' property of the session-factory configuration section with one of the available NHibernate.ByteCode providers.
Example:
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>


..., change your filenameHere.hbm.xml's Build action property from Nothing to Embed as resource

Troubleshooting NHibernate on MonoDevelop

If you received this kind of error when you run your MonoDevelop NHibernate program even though you already add the necessary dialect in your app.config file ...

Unhandled Exception: NHibernate.MappingException: Could not compile the mapping document: AwesomeNHibernate.RecordCompanyDatabase.hbm.xml ---> System.InvalidOperationException: Could not find the dialect in the configuration

..., just change your app.config's Copy to output directory property from Do not copy to Always copy

Friday, October 22, 2010

NHibernate ORM How-To. The Object, the Relational, the Mapping. In 4 Easy to Follow Steps

1. The Object aspect, sans relational. This will run as is(actually you can skip this Step 1, the Step 2 contains both object and its relational query):

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

namespace AwesomeNHibernate
{
 class Program
 {
  static void Main(string[] args)
  {
   IList<Musician> musicians = SampleMusicianList();                            
     
   foreach (Musician musician in musicians)
   {
    Console.WriteLine("*****\n{0}\n\nAge: {1}\n", musician.MusicianInfo, musician.Age);
   }

   Console.ReadLine();
      
  }


  static IList<Musician> SampleMusicianList()
  {
   return new List<Musician>
   {
    new Musician { MusicianId = 1, MusicianName = "Elvis Presley", BirthYear = 1935, FavoriteInstrument = "Guitar" },
    new Musician { MusicianId = 2, MusicianName = "Jimi Hendrix", BirthYear = 1942, FavoriteInstrument = "Electric Guitar" },
   };
  }

 }//Program

 public class Musician
 {
  public int MusicianId { get; set; }
  public string MusicianName { get; set; }
  public int BirthYear { get; set; }
  public string FavoriteInstrument { get; set; }



  public int Age
  {
   get
   {
    return DateTime.Today.Year - BirthYear;
   }
  }
  
  public string MusicianInfo
  {
   get
   {
    return string.Format("Musician ID: {0}\nName: {1}\nFavorite Instrument: {2}", MusicianId, MusicianName, FavoriteInstrument);
   }
  }        
  
 }//Musician
}//Awesome

2. The Relational aspect. This is a complete ORM code but will not run yet. There's already object-relational stuff happening in this code, but it's not mapped to a live database yet, shall run after you're done with steps 3 and 4.

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



namespace AwesomeNHibernate
{
 class Program
 {
     
  static void Main(string[] args)
  {
   IList<Musician> musicians = MusicianList();                            
     
   foreach (Musician musician in musicians)
   {
    Console.WriteLine("*****\n{0}\n\nAge: {1}\n", musician.MusicianInfo, musician.Age);
   }

   Console.ReadLine();
      
  }
 
  
  // Relational...
  static ISession OpenSession()
  {
   var c = new Configuration();
   c.AddAssembly(Assembly.GetCallingAssembly());
   ISessionFactory f = c.BuildSessionFactory();
   return f.OpenSession();
  }


  static IList<Musician> MusicianList()
  {
   using (ISession session = OpenSession())
   {
    IQuery query = session.CreateQuery("from Musician order by BirthYear, MusicianName");

    IList<Musician> musicians = query.List<Musician>();

    return musicians;
   }

  }
  // ...Relational

 }//Program

 public class Musician
 {
  public int MusicianId { get; set; }
  public string MusicianName { get; set; }
  public int BirthYear { get; set; }
  public string FavoriteInstrument { get; set; }



  // The beauty of ORM, it allows you to offload compute-intensive routine from database to front-end(e.g. webserver) or middle-tier        
  public int Age
  {
   get
   {
    return DateTime.Today.Year - BirthYear;
   }
  }

  
  public string MusicianInfo
  {
   get
   {
    return string.Format("Musician ID: {0}\nName: {1}\nFavorite Instrument: {2}", MusicianId, MusicianName, FavoriteInstrument);
   }
  }        
  
 }//Musician
}//Awesome

3. The Mapping aspect

Create RecordCompanyDatabase.hbm.xml file and add it to your project, then put this content...

<?xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" assembly="AwesomeNHibernate" namespace="AwesomeNHibernate" >

  <class name="Musician" lazy="false" table="musician">
    <id name="MusicianId" column="musician_id">
      <generator class="sequence">
        <param name="sequence">musician_id_seq</param>
      </generator>
    </id>

    
    <property name="MusicianName" column="musician_name"/>
    <property name="BirthYear" column="birth_year"/>
    <property name="FavoriteInstrument" column="favorite_instrument"/>
    
    
  </class>

</hibernate-mapping>  


After adding that xml file, change the RecordCompanyDatabase.hbm.xml's Build Action property from Content to Embedded Resource. Keyboard shortcut: Ctrl+W+S, Ctrl+W+P, F4(or Alt+Down)



Alternatively, if your NHibernate objects are organized to different assemblies and/or namespace, you can put the explicit namespace name and assembly name in the class' name itself. i.e. class name="NamespacenameHere.ClassnameHere, AssemblynameHere"


<?xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">

  <class name="AwesomeNHibernate.Musician, AwesomeNHibernate" lazy="false" table="musician">
    <id name="MusicianId" column="musician_id">
      <generator class="sequence">
        <param name="sequence">musician_id_seq</param>
      </generator>
    </id>

    
    <property name="MusicianName" column="musician_name"/>
    <property name="BirthYear" column="birth_year"/>
    <property name="FavoriteInstrument" column="favorite_instrument"/>
    
    
  </class>

</hibernate-mapping>  


4. The database

  • Connection. Put this in your App.config file
  • <?xml version="1.0" encoding="utf-8" ?>
    <configuration>  
      <configSections>
        <section name="hibernate-configuration"   type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
      </configSections>
    
      <hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
        
        <session-factory>
    
          <property name="dialect">NHibernate.Dialect.PostgreSQLDialect</property>      
          <property name="connection.connection_string">Server=localhost;Database=test;User ID=postgres;Password=opensesame;</property>            
          <property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
                   
        </session-factory>
                
      </hibernate-configuration>
      
    </configuration>
    
    Note: In order for this to work in MonoDevelop, change app.config's Copy to output directory property from Do not copy to Always copy If you don't want to clutter your app.config, you can put nhibernate settings on separate file instead, NHibernate look its settings from hibernate.cfg.xml file:
    <?xml version="1.0" encoding="utf-8" ?>
    
    <hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
     
     <session-factory>
     
       <property name="dialect">NHibernate.Dialect.PostgreSQLDialect</property>      
       <property name="connection.connection_string">Server=localhost;Database=test;User ID=postgres;Password=opensesame;</property>            
       <property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
                 
     </session-factory>
             
    </hibernate-configuration>   
    
    Likewise, change hibernate.cfg.xml's Copy to output directory property from Do not copy to Always copy. And change the OpenSession code to:
    static ISession OpenSession()
       {
        var c = new Configuration(); 
        c.Configure(); // add this, this makes NHibernate look for its settings from hibernate.cfg.xml instead of app.config
        c.AddAssembly(Assembly.GetCallingAssembly());
        ISessionFactory f = c.BuildSessionFactory();     
        return f.OpenSession();
       }
    
    Note the c.Configure();, failing to add that code will result to:
    Unhandled Exception: NHibernate.MappingException: Could not compile the mapping document: AwesomeNHibernate.RecordCompanyDatabase.hbm.xml ---> System.InvalidOperationException: Could not find the dialect in the configuration
    
  • Download Postgres as your database
  • Supporting Components(add these 3 files to your Project's Reference)
    • NHibernate-2.1.2.GA-bin\Required_Bins\NHibernate.dll
    • NHibernate-2.1.2.GA-bin\Required_For_LazyLoading\LinFu\NHibernate.ByteCode.LinFu.dll
    • Npgsql2.0.10-bin-ms.net4.0\Npgsql.dll
    • Download:
  • Database content
  • create table musician
    (
    musician_id serial not null primary key,
    musician_name text,
    favorite_instrument text,
    birth_year int
    );
    
    insert into musician(musician_name, favorite_instrument, birth_year) values
    ('John Lennon','Guitar', 1940),
    ('Paul McCartney', 'Bass Guitar', 1942),
    ('George Harrison', 'Sitar', 1943),
    ('Ringo Starr', 'Drums', 1940);
    


You can now run the project. When we add the .NET 4.0 version of Npgsql, we must also change the Target Framework of our project to 4.0. Another note, if you received a compile-time error that type or namespace NHibernate could not be found even you already add the NHibernate.dll reference to your project, change the Target Framework from .NET Framework 4 Client Profile to .NET Framework 4

Note: To facilitate autocomplete for your NHibernate hbm.xml files, put these two files...

  • NHibernate-2.1.2.GA-bin\Required_Bins\nhibernate-configuration.xsd
  • NHibernate-2.1.2.GA-bin\Required_Bins\nhibernate-mapping.xsd

...to:

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Xml\Schemas




To use the above NHibernate code on Sql Server, just change the three session-factory properties of App.config(or in hibernate.cfg.xml)...


<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name="connection.connection_string">Data Source=.\SQLEXPRESS;Initial Catalog=RecordCompany;Trusted_Connection=yes</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>

..., and change RecordCompanyDatabase.hbm.xml's Musician's id generator to:

<id name="MusicianId" column="musician_id">
    <generator class="native"/>
</id>    


...And on musician table, change the serial to its Sql Server equivalent

musician_id int identity(1,1) not null primary key

Another note, Postgresql's TEXT type is essentially the same as VARCHAR(MAX). So you also need to change the TEXT types to VARCHAR(MAX), e.g.

create table musician
(
musician_id int identity(1,1) not null primary key,
musician_name varchar(max),
favorite_instrument varchar(max),
birth_year int
);
 
insert into musician(musician_name, favorite_instrument, birth_year) values
('Kurt Cobain','Guitar', 1967),
('Krist Novoselic', 'Bass Guitar', 1965),
('Dave Grohl', 'Sitar', 1969)


If you will use TEXT type on SQL Server, you will encounter this error on your NHibernate query:


ADOException was unhandled

could not execute query
[ select musician0_.musician_id as musician1_0_, musician0_.musician_name as musician2_0_, musician0_.birth_year as birth3_0_, musician0_.favorite_instrument as favorite4_0_ from musician musician0_ order by musician0_.birth_year, musician0_.musician_name ]
[SQL: select musician0_.musician_id as musician1_0_, musician0_.musician_name as musician2_0_, musician0_.birth_year as birth3_0_, musician0_.favorite_instrument as favorite4_0_ from musician musician0_ order by musician0_.birth_year, musician0_.musician_name]

And it's not NHibernate's query fault. NHibernate just translates the HQL(Hibernate Query Language) to your RDBMS's SQL dialect. Sql Server cannot perform an ORDER BY on TEXT fields. Try to remove the order by BirthYear, MusicianName on your NHibernate's query, the program shall run as normal. NHibernate just reflect the fact Sql Server cannot perform ORDER BY on TEXT fields; one advice, avoid TEXT fields on Sql Server. NHibernate does a poor job on stating that fact ;-)

So if you use text on Sql Server Management Studio, and performed ordering on them,...

select * from musician order by birth_year, musician_name 

...this will be its actual error(programmer-friendly error):
The text, ntext, and image data types cannot be compared or sorted, except when using IS NULL or LIKE operator.



The how-to video:





























EDIT February 12, 2011

New approach, spoiler alert: 1 monolithic step only ;-)

One-stop-shop with Fluent NHibernate

Friday, October 15, 2010

NHibernate could not be found

If you see this kind of compile-time error even when you already add NHibernate to your project reference...

The type or namespace name 'NHibernate' could not be found (are you missing a using directive or an assembly reference?)

...Just change your project target framework. Click Project > YourProjectNameHere Properties > change Target Framework from .NET Framework 4 Client Profile to .NET Framework 4

Thursday, October 14, 2010

Sql Server IS DISTINCT FROM

How to test if two NULLS are equal in SQL Server, ala-C#. Before our dear DBAs waxes philosophical that NULL = NULL is unknown, NULL <> NULL is also unknown, we must note that comparing things that results to knowns has uses, say for example we want to make audit logger in trigger code, that trigger code must be optimized. We will have database performance problem if we don't detect the field when logging changes, as this will do unconditional logging, whether the pertinent field(s) changes or not. We will also have problem in our logging logic if we cannot properly detect if there is a change that have occured in nullable field.

As typified by this:
IF new.sub_account_of <> old.sub_account_of THEN
    // log changes here
ELSE
    // do nothing
END

That will not work, if one of them has null. We must use this(doesn't work on Sql Server, works on Postgres, DB2):

IF new.sub_account_of IS DISTINCT FROM old.sub_account_of THEN
    // log changes here
ELSE
    // do nothing
END


Truth table for C#-like null comparison:
   A ==    B
NULL == NULL : True
NULL ==    1 : False
NULL ==    2 : False
   1 == NULL : False
   1 ==    1 : True
   1 ==    2 : False
   2 == NULL : False
   2 ==    1 : False
   2 ==    2 : True

   A !=    B
NULL != NULL : False
NULL !=    1 : True
NULL !=    2 : True
   1 != NULL : True
   1 !=    1 : False
   1 !=    2 : True
   2 != NULL : True
   2 !=    1 : True
   2 !=    2 : False

For the code above, expand the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NullComparison
{
    class Program
    {
        struct Rec
        {
            public int? a, b;

            public Rec(int? a, int? b)
            {
                this.a = a;
                this.b = b;
            }            
        }


        static void Main(string[] args)
        {
            Console.WriteLine("{0,4} == {1,4}", "A", "B");
            foreach (Rec r in Values())
            {
                Console.WriteLine("{0,4} == {1,4} : {2}", 
                    r.a != null ? r.a.ToString() : "NULL", 
                    r.b != null ? r.b.ToString() : "NULL", 
                    r.a == r.b);                
            }

            Console.WriteLine();
            Console.WriteLine("{0,4} != {1,4}", "A", "B");
            foreach (Rec r in Values())
            {
                Console.WriteLine("{0,4} != {1,4} : {2}", 
                    r.a != null ? r.a.ToString() : "NULL", 
                    r.b != null ? r.b.ToString() : "NULL", r.a != r.b);                
            }

            Console.ReadLine();
            
        }

        static IEnumerable<Rec> Values()
        {
            yield return new Rec(null, null);
            yield return new Rec(null, 1);
            yield return new Rec(null, 2);
            yield return new Rec(1, null);
            yield return new Rec(1, 1);
            yield return new Rec(1, 2);
            yield return new Rec(2, null);
            yield return new Rec(2, 1);
            yield return new Rec(2, 2);
        }

    }//class Program

}//namespace NullComparison

If you want to go directly to Sql Server logic, click this, otherwise continue reading...

Now let's do it first in PostgreSQL to verify the logic of our code, since it has first class support for C#-like nullable values comparison behavior. For equality, it uses IS NOT DISTINCT FROM, for inequality it uses IS DISTINCT FROM, pretty intuitive isn't it? If I remember correctly, MySQL uses <=> for its IS DISTINCT FROM, I don't recall if there's an IS NOT DISTINCT FROM operator in MySQL.

To create the table(also works in SQL Server 2008):
select a,b into x_m
from 
(
 values
 (null,null),
 (null,1),
 (null,2),
 (1,null),
 (1,1),
 (1,2),
 (2,null),
 (2,1),
 (2,2)
)as x(a,b)

Without further ado, this is the logic of equality: coalesce(a = b or (a is null and b is null), false) as manual_comp

Why coalesce is needed there? It's when either of a or b is null, the equality comparison will result to null. So we need to translate null to false, for that we will use coalesce.

To test:
select a,b
,coalesce(a = b or (a is null and b is null), false) as manual_comp
,a is not distinct from b as built_in_comp
from x_m

Outputs:
 a | b | manual_comp | built_in_comp
---+---+-------------+---------------
   |   | t           | t
   | 1 | f           | f
   | 2 | f           | f
 1 |   | f           | f
 1 | 1 | t           | t
 1 | 2 | f           | f
 2 |   | f           | f
 2 | 1 | f           | f
 2 | 2 | t           | t
(9 rows)

Now how to check if b is different from a? use IS DISTINCT FROM, now how do we do it in manual SQL? One approach is we just put NOT on the whole expression, another one is we rewrite the query:

select a,b
,coalesce(a <> b and (a is not null or b is not null), true) as manual_comp
,a is distinct from b as built_in_comp
from x_m

Outputs:
 a | b | manual_comp | built_in_comp
---+---+-------------+---------------
   |   | f           | f
   | 1 | t           | t
   | 2 | t           | t
 1 |   | t           | t
 1 | 1 | f           | f
 1 | 2 | t           | t
 2 |   | t           | t
 2 | 1 | t           | t
 2 | 2 | f           | f
(9 rows)


As we can see, re-wiring rewriting the query seems a bit tedious to read:

coalesce(a <> b and (a is not null or b is not null), true) as manual_comp

Programmers also tend to re-read their logic if it involves multiple NOT EQUAL comparison. I cannot just help myself to skim-read that query. Maybe one of those NOT EQUAL comparisons could launch a missile!

Let's find one example how using only one NOT happens in real life. If an interviewer asked the interviewee about her favorite singer, and the answer is neither John, Paul, George nor Ringo, then the interviewer should go find another interviewee.

Now how most programmers(not all programmers) translate that to program?

IF ans != 'John' AND ans != 'Paul' AND ans != 'George' AND ans != 'Ringo' THEN 
    FindAnotherInterviewee
END

See the pattern there? You never read written instructions like this in real life "Please interview another person if the interviewee's answer is not john and not paul and not george and not ringo." In real life, you just use one NOT. The code above doesn't mimic the original English sentence anymore, it's hard to read that logic, it compels the programmer to re-read the logic, multiple NOT EQUALs promotes doubtful assertion, perhaps you've seen others prefer this (translation of if answer is neither Y, N nor C):

IF ans != 'Y' AND ans != 'N' AND ans != 'C' THEN ask again END

Over this readable one:
IF NOT(ans = 'Y' OR ans = 'N' or ans = 'C') THEN ask again END


So I shun multiple NOT EQUALs in logic, they make the program harder to read. So the English sentence of neither John,Paul,George nor Ringo, should be written like this:

IF NOT(ans = 'John' OR ans = 'Paul' OR ans = 'George' OR ans = 'Ringo') THEN     
    FindAnotherInterviewee
END

That directly mimics the english sentence with only one NOT. Actually the word nor from actual English sentence is a signal in itself that one should not use AND, should use OR instead when translating the English sentence to code.

So let's stick with readable programs.

To continue, for inequality comparisons, we just stick NOT in front of the equality expression.

select a,b
,not coalesce(a = b or (a is null and b is null), false) as manual_comp
,a is distinct from b as built_in_comp
from x_m

Here's the output:
 a | b | manual_comp | built_in_comp
---+---+-------------+---------------
   |   | f           | f
   | 1 | t           | t
   | 2 | t           | t
 1 |   | t           | t
 1 | 1 | f           | f
 1 | 2 | t           | t
 2 |   | t           | t
 2 | 1 | t           | t
 2 | 2 | f           | f
(9 rows)



Now let's go back to the main gist of this article, since up to this time of writing, Microsoft SQL Server 2008 still doesn't support IS DISTINCT FROM and IS NOT DISTINCT FROM operators. We must find our way to support those conditions.


So how to translate those IS DISTINCT FROM and IS NOT DISTINCT FROM to Sql Server?

Postgresql version:

select a,b
,coalesce(a = b or (a is null and b is null), false) as manual_comp
,a is not distinct from b as built_in_comp
from x_m

To translate to Sql Server-consumable one, use CASE WHEN:

select a,b,
    case 
    when a = b then 1
    when a is null and b is null then 1 
    else 0
    end as mssql_manual_comp
from x_m

Outputs:
a           b           mssql_manual_comp
----------- ----------- -----------------
NULL        NULL        1
NULL        1           0
NULL        2           0
1           NULL        0
1           1           1
1           2           0
2           NULL        0
2           1           0
2           2           1

(9 row(s) affected)

Working properly, now how to check if a IS DISTINCT FROM b? Since Sql Server don't have first-class support for booleans, we cannot just put NOT on front of CASE statement. This will result to incorrect syntax:
select a,b,
      NOT
      case 
      when a = b then 1
      when a is null and b is null then 1 
      else 0
      end as mssql_manual_comp
from x_m


So let's get some help from XOR operator to toggle the logic:
select a,b,
    case 
    when a = b then 1
    when a is null and b is null then 1 
    else 0
    end ^ 1 as mssql_manual_comp
from x_m

So what's the output for our inequality comparison?
a           b           mssql_manual_comp
----------- ----------- -----------------
NULL        NULL        0
NULL        1           1
NULL        2           1
1           NULL        1
1           1           0
1           2           1
2           NULL        1
2           1           1
2           2           0

(9 row(s) affected)

So our logic is correct, so now let's give some IS DISTINCT FROM love to Sql Server, which if I may add can already be done on other major RDBMS

To recap, how to do IS NOT DISTINCT FROM in Sql Server?
select a,b
from x_m
where a IS NOT DISTINCT FROM b

Here's the equivalent in Sql Server:
select a,b
from x_m
where  
    (case 
    when a = b then 1
    when a is null and b is null then 1 
    else 0
    end) = 1

Outputs:
a           b
----------- -----------
NULL        NULL
1           1
2           2

(3 row(s) affected)


And how to do IS DISTINCT FROM in Sql Server?
select a,b
from x_m
where a IS DISTINCT FROM b


Here's the equivalent in Sql Server:
select a,b
from x_m
where  
    (case 
    when a = b then 1
    when a is null and b is null then 1 
    else 0
    end) = 0

Outputs:
a           b
----------- -----------
NULL        1
NULL        2
1           NULL
1           2
2           NULL
2           1

(6 row(s) affected)


Please do note that we don't need to use XOR in our CASE expression in WHERE clause, we can just directly compare the CASE expression to 1 or 0. 1 denotes equality, 0 denotes inequality.


Regarding DeMorgan logic simplifier and why multiple != (aka <>) should be suspected of code smell http://stackoverflow.com/questions/4615113/how-can-the-and-and-or-key-word-used-together-in-a-select-query/4615182#4615182


UPDATE 2011-08-08

Here's another approach for IS NOT DISTINCT FROM:
select a,b
from x_m
where 
    (
        a = b
        or
        (a is null and b is null)
    )

For IS DISTINCT FROM:
select a,b
from x_m
where 
    a <> b
    or 
    ( 
        not (a is null and b is null )
        and ( a is null or b is null )
    )   


UPDATE 2014-04-08

Here's another approach for IS DISTINCT FROM: http://sqlfiddle.com/#!15/d41d8/1731
with x as
(
    select a, b
    from
    (
        values
        (null,null),
        (null,1),
        (null,2),
        (1,null),
        (1,1),
        (1,2),
        (2,null),
        (2,1),
        (2,2)
    )as x(a,b)
)
select *,
 
 
    x.a IS DISTINCT FROM x.b as perfect,
 
 
    x.a <> x.b as flawed,
 
 
    a <> b
    or
    (
        not (a is null and b is null )
        and ( a is null or b is null )
    )  
        as good_workaround,
 
 
 
    (x.a <> x.b or x.a is null or x.b is null)
    and not (x.a is null and x.b is null)
 
        as perfect_workaround
 
 
 
from x;

Output:
|      A |      B | PERFECT | FLAWED | GOOD_WORKAROUND | PERFECT_WORKAROUND |
|--------|--------|---------|--------|-----------------|--------------------|
| (null) | (null) |       0 | (null) |          (null) |                  0 |
| (null) |      1 |       1 | (null) |               1 |                  1 |
| (null) |      2 |       1 | (null) |               1 |                  1 |
|      1 | (null) |       1 | (null) |               1 |                  1 |
|      1 |      1 |       0 |      0 |               0 |                  0 |
|      1 |      2 |       1 |      1 |               1 |                  1 |
|      2 | (null) |       1 | (null) |               1 |                  1 |
|      2 |      1 |       1 |      1 |               1 |                  1 |
|      2 |      2 |       0 |      0 |               0 |                  0 |  

Wednesday, October 13, 2010

You can perform data manipulation on views

use master;
go

create database y_test;
go

use y_test;
go


create table employee
(
id int not null,
name varchar(100) not null,
gross_salary numeric(18,4) not null default '',
password varchar(100) not null default ''
);
go

insert into employee(id, name, gross_salary, password) 
select id, name, gross_salary, password 
from (values
(1, 'Jobs', 75000, 'dashing'),
(2, 'Ballmer', 30000, 'through'),
(3, 'Gatez', 90000, 'the snow')
) as x(id, name, gross_salary, password);
go

select * from employee;
go

create view hr_facing_employee_record as
select id+0 as id, name, gross_salary * (1 - .32 /* Darn Philippines Withholding Tax! */ ) as net_salary from employee;
go

select * from hr_facing_employee_record;
go

delete from hr_facing_employee_record where id = 2;
go

select * from hr_facing_employee_record;
go

-- won't be allowed, inserting records to database must be done in a controlled manner, i.e. must insert directly to table, for example, there might other mechanism how ID is generated/assigned, so must directly insert to table
insert into hr_facing_employee_record(id,name) values(9,'Torvalds');
go

select * from hr_facing_employee_record;
go


update hr_facing_employee_record set name = 'Gates' where id = 3;
go

select * from hr_facing_employee_record;
go


/* 

-- won't be allowed, password is not exposed in hr_facing_employee_record

update hr_facing_employee_record set name = 'Backdoor', password = 'open sesame' where id = 3;
go

select * from hr_facing_employee_record;
go
*/


-- won't be allowed, a view can protect the record integerity
update hr_facing_employee_record set id = 8 where id = 3;
go

select * from hr_facing_employee_record;
go

use master;
go

drop database y_test;
go


Somehow, updateable views is justified (Hello Postgresql! requesting ^_^ ), you can hide the actual table from the user and you can protect what needs to be protected and at the same time abstract some information. However, this problem could also be tackled by using column-level permissions feature of your favorite RDBMS. Each approach has their own appeal.


Sometimes programming into the language has some drawbacks. You won't know what features the alternative products can bring to the table, you sort of missing the proper way of expressing your idea/solution to a given problem domain.

Sql Server Views has updateable views, will keep that in mind, will keep that in mind, or rather in blog ;-)

Tuesday, October 12, 2010

Run multiple instances of an app on Mac OS X

Click Applications on Dock, select Automator. Choose Application. On searchbox, type: shell. Choose Run Shell Script, double click it. Then on text area, replace it with this text:

if [ -n "$*" ]; then
    open -n "$*"
else
    osascript -e 'tell app "Finder" to display dialog "PLZ DRAG AN APP 2 MULTIPLE INSTANCE" with title "MULTIPLE INSTANCE LAUNCHER" buttons { "OH HAI" } '
fi

On Pass input, change it to as arguments. Press command+S, on Save as type: Multiple Instance, on Where, choose Applications, click Save. Quit Automator.

Click Applications, drag Multiple Instance to Dock, preferably near Applications folder.

Click Applications, drag an app(example: Calculator) to Multiple Instance, repeat to launch multiple instance of that app.

Watch it on YouTube

Tuesday, October 5, 2010

Linq to SQL is not a perfect match for reporting needs

Is clean (or performant) SQL achievable in Linq to Sql?

I wanted Linq to Sql produce this code:

SELECT C.CustomerID, COUNT(O.CustomerID) AS N
FROM Customers C
LEFT JOIN Orders O ON O.CustomerID = C.CustomerID
GROUP BY C.CustomerID

Here's my first attempt:

var q = 
from c in db.Customers
join o in db.Orders on c.CustomerID equals o.CustomerID into sr
from x in sr.DefaultIfEmpty()
group x by c.CustomerID into y
select new { y.Key, N = y.Count(t => t.CustomerID != null) };


First, my beef with Linq is it cannot allow the natural way to write a query. For comparison expressions, it is best to put on the left side the value/expression that is varying much, the less varying ones(e.g. constants) should be on the right side. To convey the point:

int customerId = 7;
bool found = false;
for(int i = 0; i < orders.Length; ++i)
{
    if(orders[i].CustomerId == customerId)
    {
        found = true;
        break;
    }
}

Linq doesn't allow this kind of statement:
var q = from c in db.Customers
        join o in db.Orders on o.CustomerID equals c.CustomerID into sr


Writing query on this form: from c in db.Customers join o in db.Orders on c.CustomerID equals o.CustomerID into sr is akin to doing this code:

int customerId = 7;
bool found = false;
for(int i = 0; i < orders.Length; ++i)
{
    if(customerId == orders[i].CustomerId)
    {
        found = true;
        break;
    }
}

Well that code just doesn't feel natural, isn't it?


Back to the gist of this topic, is performant code achievable in Linq to SQL?

The Linq to SQL code above produces:

SELECT [t2].[CustomerID] AS [Key], (
    SELECT COUNT(*)
    FROM [Customers] AS [t3]
    LEFT OUTER JOIN [Orders] AS [t4] ON [t3].[CustomerID] = [t4].[CustomerID]
    WHERE ([t4].[CustomerID] IS NOT NULL) AND ((([t2].[CustomerID] IS NULL) AND ([t3].[CustomerID] IS NULL)) OR (([t2].[CustomerID] IS NOT NULL) AND ([t3].[CustomerID] IS NOT NULL) AND ([t2].[CustomerID] = [t3].[CustomerID])))
    ) AS [N]
FROM (
    SELECT [t0].[CustomerID]
    FROM [Customers] AS [t0]
    LEFT OUTER JOIN [Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID]
    GROUP BY [t0].[CustomerID]
    ) AS [t2]

Well, that is far cry from the simple thing we want to achieve; that is, Linq's Count(expression here) should not produce COUNT(*), it should produce COUNT(O.CustomerId), but since we cannot feed non-lambda operation on Linq's Count's parameter, we must do: select new { y.Key, N = y.Count(t => t.CustomerID != null) };. And that code produces inefficient query, look at the Sql output above.

Here's my second attempt...

var q = 
from c in db.Customers
join o in db.Orders on c.CustomerID equals o.CustomerID into sr
from x in sr.DefaultIfEmpty()
group x by c.CustomerID into y                                        
select new { y.Key, N = y.Sum(t => t.CustomerID != null ? 1 : 0 )};

...that code produces:

SELECT SUM(
    (CASE
        WHEN [t1].[CustomerID] IS NOT NULL THEN @p0
        ELSE @p1
     END)) AS [N], [t0].[CustomerID] AS [Key]
FROM [Customers] AS [t0]
LEFT OUTER JOIN [Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID]
GROUP BY [t0].[CustomerID]

Though cleaner and performance-wise is passable, it still leave much to be desired, it doesn't inline constants; parameters might be the way of Linq to Sql for passing values or expressions to query(be it a variable or constant), however it still doesn't have a natural feel into it. As far as I know, there's no way to make Linq-to-Sql produce this SQL code: COUNT(O.CustomerId)


Linq to Sql is good as an ORM, storage persistence, fetching data, CRUD operations; but for reporting needs, I wouldn't bet my farm on it though. I would continue using plain old combo of SP,functions,views and ADO.NET for reporting needs.

Saturday, October 2, 2010

NullReferenceException on GetEntryAssembly

I'm following an MVC lesson from Steven Sanderson book. There's an error which eludes me, but solved by just changing the erring function to other equivalent function.


Server Error in '/SportsStore' Application.


Object reference not set to an instance of an object.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error:

Line 39:             
Line 40: 
Line 41:             var controllerTypes = from t in Assembly.GetEntryAssembly().GetTypes()
Line 42:                                   where typeof(IController).IsAssignableFrom(t)
Line 43:                                   select t;






That problem can be solved by changing GetEntryAssembly to GetExecutingAssembly

Castle Windsor warning on AddComponentLifeStyle is obsolete

Wrong warning...


Warning 1 'Castle.Windsor.WindsorContainer.AddComponentLifeStyle(string, System.Type, Castle.Core.LifestyleType)' is obsolete: 'Use Register(Component.For(classType).Named(key)).Lifestyle.Is(lifestyle)) instead.' C:\_CODE\SportsStore\SportsStore\Controllers\WindsorControllerFactory.cs 37 17 SportsStore


...for this kind of code:


container.AddComponentLifeStyle(t.FullName, t, LifestyleType.Transient);

If you try to type LifeStyle after of Named(t.FullName)) ...

container.Register(Component.For(t).Named(t.FullName)).LifeStyle.Is(LifestyleType.Transient));

...the VS Intellisense will not kick in. 

Lifestyle doesn't belong to container.Register, Lifestyle belongs to  Component.For.Named.  This is the correct code, just remove the extra close parenthesis on Named:

container.Register(Component.For(t).Named(t.FullName).LifeStyle.Is(LifestyleType.Transient));

Login failed for user IIS APPPOOL\DefaultAppPool troubleshooting

This error...


Cannot open database "SportsStore" requested by the login. The login failed.
Login failed for user 'IIS APPPOOL\DefaultAppPool'.
A severe error occurred on the current command.  The results, if any, should be discarded.



...has this solution:


Open Microsoft SQL Server Management Studio

Go to Logins node under Security.

Add a new Login, name it: IIS APPPOOL\DefaultAppPool



Then select the User Mapping on left pane, then check the Map column of your database (e.g. SportsStore).  Then check the db_owner on Database role membership of your user IIS APPPOOL\DefaultAppPool on your database SportsStore