Monday, April 30, 2012

Working with a Local Database in Windows Phone 7

Introduction

In this article we are going to see the usage of Isolated Storage by creating a local relational database and save the data locally that are accessible to the specific Windows Phone 7 application. The local relational database will be created on to the Isolated Storage Container where in Windows Phone 7 we need to make use of the LINQ to SQL for all the database operations. LINQ to SQL plays a major role in creating the data schema, selecting the data and making operation to the data as and when required. LINQ to SQL object model uses the System.Data.Linq.DataContext namespace to basically make a proxy call to the local database in the Isolated Storage container. LINQ to SQL Runtime plays as a bridge between the data context object and the real data to do the manipulations based on the user selection.

When considering making use of a local database for Windows Phone 7 Application development we need to consider some of the points mentioned below to get a much more performance and usage over the application.
  • Database file will be stored in the Isolated Storage Container.
  • Database is available specific to the application targeted as it is Isolated from other application.
  • LINQ is used to query the data from the database since TSQL Querying is not supported.
  • Local database feature can be accessed directly by adding System.Data.Linq assembly only since primary support is available with the framework.
  • Connection string much be use in the format of "Data Source ='isostore:/DirectoryName/Databasename.sdf";
We are going to see how to perform the CRUD operation for the Windows Phone 7 Application Isolated Storage Local database using the Data Context class with a sample application. We will get clear idea on the below tasks on how to perform with the Windows Phone 7, which will be covered in details in this article
  • Creating a local database
  • Adding data to the local database
  • Fetching data from local database
  • Deleting data from the local database
  • Deleting a local database
Let us jump start to see the step by step process on how to achieve the above tasks with the Isolated Storage Local Database in Windows Phone 7 Application development by creating a sample application.

Steps:


Open Visual Studio 2010 IDE in administrator mode and create a new Silverlight for Windows Phone 7 Application project with a valid project name as shown in the screen below.

Clipboard01.jpg


Now let us design the User Interface to achieve the tasks listed above, Copy the below XAML code to get the unique user interface with the controls provided to achieve each and every task as shown in the screen below.

Clipboard02.jpg

XAML Code

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <!-TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="F5DEBUG WP7 TUTORIALS" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="Employee DB" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>
  <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <TextBox Height="72" HorizontalAlignment="Left" Margin="113,28,0,0" Name="txtName" Text="" VerticalAlignment="Top" Width="324" />
        <TextBlock Height="30" HorizontalAlignment="Left" Margin="33,57,0,0" Name="textBlock1" Text="Name" VerticalAlignment="Top" />
        <TextBox Height="72" HorizontalAlignment="Left" Margin="113,93,0,0" Name="txtAge" Text="" VerticalAlignment="Top" Width="324" />
        <TextBlock Height="30" HorizontalAlignment="Left" Margin="33,122,0,0" Name="textBlock2" Text="Age" VerticalAlignment="Top" />
        <TextBox Height="72" HorizontalAlignment="Left" Margin="113,159,0,0" Name="txtEmpid" Text="" VerticalAlignment="Top" Width="324" />
        <TextBlock Height="30" HorizontalAlignment="Left" Margin="33,188,0,0" Name="textBlock3" Text="Emp ID" VerticalAlignment="Top" />
        <Button Content="Create Database" Height="72" HorizontalAlignment="Left" Margin="33,255,0,0" Name="button1" VerticalAlignment="Top" Width="404" Click="button1_Click" />
        <Button Content="Add an Employee" Height="72" HorizontalAlignment="Left" Margin="33,319,0,0" Name="button2" VerticalAlignment="Top" Width="404" Click="button2_Click" />
        <Button Content="Delete an Employee" Height="72" HorizontalAlignment="Left" Margin="33,384,0,0" Name="button3" VerticalAlignment="Top" Width="404" Click="button3_Click" />
        <Button Content="Fetch all Employees" Height="72" HorizontalAlignment="Left" Margin="33,449,0,0" Name="button4" VerticalAlignment="Top" Width="404" Click="button4_Click" />
        <Button Content="Delete Database" Height="72" HorizontalAlignment="Left" Margin="33,514,0,0" Name="button5" VerticalAlignment="Top" Width="404" Click="button5_Click" />
    </Grid>
</
Grid>

Now we are done with the User interface design, now we need to create a data context and start using the data object model and start using the data schema to perform the operations. Let us start with adding the LINQ to SQL data context reference by right clicking the project from the solution explorer and adding the reference from the Add Reference menu as shown in the screen below.

Clipboard03.jpg

Once we added the reference for the System.Data.Linq to the application, we need to add the below namespaces to the code behind page of the MainPage.Xaml as shown in the screen below.

