Sunday, August 21, 2011

Linq to Dataset in C#

Linq to Dataset

Linq to Dataset is allows us to retrieve data from the Dataset. Since Dataset belongs to ADO.Net so we can query any kind database which is supported by ADO.Net. Linq can query any kind of Data Source which is implements <IEnumerable>, but by default Data Table does not implements the <IEnumerable>, so we should call AsEnumerable() Method, which is an extension method for DataTable, to obtain a wrapper that implements that interface. So that we need to add additional references with System.Linq.dll, System.Data.dll called System.Linq.DatasetExtension.dll.
Once the reference has been added we can query the Data Table using Linq. Let see the first example

//Creating clone to DataTable
dt = ds.Tables[0].Clone();
var dt = (from data in ds.Tables[0].AsEnumerable()
    select data).CopyToDatatable();
dataGridView1.DataSource = dt;

//Lamda Expression
var dt = ds.Tables[0].AsEnumerable().Select(o => o).CopyToDataTable();

In the first line we just copy the Table schema to the new table. Please refer the Clone () Method. In the second line we are making the Table as Enumerable so that we can query the table. Then we are calling CopyToDataTable () method, provided as an extension of the IEnumerable<T> interface, is used to fill a typed DataTable object. Next we are binding the DataTable to DataGridView. In this query we are just pulling the data from one DataTable to another DataTable using Linq.


Where clause

Where clause is used to filter the data by checking the condition of fields or columns. I have used EmployeeID to check the condition.

dt = (from data in ds.Tables[0].AsEnumerable()
                  where data.Field<int>("EmployeeID") == 1
                  select data).AsDataView().ToTable();

//Lamda Expression
var dt = ds.Tables[0].AsEnumerable().Where(o => o.Field<int>("EmployeeID") == 1)
                                                       .Select(o => o).CopyToDataTable();

We should supply the Field type and column name implicity. Here why I am using .AsDataView().ToTable() instead of .CopyToDatatable() because if there no matching records then it will show an exception. I think it’s a bug.

Select Particular Fields

Normally we are fetching all rows from the tables but many times we need to fetch particular column from table .

for example here I have selected LastName,FirstName,Address,City columns only.

var dt = (from data in ds.Tables[0].AsEnumerable()
              where data.Field<int>("EmployeeID") == 1
              select new
              {
               LastName = data.Field<string>("LastName"),
               FirstName = data.Field<string>("FirstName"),
               Address = data.Field<string>("Address"),
               City = data.Field<string>("City")                     
              }).ToList();

//Lamda Expression
var dt = ds.Tables[0].AsEnumerable().
         Where(o => o.Field<int>("EmployeeID") == 1)
         .Select(r => new
         {
          LastName = r.Field<string>("LastName"),
          FirstName = r.Field<string>("FirstName"),
          Address = r.Field<string>("Address"),
          City = r.Field<string>("City"),
         }).ToList();

Here I have used var type datatype because we do not know the schema of Data Table. And also we can iterate the data like this.

foreach (var a in dt)
         {
           string LastName = a.LastName;
           string FirstName = a.FirstName;
           string Address = a.Address;
           string City = a.City;
         }


Order By Clause

Order by used arrange the result set we can both ascending and descending  

var dt = (from data in ds.Tables[0].AsEnumerable()                                        
             orderby data.Field<string>("LastName")
             select new
            {
             LastName = data.Field<string>("LastName"),
             FirstName = data.Field<string>("FirstName"),
             Address = data.Field<string>("Address"),
             City = data.Field<string>("City")                     
            }).ToList();

//Lamda Expression
var dt = ds.Tables[0].AsEnumerable()
                    .Select(r => new
                    {
                        LastName = r.Field<string>("LastName"),
                        FirstName = r.Field<string>("FirstName"),
                        Address = r.Field<string>("Address"),
                        City = r.Field<string>("City"),
                    }).OrderBy(o => o.LastName).ToList();

It will fetch the data with order by LastName.


Skip

