Wednesday, January 26, 2011

Tutorial: Hello ORM with ADO.NET EDM

I hope, you might already know what OOP is. Most of .net developers know what OOP is and what the features of OOP are. They may also learn some OOP tutorials. However, just knowing is not enough and it is the most important to know how to put in place in real world projects.

Before ADO.NET EDM is released, I couldn't find any useful way to use OOP in real world applications. Most of my applications are data centric applications and our lives were so easy with Microsoft Data Binding and ADO.NET DataAdapter. All we need to do is to provide CRUD store procedures to DataAdapter, drag-drop DataGridView to form and bind DataGridView with DataAdapter. That's all!!! It was amazingly easy and really straightforward. All insert/update/delete are handled by the DataGridView and DataAdapter.

If you create your own business entities or business objects, it is all your responsibilities to persist these business objects to data store. It is just a nightmare to handle all these things by hand instead of using frameworks to do our jobs. I don't say that it is impossible to do these things. It just gives us more works. Instead of concentrating on the business logic, we need to share our man-days wasting on the persistence.

Now it is time to say thanks to Microsoft for bringing in Object Relational Mapping feature to the .Net world. Microsoft introduced Entity Data Model (EDM) with Visual Studio 2008 SP1. Entity Data Model and Entity Data Framework will do our jobs for persisting these business objects.

Here I would like to show you the very basic but insight tutorial on EDM. Visual Studio has built-in EDM designer. But it hides all the great details and it isn't good for the loosely coupled mappings. EDM designer only supports Properties and it doesn't support to add behaviors to our business objects. Although you can achieve it by partial class, I don't prefer that way. By hand-writing the whole mapping, you will get whole freedom.

There are three main files to define the mapping between entity objects and the relational database.
1) .csdl file. (CSDL stands for Conceptual Schema Definition Language and it is the description of our entity classes.
2) .ssdl file. (SSDL stands for Storage Shchema Definition Language and it is the description of relational database model.
3). .msl file (MSL stands for Mapping Specification Language and it is the mapping between conceptual model and the storage model.)

I hope you got a small picture of what EDM is. Now it's time to show you the sample application.

First of all I'll create an entity class called User. 
User.cs

/*
MyModels is XML Schema namespace and User is the entity type, both are defined in .csdl file. These attributes map the entity c# class "User" with the entity type "User" defined in .csdl file*/
[EdmEntityTypeAttribute(NamespaceName = "MyModels", Name = "User")]
    [Serializable()]
    [DataContractAttribute(IsReference = true)]
    ///Our class must extend EntityObject
    public class User : EntityObject
    {
       public static User CreateUser(global::System.Int32 userID)
       {
            User user = new User();
            user.UserID = userID;
            return user;
       }

        /*These attributes state that this property needs to be 
        mapped to the database column.*/
        [EdmScalarPropertyAttribute(EntityKeyProperty = true, IsNullable = false)]
        [DataMemberAttribute()]
        public global::System.Int32 UserID
        {
            get
            {
                return _UserID;
            }
            set
            {
                if (_UserID != value)
                {
                    _UserID = StructuralObject.SetValidValue(value);
                }
            }
        }
        private global::System.Int32 _UserID;
        

        [EdmScalarPropertyAttribute(EntityKeyProperty = false, IsNullable = true)]
        [DataMemberAttribute()]
        public global::System.String Username
        {
            get
            {
                return _Username;
            }
            set
            {
                _Username = StructuralObject.SetValidValue(value, true);
                
            }
        }
        private global::System.String _Username;
        

        [EdmScalarPropertyAttribute(EntityKeyProperty = false, IsNullable = true)]
        [DataMemberAttribute()]
        public global::System.String Password
        {
            get
            {
                return _Password;
            }
            set
            {
                _Password = StructuralObject.SetValidValue(value, true);
                
            }
        }
        private global::System.String _Password;        

        //Custom Business logic added for demonstration
        public string SayHello()
        {
            return "Hello, my name is " + _Username;
        }
    }

Next thing is to add the DataAdapter like class. It will handle all CRUD processing based on the provided mapping files and it will keep track of all the entity state changes and will do Insert/Update/Delete accordingly.

BusinessEntities.cs
//this class must inherit ObjectContext class
public class BusinessEntities : ObjectContext
    {
        /*The first parameter is the connection name in App.config file. The second is the container name defined in config files*/
        public BusinessEntities()
            : base("name=BusinessEntitiesConString", "BusinessEntities")
        {
            this.ContextOptions.LazyLoadingEnabled = true;
        }
        
        public ObjectSet<User> User
        {
            get
            {
                if ((_User == null))
                {
                    _User = base.CreateObjectSet<User>("User");
                }
                return _User;
            }
        }
        private ObjectSet<User> _User;
    }

The last thing is to create a Form and see the results. I'll add one DataGridView and two buttons to the form.
Form1.cs
public partial class Form1 : Form
{
   //Create a instance variable of our context class
   BusinessEntities be = new BusinessEntities();

   ///This method will retrieve all user objects from database  
   ///and show in the datagridview
   private void button1_Click(object sender, EventArgs e)
   {
            
       dataGridView1.DataSource = from user in be.User
                                       select user;
   }
   