Clipboard04.jpg

Code Behind

using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.ComponentModel;
using System.Collections.ObjectModel;

Now our first task is to create a database which is used locally isolated to the application. Since we are going to use the LINQ to SQL data context as a bridge between the local database and the data context we need to create 2 classes as shown below.

The first class is the Employee class which holds the properties for the fields that are tables and columns which are used to build the database, copy the below code to a new class Employee as shown in the screen below. The class has 3 properties that are going to be the data columns which we are going to get as inputs from the end users. If we notice in the below code we are providing the properties for each of the column with one being a primary key, and other are not null etc which we need to specify based on the database design that is normally changes based on the requirement.


Clipboard05.jpg

Code Behind

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Data.Linq.Mapping;
using System.Data.Linq;

namespace F5debugWp7LocalDatabase
{
    [Table]
    public class
Employee
    {
        public int EmployeeID
        {
            get;
            set;
        }
        [Column(CanBeNull = false)]
        public string EmployeeName
        {
            get;
            set;
        }
        [Column(CanBeNull = false)]
        public string EmployeeAge
        {
            get;
            set;
        }
    }
}

Now we need to add another class as EmployeeDataContext which is basically used as the database schema to create an instance, copy the code from the below code block as shown in the screen below.

Clipboard05.jpg

Code Behind

using System;
 using System.Net;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Documents;
 using System.Windows.Ink;
 using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Media.Animation;
 using System.Windows.Shapes;
 using System.Data.Linq;
namespace F5debugWp7LocalDatabase
 {
 public class EmployeeDataContext:DataContext
 {
 public EmployeeDataContext(string connectionString)
 : base(connectionString)
 {
 }
public Table<Employee> Employees
 {
 
get
 {
 return this.GetTable<Employee>();
 }
 }
 }
 }


Now let us start with our code on the MainPage.Xaml.cs to perform each of the tasks that are mentioned above.

Task 1 - Creating a local database

First let us start with creating a database which is the very first step we need to perform when we are going to use the local database storage to store the data with in the application Isolated Storage Container. We need to have a connection string which is pointing to the local database storage, let us create the connection string as a private constant as shown in the code below.

Code Behind

private const string strConnectionString = @"isostore:/EmployeeDB.sdf";

Now we need to add the below code to create a database instance, here we are going to create an instance of the Data context by passing the connection string which is pointing to the local database storage as shown in the screen below.

Clipboard07.jpg-

Code Behind


private void button1_Click(object sender, RoutedEventArgs e)
{
using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString))
{

if (Empdb.DatabaseExists() == false)

{

Empdb.CreateDatabase();

MessageBox.Show("Employee Database Created Successfully!!!");

}

else

{

MessageBox.Show("Employee Database already exists!!!");

}

}
 }
Task 2 - Adding data to the local database

Our second task is to add some records to the database which we have created, so to add the employee we need to create an instance of the data context and pass the properties that are matching the column properties which we are created in our data context initially. Here we are going to add an employee which has the Employee ID, Employee Name and Employee Age, we have created the instance and passed the values appropriately. Once we fetched the user inputs we need to insert the details on the submit so we use the
 InsertonSubmit method to add the employees as shown in the screen below.
Clipboard08.jpg

Code Behind

private void button2_Click(object sender, RoutedEventArgs e)
{
using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString))
{
Employee newEmployee = new Employee {

EmployeeID = Convert.ToInt32(txtEmpid.Text.ToString()),

EmployeeAge= txtAge.Text.ToString(),

EmployeeName=txtName.Text.ToString()

};

Empdb.Employees.InsertOnSubmit(newEmployee);

Empdb.SubmitChanges();

MessageBox.Show("Employee Added Successfully!!!");

}

}


Task 3 - Fetching data from local database
Our next task is to fetch the consolidated list of data from the local database which normally as an end user we require to report the data in some particular format. So in order to fetch the data we use the LINQ query format to query the data based on the data table and the data context. We have used the simple List to consolidate the data using the LINQ query and we are using the string builder to consolidate the data as user readable as shown in the screen below.

Clipboard09.jpg

Code Behind

public IList<Employee> GetEmployeeList()
{

IList
<Employee> EmployeeList = null;
using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString)
{
IQueryable
<Employee> EmpQuery = from Emp in Empdb.Employees select Emp;
EmployeeList = EmpQuery.ToList();
}
return EmployeeList;
}
private void button4_Click(object sender, RoutedEventArgs e)
{

IList<Employee> EmployeesList = this.GetEmployeeList();

StringBuilder strBuilder = new StringBuilder();

strBuilder.AppendLine("Employee Details");

foreach (Employee emp in EmployeesList)

{

strBuilder.AppendLine("Name - " + emp.EmployeeName + " Age - " + emp.EmployeeAge);

}

MessageBox.Show(strBuilder.ToString());

}