var dt = (from data in ds.Tables[0].AsEnumerable()                                        
                      orderby data.Field<string>("LastName")
                      select new
                      {
                        LastName = data.Field<string>("LastName"),
                        FirstName = data.Field<string>("FirstName"),
                        Address = data.Field<string>("Address"),
                        City = data.Field<string>("City")                     
                      }).Skip(3).ToList();



//Lamda Expression
var dt = ds.Tables[0].AsEnumerable()
                    .Select(r => new
                    {
                        LastName = r.Field<string>("LastName"),
                        FirstName = r.Field<string>("FirstName"),
                        Address = r.Field<string>("Address"),
                        City = r.Field<string>("City"),
                    }).OrderBy(o => o.LastName).Skip(3).ToList();

It will skip first three record.


Group By

Group By clause is used to grouping the rows based on cloumns 

var dt = (from data in ds.Tables[0].AsEnumerable()
                      group data by data.Field<string>("City") into Employee
                      select new
                      {
                          City= Employee.Key,
                          Count= Employee.Count()
                      }).ToList();

//Lamda Expression
var dt = ds.Tables[0].AsEnumerable().GroupBy(g => g.Field<string>("City")).
         Select(r => new
         {
          City = r.Key,
          Count = r.Count()
         }).ToList();

It will group the Data by City and output will City and Count of each city.

Output will be
City
Count
Seattle
2
Tacoma
1
KirkLand
1
Redmond
1
London
4


Join Clause

Many times we need to select data from than one table so that we should go the join clause. Join clause is used to join the more than one table using keys like primary,foreign key etc….

var dt = (from product in ds.Tables["Products"].AsEnumerable()
             join order in ds.Tables["OrderDetails"].AsEnumerable()
   on product.Field<int>("ProductID") equals order.Field<int>("ProductID")
             where product.Field<int>("ProductID") == 11
             select new
             {
              ProductName = product.Field<string>("ProductName"),
              SupplierID = product.Field<int>("SupplierID").ToString(),
              UnitPrice = order.Field<decimal>("UnitPrice").ToString(),
              Quantity = order.Field<int>("Quantity").ToString()
             }).ToList();

//Lamda Expression
            var dt = ds.Tables["Products"].AsEnumerable().Join(
                        ds.Tables["OrderDetails"].AsEnumerable(),
                        r => r.Field<int>("ProductID"),
                        o => o.Field<int>("ProductID"),
                   (r, o) => new { Product = r, Order = o }).Where(n => n.Product.Field<int>   ("ProductID") == 11)
                    .Select(p => new
                    {
                        ProductName = p.Product.Field<string>("ProductName"),
                        SupplierID = p.Product.Field<int>("SupplierID").ToString(),
                        UnitPrice = p.Order.Field<decimal>("UnitPrice").ToString(),
                        Quantity = p.Order.Field<int>("Quantity").ToString()
                    }).ToList();

Joining two is like how you joining Sql here I have join Product with OrderDetails on Primary key called ProductID and conditioned with ProductID is 11.It will do inner join from the result I have selected only four columns. Beware while you using datatype inside Field<> because wrong datatype will throw an exception.


 Distinct

The Distinct operator removes duplicate rows from a sequence of objects. It returns an object that, when enumerated, enumerates a source sequence of objects and returns a sequence of objects with the duplicate rows removed. 

var dt = (from data in ds.Tables[0].AsEnumerable()
          select new
          {
           LastName = data.Field<string>("LastName"),
           FirstName = data.Field<string>("FirstName"),
           Address = data.Field<string>("Address"),
           City = data.Field<string>("City")
          }).Distinct().ToList();

//Lamda Expression
var dt = ds.Tables[0].AsEnumerable()
                    .Select(r => new
                    {
                        LastName = r.Field<string>("LastName"),
                        FirstName = r.Field<string>("FirstName"),
                        Address = r.Field<string>("Address"),
                        City = r.Field<string>("City"),
                    }).Distinct().ToList();

Just call Distinct() to get distinct data from table.

Examples in the article is just a sample one. We can write more and more complex queries. So play with Linq queries.