   /*You can Add/Edit/Delete records in DataGridView and call this method to save all the changes back to DB*/
   private void button2_Click(object sender, EventArgs e)
   {
       be.SaveChanges();
   }   
}

OK, we are done with the coding part. Now let's go to the config part.

First we need to add Database (.mdf) file to the solution root folder. I'll call it mydb.mdf.  Double click the database file to open in database explorer. Then add new table to the database.
UserID int PK not null
Username varchar(50)
Password varchar(50)

Next add connection string to the App.config.
<add name="BusinessEntitiesConString" connectionString="metadata=.\MyModel.csdl|.\MyModel.ssdl|.\MyModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\mydb.mdf;Integrated Security=True;User Instance=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

Please note that the connection string name will be used from our BusinessEntities constructor.

Please note that you need to set "Copy to output directory" properties of below three files to Copy Always or Copy if newer.

Then add MyModel.csdl file. This file describe the conceptual model of our business domain models. This file contains container, entity type and other attributes and those are used to map with our .cs class files.
<?xml version="1.0" encoding="utf-8"?>
<Schema Namespace="MyModels" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
  <EntityContainer Name="BusinessEntities" annotation:LazyLoadingEnabled="true">
    <EntitySet Name="User" EntityType="MyModels.User" />
  </EntityContainer>
  <EntityType Name="User">
    <Key>
      <PropertyRef Name="UserID" />
    </Key>
    <Property Name="UserID" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
    <Property Name="Username" Type="String" MaxLength="50" Unicode="false" FixedLength="false" />
    <Property Name="Password" Type="String" MaxLength="50" Unicode="false" FixedLength="false" />
  </EntityType>
</Schema>

The attribute values such as "MyModels, BusinessEntities, MyModels.User" could be any thing. But please make sure that these names reflect the names used in the attributes in our .cs classes.

Then add MyModel.ssdl file. This file reflect the schema of our database.
<?xml version="1.0" encoding="utf-8"?>
<Schema Namespace="MyModels.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2005" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
  <EntityContainer Name="MyModelsStoreContainer">
    <EntitySet Name="TB_User" EntityType="MyModels.Store.TB_User" store:Type="Tables" Schema="dbo" />
  </EntityContainer>
  <EntityType Name="TB_User">
    <Key>
      <PropertyRef Name="UserID" />
    </Key>
    <Property Name="UserID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
    <Property Name="Username" Type="varchar" MaxLength="50" />
    <Property Name="Password" Type="varchar" MaxLength="50" />
  </EntityType>
</Schema>

The last thing is to add mapping file MyModel.msl. This file provides mapping between above two files, conceptual and storage.

<?xml version="1.0" encoding="utf-8"?>
<Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2008/09/mapping/cs">
  <EntityContainerMapping StorageEntityContainer="MyModelsStoreContainer" CdmEntityContainer="BusinessEntities">
    <EntitySetMapping Name="User">
      <EntityTypeMapping TypeName="MyModels.User">
        <MappingFragment StoreEntitySet="TB_User">
          <ScalarProperty Name="UserID" ColumnName="UserID" />
          <ScalarProperty Name="Username" ColumnName="Username" />
          <ScalarProperty Name="Password" ColumnName="Password" />
        </MappingFragment>
      </EntityTypeMapping>
    </EntitySetMapping>
  </EntityContainerMapping>
</Mapping>

This file map the entities, containers and properties from the above two xml files.

Ok, we are almost there. The very final thing to do is to press F5 and enjoy.

















Thanks for reading and hope worth reading!
:)
















Wednesday, January 12, 2011

KB: How ASPSESSIONID Works

HTTP is stateless. There is no way to track the browser's request by web server. So for every request, web server treats it as a new request and send response back to the browser. This was quite ok long ago because early ages of websites are to give information only.

But when it times for the shopping cart or other e-commence to be emerged, we need something better than the stateless http. Then SESSION cookies come into action. The main purpose of the SESSION cookie is to identify each request from the user to be able to provide user specific information.

The essential part of the session cookie is the Session ID. The name of the Session ID is different for different programming languages. For example, ASPSESSIONID for Asp and JSESSIONID for Java.

Here I'll talk about ASPSESSIONID. Asp Session ID has both key and value just like normal cookie. The key will start with the word "ASPSESSIONID" and it will be appended with randomly generated characters to have total length of 20 characters key. And Session ID values are 32-bit integers and each time web server is restarted, random session id will be generated. For subsequent request, the session id will be increased by 1 number.

You can see the real session id by executing the following scripts:
Session ID = <%= Session.SessionID %>
And the response is similar to this.
Session ID = 845888955 
That's what you will see when you work at the server side. But this plain value will be encrypted as explain above and send it to the browser as a session cookie and it will look something like this:
ASPSESSIONIDASDTTQAS=FKNDLGCDGCBGKEGABELPFEIB
Here "ASPSESSIONID" is fixed all the time and appended with randomly generated "ASDTTQAS". The integer value "845888955" is encrypted as "FKNDLGCDGCBGKEGABELPFEIB".