Task 4 - Deleting data from the local database
Our next task is to delete the user specific data from the local isolated storage database, this is straight forward as we query the data from the data context and delete it as shown in the screen below.

Clipboard10.jpg

Code Behind

private void button3_Click(object sender, RoutedEventArgs e)
{
using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString))
{
IQueryable<Employee> EmpQuery = from Emp in Empdb.Employees where Emp.EmployeeName == txtName.Text select Emp;
Employee EmpRemove = EmpQuery.FirstOrDefault();
Empdb.Employees.DeleteOnSubmit(EmpRemove);
Empdb.SubmitChanges();
MessageBox.Show("Employee Deleted Successfully!!!");
}
}

Task 5 - Deleting a local database


Our final task is to delete the database completely once the user removes the application from the device. So to delete the data we can use the below code as shown in the screen below.

Clipboard11.jpg

Code Behind
private void button5_Click(object sender, RoutedEventArgs e)
{
using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString))
{
if (Empdb.DatabaseExists())
{
Empdb.DeleteDatabase();
MessageBox.Show("Employee Database Deleted Successfully!!!");
}
}
}
Once we are done with the above code, our consolidated code will be like below. Just copy and paste it directly on to the cs page for easy access to the code which we have in the above 5 tasks

Consolidated Code Behind

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Text;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.ComponentModel;
using System.Collections.ObjectModel;
 
namespace F5debugWp7LocalDatabase
{
    public partial class MainPage : PhoneApplicationPage
    {
        private const string strConnectionString = @"isostore:/EmployeeDB.sdf";
        // Constructor
        public MainPage()
        {
            InitializeComponent();
        }
       
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString))
            {
                if (Empdb.DatabaseExists() == false)
                {
                    Empdb.CreateDatabase();
                    MessageBox.Show("Employee Database Created Successfully!!!");
                }
                else
                {
                    MessageBox.Show("Employee Database already exists!!!");
                }
            }
        }
 
        private void button2_Click(object sender, RoutedEventArgs e)
        {
            using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString))
            {
                Employee newEmployee = new Employee
                {
                    EmployeeID = Convert.ToInt32(txtEmpid.Text.ToString()),
                    EmployeeAge = txtAge.Text.ToString(),
                    EmployeeName = txtName.Text.ToString()
                };
 
                Empdb.Employees.InsertOnSubmit(newEmployee);
                Empdb.SubmitChanges();
                MessageBox.Show("Employee Added Successfully!!!");
            }
        }
 
        public IList<Employee> GetEmployeeList()
        {
            IList<Employee> EmployeeList = null;
            using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString))
            {
                IQueryable<Employee> EmpQuery = from Emp in Empdb.Employees select Emp;
                EmployeeList = EmpQuery.ToList();
            }
            return EmployeeList;
        }
 
        private void button4_Click(object sender, RoutedEventArgs e)
        {
            IList<Employee> EmployeesList = this.GetEmployeeList();
 
            StringBuilder strBuilder = new StringBuilder();
            strBuilder.AppendLine("Employee Details");
            foreach (Employee emp in EmployeesList)
            {
                strBuilder.AppendLine("Name - " + emp.EmployeeName + " Age - " + emp.EmployeeAge);
            }
            MessageBox.Show(strBuilder.ToString());
        }
 
        private void button3_Click(object sender, RoutedEventArgs e)
        {
            using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString))
            {
                IQueryable<Employee> EmpQuery = from Emp in Empdb.Employees where Emp.EmployeeName == txtName.Text select Emp;
                Employee EmpRemove = EmpQuery.FirstOrDefault();
                Empdb.Employees.DeleteOnSubmit(EmpRemove);
                Empdb.SubmitChanges();
                MessageBox.Show("Employee Deleted Successfully!!!");
            }
        }
 
        private void button5_Click(object sender, RoutedEventArgs e)
        {
            using (EmployeeDataContext Empdb = new EmployeeDataContext(strConnectionString))
            {
                if (Empdb.DatabaseExists())
                {
                    Empdb.DeleteDatabase();
                    MessageBox.Show("Employee Database Deleted Successfully!!!");
                }
            }
        }
    }
 
}
 
Now we are done with our code, to build and test the application press F5 and we can see the expected outputs as shown in the screen below.

Output Screens:


Clipboard12.jpg
Clipboard13.jpg

Conclusion:

So in this article we have seen how to use the local isolated storage to create and use the database by using the Linq to SQL data context and also we have seen the different steps to achieve the tasks mentioned on start of this article.

No comments:

Post a Comment