I hope this article will be very helpful to all. Thanks for reading this article.

“Keep reading and share the knowledge”  
“Grow more trees to save the Earth”



Saturday, August 20, 2011

User Defined Functions(UDF) in SqlServer

User Defined Function (UDF) is a single or collection of pre prepared T-SQL statements under a common name. It allows us to create T-SQL statements under common name that can accept zero or more parameter and may return scalar data value or table data value. In simple UDF is code of segment accepting the argument, process the logic and return the value.

There are three types of UDF
  • Scalar
  • Inline Table
  •  Multistatement table 

Let see one by one

Scalar Function
Scalar UDF return a single value consisting of a scalar datatype such as integer, varchar(n), char(n), money, datetime, bit, and so on. UDFs can also return user-defined datatypes (UDDTs) if they are based on a scalar datatype.

Syntax

CREATE FUNCTION owner.function_name
(parameter_name data_type [=default] [, n])
RETURNS scalar_data_type
[WITH function_option]
AS BEGIN
Function body
RETURN scalar expression
END

 Department
ID
Department
Basic
HRA
MA
PF
1
IT
20000
6000
800
2000
2
Sales
10000
3000
400
1000
3
Add
25000
7500
1000
2500
4
IT
30000
9000
1200
3000
5
IT
25000
7500
1000
2500
6
Sales
5000
1500
200
500
7
Add
16533
4960
661
1653
8
Sales
4562
1369
182
456



Take this table as example I created one function to find whether the employee needs to pay tax or not based on the gross salary then we can go for the UDF.

Create Function PayTax(@id int) Returns Varchar(50) As
Begin
          Declare @bool Varchar(10)
          Declare @grosssalary Int
     Select @grosssalary = ((basic + hra +ma)-(pf + loan)) From  department Where employeeid= @id

          If @grosssalary >10000
                   Set @bool ='Yes'
          Else
                   Set @bool ='No'

          Return @bool
End

In this example I have created fucntion with name of PayTax with one argument called @id and inside the function I have declared two varibles @bool and @grosssalary. @bool is used to store whether the employee need to pay tax or not that means ‘Yes’ or ‘No’ and @grosssalary is used to store the gross pay value inside the function finally it return the value of varchar() datatype. This kind of scenarion you can use the UDF.

To call this function you can use

select  dbo.Paytax(1)

To drop the function using this line of code

drop function paytax

Inline Table
This type of function returns a result set, much like a view. However, unlike a view, functions can accept parameters. The inline function’s syntax is quite simple. In the function definition, the return type is set to a table. A RETURN statement is used with a SELECT query in parentheses

Syntax

CREATE FUNCTION owner.function_name
(parameter_name data_type [=default] [, n])
RETURNS Table
[WITH function_option]
AS
RETURN (
Function body statement
)

Employee Table
EmployeeID
EmployeeName
Address
1
A
Arumandhai
2
B
Madurai
3
C
Trichy
4
D
Chennai
5
E
madurai
6
F
Kovai
7
G
Kovai
8
H
Chennai

Department Table 
ID
Department
Basic
HRA
MA
PF
1
IT
20000
6000
800
2000
2
Sales
10000
3000
400
1000
3
Add
25000
7500
1000
2500
4
IT
30000
9000
1200
3000
5
IT
25000
7500
1000
2500
6
Sales
5000
1500
200
500
7
Add
16533
4960
661
1653
8
Sales
4562
1369
182
456


Take the above tables as example. I create a function with Id as parameter and it will return the data row which is matching to that Id.

Create Function GetEmployee( @id int) Returns Table
As
Return
(
 Select E.EmployeeID, E.EmployeeName, E.Address,D.Department, D.Basic
 From Employee as E inner join Department as D on E.EmployeeID=D.EmployeeID
 Where E.EmployeeID= @id
)

To run the function 

Select * from GetEmployee(1)

The Output will be
EmployeeID
EmployeeName
Address
Department
Basic
EmployeeID
1
A
Arumandhai
IT
20000
1