Important!
 If you don't set the cookie expiration or if you don't clear the browser cache, this session ID and value will be used for all future requests even if you close the browser and open again.

You can execute this script to see the above session cookie.
<%= Request.ServerVariables("HTTP_COOKIE") %>
Or you can use javascript alert.
alert(document.cookie);


For the very first request from the browser, there is no session cookie in the request and the request header will look something like this:

GET /somepage.asp HTTP/1.1
Host: 1.2.3.4
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729; .NET4.0E)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive

And if the web server doesn't detect any session cookie in the header or it detects invalid session cookie, it will generate new session id and sent it back to the browser in response header. Here is the sample response

HTTP/1.1 200 OK
Date: Thu, 13 Jan 2011 02:17:57 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
P3P: CP = “IDC ADM HIS OUR IND”
Content-Length: 410
Content-Type: text/html
Set-Cookie: ASPSESSIONIDASDTTQAS=FNNDLGCDBAPCAHACKCKNLOCA; path=/
Cache-Control: private

In all subsequent request, the browser will include session cookie in all request headers.

GET /anotherpage.asp HTTP/1.1
Host: 1.2.3.4
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729; .NET4.0E)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Cookie: ASPSESSIONIDASDTTQAS=FNNDLGCDBAPCAHACKCKNLOCA
Cache-Control: max-age=0

In this way, web server can identify each request from all over the world and send the respective information back to the user.


There is one interesting thing to note if you need to work with Asp Session ID. You can terminate or abandon the current session by executing this script
<% Session.Abandon() %>
This will only terminate the current session in the web server and the server will clear all values store in session by using Session("somekey") = "Some Value". However, the browser session key and value will not be clear out and will not be changed. If you make a new request to the web server, the same session key and value will be sent from the browser and the web server will create new session with the key and value provided by the browser. After you abandon your session and you want new session key and value, you have to assign invalid value to session id to force the web server to re-generate new session id.


Thanks for reading and hope worth reading!





Tuesday, January 11, 2011

BEST PRACTICE: SQL Composite or Auto-generated Primary Key

There are lots of arguments whether to use Composite Primary Key or Auto-generated/Unique Primary Key.
There are PROs & CONs for both of these techniques.
But if you will have multiple child tables and you will have multiple foreign key relationships, only use auto-generated key approach.

Why? If you use composite key with 3 columns, when you join the two tables, you need to compare all these 3 columns in join. So if you need to join multiple tables using composite key consisting 2 or more columns, can you imaging how your SQL becomes too complex. However, if you use auto-generated key, you only need to compare 1 column.

But do remember to assign Unique Constraints if you use auto-generated key.
Consider this:

PKProductIDColorPrice
11001Red$100
21001Blue$200


Product ID and Color is the row identifier for the table. Later you mistakenly insert ProdcutID:1001 and Color:Red. Then your data integrity is lost.


To avoid, you must add Unique Constraints for combination of ProductID and Color.


Hope worth reading.

HOW TO: Use JSON with Ajax & Classic ASP

JSON stands for JavaScript Object Notation and it is just a standard object description that can be adopted by all programming languages. We can also assume it as a data interchange format between different programming languages. Unlike XML, JSON is lightweight.
You can read more about JSON at http://www.json.org/


I would like to explain simple example that will retrieve person name from server and display the greeting message to the user. I'll use classic asp for server side page, and javascript and ajax to query the server side page.


GetMessage.asp

This is the server side classic asp page and when this page is requested, it will return JSON object.
<%
    'This will return the JSON object as a response
    'Comment below line to see this page result in browser
    Response.AddHeader "Content-Type", "application/json"
%>
<!-- #include file="JSON_2.0.4.asp" -->
<!-- #include file="JSON_UTIL_0.1.1.asp" -->
<%
    Dim Com, SQL
    'This is just a helper function to open database connection
    Call fnOpenDBConnection("dbName",Com)
    'This query simply return first name and last name
    SQL = "Select FirstName,LastName From PersonTable"
    'This to make sure any un-related responses to be clear
    Response.Clear
    'This utility function in JSON_UTIL_0.1.1.asp accept SQL query and connection object and return JSON object. Extra Flush function directly write the response JSON object to response stream
    QueryToJSON(Com, sql).Flush
    'Close database connnection
    Call fnCloseDBConnection(Com)
End Function
%>

You can download ASP to JSON .asp files from

When you access this page in the browser, it will show similar to this:
[{"FirstName":"Kyaw","LastName":"Lwin"}]
But remember to comment Content-Type header to be able to view the page in browser.

Greeting.html
This html page will query the server side page and it will show the result back to the user as a alert.
<html>
<head>
<script src="jquery.js">
<script type="text/javascript" language="javascript">
     'query the server side page with ajax
     'if the result is success, show alert message together with the result
     'dataType:"json" tells that expected response from server is JSON
     $.ajax({url:"GetMessage.asp",type:"POST",  
          success:function(result){
               alert('Hello ' + result[0].FirstName + ' ' + result[0].LastName);
          },dataType:"json"});

</script>
</head>
<body>
This is JSON test page.
</body>
</html>

You can download jquery.js from
http://jquery.org/