Monday, May 28, 2012

SQLIte Database Take Two

I wanted to redo the database in the simplest way possible to make things clearer. To do this I made a simple initial form with two buttons:

I still needed to create the sqlHelper class. But this time I only created a single table. Here is the code for the SqlHelperClass

package com.spconger.programmingresourcesdata;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;


public class SqlHelperClass extends SQLiteOpenHelper{

 /*
  * This class extends SqlLiteOpenHelper
  * It creates the database and the tables
  * and sets static constants that are used
  * in the other classes
  */
 
 //set database as priiate constatn
 private static final String DATABASE_NAME = "ProgramResources.db";
 private static final int DATABASE_VERSION = 1;
 
 //public constants
 //database table
 public static final String TABLE_NAME="Book";
 
 //columns
 public static final String BOOK_ID="bookId";
 public static final String BOOK_TITLE="title";
 public static final String BOOK_AUTHOR="author";
 public static final String BOOK_RATING="Rating";
 
 //required constructor
 //takes the contest which is usually the current 
 //activity, it also passes the database name and
 //version to the super class
 public SqlHelperClass(Context context) {
  super(context, DATABASE_NAME, null, DATABASE_VERSION);
  // TODO Auto-generated constructor stub
 }

 @Override
 public void onCreate(SQLiteDatabase db) {
  // here we create the table
  String sql_Book="CREATE TABLE " + TABLE_NAME
  +"(" + BOOK_ID + " integer primary key autoincrement, " 
  + BOOK_TITLE + " text not null, "
  + BOOK_AUTHOR + " text not null, "
  + BOOK_RATING + " int, "
  + "unique (" +BOOK_TITLE + "))";
  
  //add the table to the database
  db.execSQL(sql_Book);
 }

 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  //You should put code here to handle new versions of the database
  
 }

}


Here is the form for adding records


The java behind this form is fairly straight forward. I just initialize a writable database, get the values from the EditText controls and insert them into the database

package com.spconger.programmingresourcesdata;



import android.app.Activity;
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class AddRecordsActivity extends Activity{
 /*
  * This activity adds records to the database. 
  * I purposefully kept this simple
  * not breaking it into too many methods
  * Consequently the AddRecord method does 
  * more than it probably should
  */
 EditText txtTitle;
 EditText txtAuthor;
 EditText txtRating;
 Button btnSave;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.addrecords);
  
  btnSave = (Button)findViewById(R.id.button1);
  btnSave.setOnClickListener(new AddRecordListener());
 }
 
 private class AddRecordListener implements View.OnClickListener{

  @Override
  public void onClick(View v) {
   
   //get database
   SqlHelperClass sqlHelper = new SqlHelperClass(AddRecordsActivity.this);
   SQLiteDatabase db= sqlHelper.getWritableDatabase();
   
   //get the values from the EditText controls
   
   txtTitle = (EditText)findViewById(R.id.editTextTitle);
   String title=txtTitle.getText().toString();
   
   txtAuthor=(EditText)findViewById(R.id.editTextAuthor);
   String author=txtAuthor.getText().toString();
   
   txtRating = (EditText)findViewById(R.id.editTextRating);
   String ratingString=txtRating.getText().toString();
   int rating=Integer.parseInt(ratingString);
   
   //add the values from the EditViews to the columns
   ContentValues values = new ContentValues();
   values.put(SqlHelperClass.BOOK_TITLE,title);
   values.put(SqlHelperClass.BOOK_AUTHOR, author);
   values.put(SqlHelperClass.BOOK_RATING, rating);
   
   
   //Insert into the database
   long book_id= db.insert(SqlHelperClass.TABLE_NAME, null, values);
   db.close();
   
   //if the insert is successful
   if(book_id != -1)
   {
    //start a toast (a message)
    Toast toast = Toast.makeText
       (AddRecordsActivity.this, "Record Added", Toast.LENGTH_LONG);
    toast.show();
   }
   else
   {
    Toast toast = Toast.makeText
      (AddRecordsActivity.this, "Record failed to Insert", Toast.LENGTH_LONG);
             toast.show();
   }
            
   //clear for next record
            clearForm();
   
   
   }
   
  }
  
  private void clearForm()
  {
   txtTitle.setText("");
   txtAuthor.setText("");
   txtRating.setText("");
  }
  }
  

finally we just view the records. I didn't do anything fancy. I created a cursor to look through the records and appended them to a string that terminates with a new line character. Then I set the resulting text to the ViewText. Here is the codeL

package com.spconger.programmingresourcesdata;

import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.widget.TextView;


public class ViewRecordsActivity extends Activity{
 
 /*
  * Again, to make this simple, the getRecords method
  * does more than one record should do
  * 
  */
 @Override
  protected void onCreate(Bundle savedInstanceState) {
 // TODO Auto-generated method stub
 super.onCreate(savedInstanceState);
 setContentView(R.layout.viewrecords);
 
 getRecords();
 }
 
 private void getRecords(){
  
  //initiate the SqlHeperClass and get the database
  SqlHelperClass sqlHelper = new SqlHelperClass(ViewRecordsActivity.this);
  SQLiteDatabase db= sqlHelper.getWritableDatabase();
  
  //create an array of the columns
  String[] columns = new String[] 
         {sqlHelper.BOOK_TITLE, 
    sqlHelper.BOOK_AUTHOR, 
    sqlHelper.BOOK_RATING};
  
  //start a cursor to move through the records
  Cursor cursor = db.query(sqlHelper.TABLE_NAME, columns, null, null, null, null, null);
  
  String result="";
  //use the cursor to loop through the records
  for(cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()){
   //I am just concatenating the records into a string
   //terminated by a line break
   result+= cursor.getString(0) + ", " + cursor.getString(1) + "--" + cursor.getInt(2) + "\n" ;
  }
  
  //assign the result to the textview
  TextView content=(TextView)findViewById(R.id.content_list);
  content.setText(result);
 }
}

Here is the the activity running

Thursday, May 24, 2012

LINQ Example

here is our example using LINQ

Remember you need to add a LINQ to SQL designer to your project and the drag the tables from the Server Explorer onto the Designer. Then be sure to save the Designer so that it will generate the classes that you need.

The LINQ Designer

The first thing we did was to simple load the services into a dataList. Here is the code behind


Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        CommunityAssistDataContext dc = new CommunityAssistDataContext();
        var serv = from s in dc.Services
                   orderby s.ServiceName
                   select new { s.ServiceName, s.ServiceDescription };
        /*
        var donors = from d in dc.Donations
                     select new { d.Person.FirstName, d.Person.LastName, d.DonationDate}
         */
        
        DataList1.DataSource = serv.ToList();
        DataList1.DataBind();
    }
    protected void LinkButton1_Click(object sender, EventArgs e)
    {
        Response.Redirect("Donate.aspx");
    }
}

Here is the source for Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" 
CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <h1>Services Offered</h1>
    <p>
        <asp:DataList ID="DataList1" runat="server">
        <ItemTemplate>
        
            <strong><asp:Label ID="Label1" runat="server" 
Text='<%#Eval("ServiceName") %>'></asp:Label></strong>, 
            <asp:Label ID="Label2" runat="server" 
Text='<%#Eval("ServiceDescription") %>'></asp:Label>
         <br />
        </ItemTemplate>
        </asp:DataList>
        </p>
        <asp:LinkButton ID="LinkButton1" runat="server" 
onclick="LinkButton1_Click">Donate?</asp:LinkButton>
    </div>
    </form>
</body>
</html>


Here is the Source for Donate.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Donate.aspx.cs" Inherits="Donate" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <table>
    <tr>
    <td> 
        <asp:Label ID="Label1" runat="server" Text="First Name"></asp:Label></td>
    <td> 
        <asp:TextBox ID="txtFirstname" runat="server"></asp:TextBox></td>
    </tr>
    
     <tr>
    <td> 
        <asp:Label ID="Label2" runat="server" Text="Last Name"></asp:Label></td>
    <td> 
        <asp:TextBox ID="txtLastName" runat="server"></asp:TextBox></td>
    </tr>

     <tr>
    <td> 
        <asp:Label ID="Label3" runat="server" Text="Street"></asp:Label></td>
    <td> 
        <asp:TextBox ID="txtStreet" runat="server"></asp:TextBox></td>
    </tr>

     <tr>
    <td> 
        <asp:Label ID="Label4" runat="server" Text="City"></asp:Label></td>
    <td> 
        <asp:TextBox ID="txtCity" runat="server"></asp:TextBox></td>
    </tr>

     <tr>
    <td> 
        <asp:Label ID="Label5" runat="server" Text="State"></asp:Label></td>
    <td> 
        <asp:TextBox ID="txtState" runat="server"></asp:TextBox></td>
    </tr>

     <tr>
    <td> 
        <asp:Label ID="Label6" runat="server" Text="Zip Code"></asp:Label></td>
    <td> 
        <asp:TextBox ID="txtZipCode" runat="server"></asp:TextBox></td>
    </tr>

     <tr>
    <td> 
        <asp:Label ID="Label7" runat="server" Text="Phone"></asp:Label></td>
    <td> 
        <asp:TextBox ID="txtPhone" runat="server"></asp:TextBox></td>
    </tr>

     <tr>
    <td> 
        <asp:Label ID="Label8" runat="server" Text="Email"></asp:Label></td>
    <td> 
        <asp:TextBox ID="txtEmail" runat="server"></asp:TextBox></td>
    </tr>

     <tr>
    <td> 
        <asp:Label ID="Label9" runat="server" Text="Donation"></asp:Label></td>
    <td> 
        <asp:TextBox ID="txtDonation" runat="server"></asp:TextBox></td>
    </tr>
     <tr>
    <td> 
        <asp:Button ID="Button1" runat="server" Text="Donate" onclick="Button1_Click" />
     </td>
    <td> 
        <asp:Label ID="lblResult" runat="server" Text=""></asp:Label>
        </td>
    </tr>
    </table>
    </div>
    </form>
</body>
</html>


Here is the code behind for Donate.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Donate : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        CommunityAssistDataContext dc = new CommunityAssistDataContext();
        Person p = new Person();
        p.FirstName = txtFirstname.Text;
        p.LastName = txtLastName.Text;

        dc.Persons.InsertOnSubmit(p);

        PersonAddress pa = new PersonAddress();
        pa.Person = p;
        pa.Street = txtStreet.Text;
        pa.City = txtCity.Text;
        pa.State = txtState.Text;
        pa.Zip = txtZipCode.Text;

        dc.PersonAddresses.InsertOnSubmit(pa);

        PersonContact phone = new PersonContact();
        phone.Person = p;
        phone.ContactInfo = txtPhone.Text;
        phone.ContactTypeKey = 1;

        dc.PersonContacts.InsertOnSubmit(phone);

        PersonContact email = new PersonContact();
        email.Person=p;
        email.ContactInfo=txtEmail.Text;
        email.ContactTypeKey=6;

        dc.PersonContacts.InsertOnSubmit(email);

        Donation d = new Donation();
        d.Person = p;
        d.DonationAmount = decimal.Parse(txtDonation.Text);
        d.DonationDate = DateTime.Now;
        d.EmployeeKey = 1;

        dc.Donations.InsertOnSubmit(d);

        dc.SubmitChanges();

        lblResult.Text = "Thank you for your Donation";
    }
}

Wednesday, May 23, 2012

ITC 162 Project

I am going to make the requirements for this minimal, given how little of the quarter is left.

The project should involve multiple activities and multiple java classes. Other than that, all I really want to see is your attempts to explore Android.

If design is your interest, you can spend the time working with the android's controls and resources, or, if programming is more your interest, see about adding some functionality, maybe consuming services on the phone or from the cloud.

You can work on these alone or in groups

I would like for groups or individuals to present what they have done on Monday of finals week

Logins, Users, Schema, Roles

---sql server login
--schema dbo as ownership
--roles
--user
--logins give you connection access to the server but not much else
Create login emp with password='p@ssw0rd1', default_database =CommunityAssist


Use CommunityAssist
--users are database specific and are always associated with a server login
Create user employ for login emp 
go
--schemas are groups of ownership
Create schema Employee

--create an object that belongs to the schema
Create view Employee.Donors
as
Select LastName, firstname,
DonationDate, Donationamount
From Person p
inner Join Donation d
on p.PersonKey=d.PersonKey

--add the user to the schema
Alter user employ with default_schema=Employee

--give the user select permissions on all the objects 
--in the schema 
Grant select on  Schema::Employee to Employ 

--A role is a collection of permissions
Create Role humanResources
Grant Select, update on Employee to humanResources
Grant Select, update on Person to humanResources

/* 
these are all the database permissions you can grant
Select 
Insert
UPDATE
Delete
Create
Alter
exec
drop
*/

--add an use to the role using a stored procedure
exec sp_addRoleMember  humanResources, employ
go

--this drops a user from the role
exec sp_droprolemember humanResources employ

Tuesday, May 22, 2012

Code for Scanner and Testing

We programmed the core functionality of the scanner in order to test it. First here are some diagrams of the code

Class Diagram


Sequence Diagram


Now here is the code for the classes

Program.cs

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

namespace DoorCardProofOfConcept
{
    class Program
    {
      
    
        static void Main(string[] args)
        {
            int exit = 1;
            while (exit != -1)
            {
                Console.WriteLine("Enter Card Number");
                string card = Console.ReadLine();
                Console.WriteLine("enter the Door number");
                string door = Console.ReadLine();
                Scanner s = new Scanner(card, door);
                Console.WriteLine(s.DoorState);
                Console.WriteLine("Enter -1 to Exit");
                exit = int.Parse(Console.ReadLine());
            }

           // Console.ReadKey();

        }
    }
}


Scanner.cs

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

namespace DoorCardProofOfConcept
{
    /// 
    /// This class represents the physical
    /// scanner. It reads the card
    /// creates a scan object and sends it
    /// off to be validated
    /// if the validation returns true
    /// it opens the door
    /// 
    /// 
    class Scanner
    {
        string cardNumber;
        string scannerID;
        string doorState;
        Scan scan;

        public Scanner(string card, string ID)
        {
            cardNumber = card;
            scannerID = ID;
            doorState = "closed";
            CreateScan();
            getScanValidated();

        }

        public string DoorState
        {
            get { return doorState; }
        }

        internal Validator Validator
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
            }
        }

        internal Scan Scan
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
            }
        }

        private void CreateScan()
        {
            DateTime date = DateTime.Now;
            scan = new Scan(scannerID,cardNumber, date);
        }

        public void getScanValidated()
        {
            bool isValid = false;
            Validator v = new Validator(scan);
            isValid = v.Validate();
            if (isValid)
            {
                doorState = "Open";
            }
            
        }
    }
}


Scan.cs

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

namespace DoorCardProofOfConcept
{
    class Scan
    {
        /// 
        /// this class is simply a collection
        /// of data so that it can be passed
        /// as a single package
        /// 
        /// 
        /// 
        /// 

        public Scan(string number, string card, DateTime date)
        {
            scannerNumber = number;
            cardNumber = card;
            this.date = date;

        }
        private string scannerNumber;

        public string ScannerNumber
        {
            get { return scannerNumber; }
           
        }
        private string cardNumber;

        public string CardNumber
        {
            get { return cardNumber; }
           
        }
        private DateTime date;

        public DateTime Date
        {
            get { return date; }
           
        }
        

    }
}


Validator

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

namespace DoorCardProofOfConcept
{
    /// 
    /// this class recieve the scan
    /// and validate its contents
    /// against a database
    /// (for now an xmlFile)
    /// 
    class Validator
    {

        private Scan scan;

        public Validator(Scan s)
        {
            scan = s;
        }

        public bool Validate()
        {
            bool valid = false;
            DataSet table = new DataSet();
            table.ReadXml(@"ScheduleData.xml");

            foreach (DataRow row in table.Tables[0].Rows)
            {
                if (scan.CardNumber.Equals(row["card"].ToString()) &&
                    scan.ScannerNumber.Equals(row["door"].ToString()) &&
                    scan.Date.ToShortDateString().Equals(row["date"].ToString())
                    && scan.Date>=DateTime.Parse(row["begintime"].ToString())
                     && scan.Date<=DateTime.Parse(row["endtime"].ToString()))
                {
                    valid = true;
                }


            }

            return valid;
        }
    }
}


ScannerData.xml

<?xml version="1.0" encoding="utf-8" ?>
<schedule>
  <item>
    <card>100</card>
    <door>1</door>
    <date>5/22/2012</date>
    <begintime>9:00</begintime>
    <endtime>17:00</endtime>
  </item>
  <item>
    <card>100</card>
    <door>2</door>
    <date>5/23/2012</date>
    <begintime>9:00</begintime>
    <endtime>13:00</endtime>
  </item>
  <item>
    <card>101</card>
    <door>2</door>
    <date>5/22/2012</date>
    <begintime>10:00</begintime>
    <endtime>15:00</endtime>
  </item>
</schedule>

Here is the spreadsheet of our results

Monday, May 21, 2012

XML and SQL

use CommunityAssist

--xml
--outputting data as xml
--xml as a data type
--xml schema collections
--xquery
--these are using all options
Select * from Person for xml raw('person'), root ('Persons'), elements

Select lastName, FirstName, DonationDate, donationAmount
From Person 
Inner Join Donation 
on person.PersonKey=donation.PersonKey
for xml auto, elements, root('dataroot') 

--explicit: you have to specify exactly where 
in the xml heirarchy each field belongs

--xml as a datatype

Select * From Meeting

--we are dropping the column in order to add it back in with a 
--schema

Alter Table Meeting
drop column meetingnotes

--this creates a schema collection which can be used
--to test whether a given xml document entered
--into an xml data column conforms to certain specifications
Create xml schema collection MeetingNotesSchemaCollection
As
'<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" 
elementFormDefault="qualified" 
targetNamespace="http://www.seattlecentral.edu/meetingnotes" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="meetingnotes">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="heading">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="attending">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="member" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="body">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="notes" />
              <xs:element name="tasks">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="taskname" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>'

--add back in the table column with the schema
Alter table meeting
Add meetingnotes xml(MeetingNotesSchemaCollection)

--insert a record with the xml column
Insert into Meeting (MeetingDate, MeetingTopic, meetingnotes)
Values(GETDATE(), 'More Naps',
'<?xml version="1.0" encoding="utf-8"?>
<meetingnotes xmlns="http://www.seattlecentral.edu/meetingnotes" >
  <heading>
    <attending>
      <member>Joe</member>
      <member>Sue</member>
    </attending>
  </heading>
  <body>
    <notes>The staff would like more nap time</notes>
    <tasks>
      <taskname>Find a napping place</taskname>
      <taskname>find a nap time</taskname>
    </tasks>
  </body>
</meetingnotes>')

select * from meeting


--this one fails because the capital A on Attending doesn't
--conform to the schema
Insert into Meeting (MeetingDate, MeetingTopic, meetingnotes)
Values(GETDATE(), 'More Naps',
'<?xml version="1.0" encoding="utf-8"?>
<meetingnotes xmlns="http://www.seattlecentral.edu/meetingnotes" >
  <heading>
    <Attending>
      <member>Joe</member>
      <member>Sue</member>
    </Attending>
  </heading>
  <body>
    <notes>The staff would like more nap time</notes>
    <tasks>
      <taskname>Find a napping place</taskname>
      <taskname>find a nap time</taskname>
    </tasks>
  </body>
</meetingnotes>')

--another insert
Insert into Meeting (MeetingDate, MeetingTopic, meetingnotes)
Values(GETDATE(), 'Application Review',
'<?xml version="1.0" encoding="utf-8"?>
<meetingnotes xmlns="http://www.seattlecentral.edu/meetingnotes" >
  <heading>
    <attending>
      <member>Bob</member>
      <member>Lisa</member>
      <member>Sasha</member>
    </attending>
  </heading>
  <body>
    <notes>We reviewed 20 applications and approved 12</notes>
    <tasks>
      <taskname>Inform recipients</taskname>
     
    </tasks>
  </body>
</meetingnotes>')

--these are examples of xquery
Select MeetingDate, MeetingTopic, 
meetingnotes.query('declare namespace mn="http://www.seattlecentral.edu/meetingnotes"; 
//mn:meetingnotes/mn:heading/mn:attending/mn:member') as Attending
From Meeting

Select MeetingDate, MeetingTopic, 
meetingnotes.query('declare namespace mn="http://www.seattlecentral.edu/meetingnotes"; 
//mn:meetingnotes/mn:body/mn:notes') as Attending
From Meeting

Select MeetingDate, MeetingTopic, 
meetingnotes.query('declare namespace mn="http://www.seattlecentral.edu/meetingnotes";
 //mn:meetingnotes/mn:body') as Attending
From Meeting

Sunday, May 20, 2012

Android Assignment 3 (assignment 6)

The goal of this assignment is to create a database with two tables, a recipe table and an ingredients table.

The Recipe Table should have a
RecipeID which is an autonumber
RecipeName which is String
RecipeDescription also String

The Ingredient Table should have
RecipeID as a foreign key
IngredientName as String

The structure is essentially identical to the CD/Tracks structure

The app should work like the example. the first activity should list the available recipes. When one is clicked on a second activity that shows all the ingredients should open. Also on the first activity there should be a button or a clickable text that takes you to an activity to insert a new recipe.

For an extra challenge you can try to add edit and delete buttons on the detail activity to further manage the records.

SQLLite Database in Android

This is fairly complex for what is really a simple thing. This example creates a database to store CDs and Tracks. The main form shows you what CDs are in the database. If you tap (or in the emulator click) on a CD it takes you to the detail view where you can see the CD title, artist and all the tracks. Also at the bottom of the main form is a clickable TextView that takes you to an Activity where you can input a new Cd and tracks.

You can get the complete project in a zip file here

Here are screen shots of the views:

the main view with some data already in the database


here is a view of the detail screen


And here is the input screen


Creating the Database

The first thing you need to do is create the database and the tables. The best way to do this is to use a SQLHelper class which extends SQLLiteOpenHelper. Here is the code for my class


package com.spconger.databasetest;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class SQLHelper extends SQLiteOpenHelper{
/*
 * this class creates the database and its tables. it 
 * extends the SQLiteOpenHelper class
 * which give access to the sql lite database
 */
 
 //create the database
 private static final String DATABASE_NAME = "Cds.db";
 private static final int DATABASE_VERSION = 1;

 // Table name
 public static final String CD_TABLE = "CD";
 public static final String TRACK_TABLE = "Tracks";
 
 // CD Table columns
 public static final String CD_TITLE = "CDTitle";
 public static final String CD_ARTIST = "Artist";
 
 //Track table columns
 public static final String CD_ID="CdId";
 public static final String TRACK_TITLE = "TrackTitle";
 
 
 //required constructor
 public SQLHelper(Context context) {
  super(context, DATABASE_NAME, null, DATABASE_VERSION);
  // TODO Auto-generated constructor stub
 }

 @Override
 public void onCreate(SQLiteDatabase db) {
  // create the CD table
  String sql_CD = "create table " + CD_TABLE + "( " + 
  CD_ID + " integer primary key autoincrement, " +
  CD_TITLE + " text not null, " + 
  CD_ARTIST + " text not null, " + 
  "unique (" + CD_TITLE + "))";

db.execSQL(sql_CD); //add to the database

//create the Track table
String sql_Track = "create table " + TRACK_TABLE + "( " +  
CD_ID + " integer, " + 
TRACK_TITLE + " text not null, " + 
"foreign key (" + CD_ID+ ") references " + CD_TABLE + "(_id));";

db.execSQL(sql_Track);
  
 }

 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  // this method is used to save data, drop and recreate tables when
  //the database software is upgraded
  
 }

}



The Android App

To work with the database, we create a CD class to store CD and track information. The tracks are stored in a listArray. the fields are entered at the constructor, and each has a get accessor. There is a method to add tracks to the arraylist, and a method that loops through the array list and writes all the tracks to the a string with line breaks after each track. I will not display that class here, but it is available in the zip file.

In the main activity, We make contact with the database and read all the data into a listarray of CDs. Then we display the titles on the screen. Here is the code to do that. It is a lot of code


 private void initPatientList()
 {
     //initialize the list view
  cdListView = (ListView) findViewById(R.id.CdListView);
  cds = new ArrayList<CD>();
  
  //link to the database
  SQLHelper sqlHelper = new SQLHelper(DatabaseTestActivity.this);
  SQLiteDatabase db = sqlHelper.getWritableDatabase();           
  
  //create a cursor to move through the data
        Cursor cdCursor = db.query(SQLHelper.CD_TABLE, 
          new String[] {"*"}, "", null, null, null, null);
        
        int cdId = -1;
        CD cd; //create an instance of the CD class
        
        //cycle through each row of data
  while(cdCursor.moveToNext())
  {
   cdId = cdCursor.getInt(0);
     
   if(cdId != -1)
   {
    //if there are cds add the title and artist to the object
    cd = new CD(cdId, cdCursor.getString(1), cdCursor.getString(2));
    
    //add the tracks
    Cursor trackCursor = db.query(SQLHelper.TRACK_TABLE, 
            new String[] {SQLHelper.TRACK_TITLE}, SQLHelper.CD_ID + " = " + cdId, 
            null, null, null, null);
    
          //cycle through each row
    while(trackCursor.moveToNext())
    {
     cd.AddTracks(trackCursor.getString(0));
    }
    
    cds.add(cd); //add the CD to a list of Cds
   }
  }
  
  if (cds.size() > 0) 
  {
   //add the cds to the list view
   CdAdapter cdAdapter = new CdAdapter(this, R.layout.cd_row, cds);
   cdListView.setAdapter(cdAdapter);
   
   //each time a cd row is clicked we will bring up the CDDetail activity
   //to see all of the CD data
   cdListView.setOnItemClickListener(new PatientItemClickListener());
  }
 }
     
 //set up the add record label to be underlined
    private void initAddRecordTextView()
    {
     String addRecordText = this.getString(R.string.add_record);
     SpannableString contentUnderline = new SpannableString(addRecordText);
     contentUnderline.setSpan(new UnderlineSpan(), 0, contentUnderline.length(), 0);
     
     TextView addRecordTV = (TextView)findViewById(R.id.txtView_addRecord);
     addRecordTV.setText(contentUnderline);
     
     addRecordTV.setOnClickListener(new AddRecordListener());
    }
    
    /*
     * when the Add Record link is clcked then go to the add patient screen
     */
    private class AddRecordListener implements View.OnClickListener
    {

  @Override
  public void onClick(View v)
  {
   startActivity(new Intent(DatabaseTestActivity.this, AddRecordActivity.class));
  }
     
    }
    
    /*
     * Adds each CD from the array of patients into the adapter. 
     * Applyng the Cd_row layout file to each of them
     */
    private class CdAdapter extends ArrayAdapter 
    {
     public CdAdapter(Context context, int textViewResourceId, ArrayList cds) 
     {
   super(context, textViewResourceId, cds);
  }
     
     @Override
  public View getView(int position, View convertView, ViewGroup parent) 
     {
      if (convertView == null) 
      {
    LayoutInflater mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    convertView = mInflater.inflate(R.layout.cd_row, null);
   }
      
      final CD cd = getItem(position);
      
      if(cd != null)
      {
       TextView nameTV = (TextView) convertView.findViewById(R.id.TextView_Name);
       nameTV.setText(cd.getCdTitle());
      }
      
      return convertView;
     }
    }
    

In addition there is an ActionListener which bundles of all the content of cd that is clicked on and opens the detail view


private class PatientItemClickListener implements OnItemClickListener
    {

  @Override
  public void onItemClick(AdapterView adapter, View view, int position,long id)
  {
   CD cd = cds.get(position);
   Intent cdIntent = new Intent(DatabaseTestActivity.this, CDDetail.class);
   cdIntent.putExtra("cdId", cd.getID());
   cdIntent.putExtra("cdTitle", cd.getCdTitle());
   cdIntent.putExtra("cdArtist", cd.getCdArtist());
   cdIntent.putExtra("cdTracks", cd.getTracks());
   
   startActivity(cdIntent);
  }
     
    }

in the detail view we take the CD object that was sent across in the bundle and display the information


import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class CDDetail extends Activity {
 /*
  * This class takes a cd sent from the main
  * activity and displays all its data
  */
 
 private int cdId;
 private String title;
 private String artist;
 private String tracks;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.cd_detail);
  
  Bundle extra = getIntent().getExtras();
  initFormData(extra);
 }
 private void initFormData(Bundle extra)
 {
  if (extra != null) 
  { 
   cdId = extra.getInt("cdId");
      title = extra.getString("cdTitle");
      artist = extra.getString("cdArtist");
      
      tracks = extra.getString("cdTracks");
   
   
      initView(title, R.id.textView_cdTitle);
   initView(artist, R.id.textView_cdArtist);
   initView(tracks, R.id.textView_cdTracks);
  }
 }
 
 /*
  * Initilaize a text view with the data
  */
 private void initView(String patientData, int textViewName)
 {
  TextView PatientDataTV = (TextView)findViewById(textViewName);
  PatientDataTV.setText(patientData);
 }

}

Finally we will look at the Input form. Here is the code that inserts into the database


package com.spconger.databasetest;


import android.app.Activity;
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class AddRecordActivity extends Activity{

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.add_record_layout);
  
  Button saveButton = (Button)findViewById(R.id.button1);
  saveButton.setOnClickListener(new SaveClickListener());
  
 }
 private class SaveClickListener implements View.OnClickListener
    {
     public void onClick(View v) 
     { 
      String cdTitle = showHideNameError(R.id.editTextTitle, R.id.title_error);
      String artist = showHideNameError(R.id.editTextArtist, R.id.artist_error);
      
         if( cdTitle == null || artist == null)
         {
          Toast errorEntry = Toast.makeText(AddRecordActivity.this, 
            "Settings were entered incorectly", Toast.LENGTH_LONG);
          errorEntry.show();
         }
         else
         {
          SQLHelper sqlHelper = new SQLHelper(AddRecordActivity.this);
          SQLiteDatabase db = sqlHelper.getWritableDatabase();
          
          long cdId = addCDToDB(sqlHelper, db, cdTitle, artist);
          
                if( cdId != -1)
                {
                 if(addAlergiesToDB(sqlHelper, db, cdId))
                 {
                  Toast successEntry = Toast.makeText(AddRecordActivity.this, 
              "CD successfully added", Toast.LENGTH_LONG);
            successEntry.show();
                 }
                }
               
         }
        }
    }
  
 /*
  * Will test if the entry is empty
  * if so it will display an error and if not it will clear the error
  */
 private String showHideNameError(int editTextId, int errorTextViewId)
    {
     EditText nameBox = (EditText)findViewById(editTextId);
     String name = nameBox.getText().toString().trim();
     
     TextView nameError = (TextView)findViewById(errorTextViewId);
     
     if(name.length() <= 0)
     {
      /* show error if the name isn't at least 3 characters */
      nameError.setText(R.string.error_blank);
      return null;
     }
     else
     {
      /* clear error if the name isn't at least 3 characters */
      nameError.setText("");
      return name;
     } 
    }
 
 
 /*
  * Adds the specified patient to the database
  * returns the patient id if the entry was entered correctly
  * returns -1 if the patient wasn't successfully entered into the db
  */
 private long addCDToDB(SQLHelper sqlHelper, SQLiteDatabase db, String title, String artist)
 {
  ContentValues values = new ContentValues();
        values.put(SQLHelper.CD_TITLE, title);
        values.put(SQLHelper.CD_ARTIST, artist);
        
        long cdId = db.insert(SQLHelper.CD_TABLE, null, values);
        
        if(cdId == -1)
        {   
         Toast toast = Toast.makeText(AddRecordActivity.this, "Error adding user to db" , Toast.LENGTH_LONG);
            toast.show();
            sqlHelper.close();
            return -1;
        }
        
        return cdId;
 }
 
 /*
  * Splits up the Tracs each one having it's own line,
  * then adds each entry to the db
  * returns true if they were successfully entered and false otherwise
  */
 private boolean addAlergiesToDB(SQLHelper sqlHelper, SQLiteDatabase db, long cdId)
 {
  ContentValues values = new ContentValues();
  
  EditText trackBox = (EditText)findViewById(R.id.editTextTracks);
  String trackText = trackBox.getText().toString().trim();
  
  if(trackText == "")
  {
   return true; //successfully added nothing
  }
  
  String[] trackItems = trackText.split("\n");
  
  for(int i= 0 ; i<trackItems.length; i++)
  {
   values.put(SQLHelper.CD_ID, cdId);
         values.put(SQLHelper.TRACK_TITLE, trackItems[i]);
         long id = db.insert(SQLHelper.TRACK_TABLE, null, values);
         
         if(id == -1)
         {
          Toast toast = Toast.makeText(AddRecordActivity.this, "Failure during insert", Toast.LENGTH_LONG);
             toast.show();
             return false;
         }
  }
  
  return true;
 }
}

Monday, May 14, 2012

Triggers

use CommunityAssist

--trigger
--procedures that fire when an event occurs
--most common: insert update and delete
--used to enforce business rules
--for, after, instead of
go
-- this trigger checks to see if a donor 
--donates more than a 1000 dollars
--if they do it will write their donation
--to a table call bigDonations for a follow
--up later
Create trigger tr_HighDonation on Donation
for insert,update --works on both insert and update
As
Declare @donationAmount money
--get the value of the donation from the temporary
--table "inserted"
Select @donationAmount = donationAmount
from inserted
--test the value 
If @donationAmount >= 1000
Begin
    --if the table doesn't exist create it
 if not exists
  (Select name from sys.tables where name='bigDonations')
 Begin
  Create table bigDonations
  (
   DonationKey int, 
   DonationDate dateTime, 
   DonationAmount money, 
   PersonKey int, 
   EmployeeKey int
  )
 end
 --insert into the table bigDonations
 --from the temporary inserted table
 Insert into bigDonations(DonationKey, 
 DonationDate, 
 DonationAmount, 
 PersonKey, EmployeeKey)
 Select DonationKey, DonationDate, 
 DonationAmount, PersonKey, 
 EmployeeKey from Inserted
End

--insert to test the trigger
--this goes into the bigDonation Table
Insert into Donation(DonationDate, DonationAmount, 
PersonKey, EmployeeKey)
Values(GETDATE(), 1002,1,1)

--this doesn't
Insert into Donation(DonationDate, DonationAmount, 
PersonKey, EmployeeKey)
Values(GETDATE(), 999,63,1)

Select * From donation

Select * from bigDonations
 
Go
--an instead of trigger intercepts the event and
--does its commands instead of the eve t
Create Trigger tr_NoDelete on Donation
instead of delete
as
print 'You can''t delete from this table'

go
--test the instead of trigger
Delete from Donation where DonationKey=3
Delete From Donation

Sunday, May 13, 2012

File reading example

This example shows how to read text and xml resource files. It has 3 activities, a main one that has two buttons, a second one that reads a text file into a TextView control and a third one that reads an XML file into a TableLayout. The app provides a brief overview of the Doctor Who show and a list of all the doctors.

I am not going to show all the code, but you can download a zip file of the whole project here.

The text file is stored in a new folder under res called "raw". For the xml file I added a new folder called "xml" also under res.

Here is a complete expanded view of the project directory



First we will look at the text file. The Activity consists of just a TextView nested in a ScrollView

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

  
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scrollbars="vertical">

    <TextView
        android:id="@+id/txtContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium" />
    
    </ScrollView>

Here is the Java code for the activity that reads the text file named overview.txt

package com.spconger.doctorwho;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import android.util.*;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class OverViewActivity extends Activity{

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.overview);
  
  fillOverView();
  
  
  
 }
 
 private void fillOverView(){
  
  try{
   //create an Input stream to read the file
  InputStream overviewFile = getResources().openRawResource(R.raw.overview);
  //assign it to a string the method is down below
  String overviewData=inputStreamToString(overviewFile);
  
  //get the TextView
  TextView txtOverview=(TextView)findViewById(R.id.txtContent);
  //set the text
  txtOverview.setText(overviewData);
  
  }
  catch(IOException e)
  {
   Log.e("DEBUG","InputStreamToString failure");
  }
  
  
  
 }
 
 private String inputStreamToString(InputStream is) throws IOException{
  //create a buffer
  StringBuffer sBuffer = new StringBuffer();
  DataInputStream dataIO = new DataInputStream(is);
  String strLine=null;
  
  while((strLine=dataIO.readLine()) != null){
   sBuffer.append(strLine + "\n");
   
  }
  dataIO.close();
  is.close();
  return sBuffer.toString();
 }

}

The xml file is called "doctorlist.xml" and follows this pattern:

\
<?xml version="1.0" encoding="UTF-8"?>
<doctors>
<doctor
 number="First"
 name="William Hartnell"
 tenure="1963-1966" />

...

</doctors>

The xml is read into a TableLayout. Here is the xml of the Activity

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

    
   <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scrollbars="vertical">
        
       <TableLayout
           android:id="@+id/tableLayout_doctors"
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:stretchColumns="*" />
      
       
   </ScrollView>

here is the java code for the activity that reads the xml

package com.spconger.doctorwho;

import android.app.Activity;
import android.os.Bundle;
import android.util.*;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.content.Intent;
import android.content.res.XmlResourceParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.*;

public class DoctorActivity extends Activity {
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.doctors);
  try
  {
   getDoctors();
  }
  catch(Exception e){
   Log.e("DEBUG", "Failed to load Doctors",e);
  }
 }

 private void getDoctors()throws XmlPullParserException, IOException{
  TableLayout doctorTable=(TableLayout)findViewById(R.id.tableLayout_doctors);
  
  XmlResourceParser doctorsXML=getResources().getXml(R.xml.doctorlist);
  
  int eventType=-1;
  
  while (eventType != XmlResourceParser.END_DOCUMENT){
   if (eventType==XmlResourceParser.START_TAG){
    String strName=doctorsXML.getName();
    
    if (strName.equals("doctor")){
     String doctorNumber=doctorsXML.getAttributeValue(null,"number");
     String doctorName=doctorsXML.getAttributeValue(null,"name");
     String doctorTenure=doctorsXML.getAttributeValue(null,"tenure");
     insertDoctorRow(doctorTable, doctorNumber, doctorName, doctorTenure);
    }
   }
   eventType=doctorsXML.next();
  }
  
 }
 
 private void insertDoctorRow(final TableLayout doctorTable, 
               String doctorNumber, String doctorName, String doctorTenure){
     
  final TableRow newRow=new TableRow(this);
  addTextToRowWithValues(newRow, doctorNumber);
  addTextToRowWithValues(newRow, doctorName);
  addTextToRowWithValues(newRow, doctorTenure);
  
  doctorTable.addView(newRow);
 }
 
 private void addTextToRowWithValues(final TableRow tableRow, String text){
  TextView textView = new TextView(this);
  textView.setText(text);
  tableRow.addView(textView);
 }
 
 @Override
 public void onStop(){
  super.onStop();
 }
}


Here are pictures of the activities when executed

Assignment five

For this assignment we are going to create a little promotional app for a coffee shop. The assignment will cover using multiple activities and reading text and XML files.

The first activity will be an introduction, it might have a picture or a logo. How you design it is up to you. One thing it should have is two buttons, one that opens an activity that describes the coffee shop. This description should be in the form of a text file. This file should be stored in a folder under res called raw. You can use your imagination for the content of the file.

The other activity should contain a list of coffee products, sizes and products. These should be read from a file called coffee.xml stored in a folder under res called xml.
The XML file should have a structure like this:


<?xml version="1.0" encoding="utf-8"?>
<coffees>
<coffee
name="expresso"
size="2 ounces"
Price="1.50"/>


</coffees>



You can add as many drinks as you like, but should have at least five.

A sample resembling this will be posted soon.



Wednesday, May 9, 2012

Stored procedure Two: New Donor

--stored procedures

use CommunityAssist 

/*
Create a new a donor and donation
Check to see if person exists
Insert into Person
insert into PersonAddress
Insert into PersonContact
Insert into Donation
*/
go
--alter the existing procedure
--you can only create once
Alter proc usp_NewDonation
--define the user provided parameters
@firstname nvarchar(255),
@LastName nvarchar(255),
@Street nvarchar(255),
@Apartment nvarchar(255), 
@State nvarchar(2) = 'WA', 
@City nvarchar(255), 
@Zip nvarchar(10), 
@phone nvarchar(255),
@Email nvarchar(255),
@DonationAmount money,
@EmployeeKey int = null
AS
Begin tran --begin the transaction
--so it all happens or none of them
--declare personkey at procedure scope
Declare @personKey int 
Begin try
--test to see if donor exists
if Exists
 (Select Lastname, firstname, ContactInfo
  From Person p
 inner Join PersonContact pc
 on p.PersonKey=pc.PersonKey
 Where LastName=@LastName
 And FirstName=@firstname
 And ContactInfo =@Email
 And ContactTypeKey=6)
Begin --if they do exist get their key
Select @personKey=p.personkey 
        from Person p
       inner Join PersonContact pc
  on p.PersonKey=pc.PersonKey
  Where LastName=@LastName
  And FirstName=@firstname
  And ContactInfo =@Email
  And ContactTypeKey=6
End 
Else --otherwise insert a new person
Begin
Insert into Person(lastname, firstname)
Values (@LastName, @firstname)


Set @personKey=IDENT_CURRENT('Person')

Insert into PersonAddress(Street, Apartment, [State], City, Zip, PersonKey)
Values(@Street, @Apartment, @State, @City, @Zip, @personkey)

Insert into PersonContact(ContactInfo, PersonKey, ContactTypeKey)
Values(@phone, @personKey, 1);

Insert into PersonContact(ContactInfo, PersonKey, ContactTypeKey)
Values(@Email, @personKey, 6);
End
--in either case take their donation
Insert into Donation(DonationDate, DonationAmount, PersonKey, EmployeeKey)
Values(GETDATE(),@DonationAmount, @personKey, @EmployeeKey);

--if all goes well commit the transaction
Commit tran
End try
--otherwise rollback the transaction and handle the error
Begin Catch
Rollback Tran
print Error_Message()
End Catch
Go

exec usp_NewDonation
@firstname ='Mom',
@LastName='Bates',
@Street='1000 north south street',
@Apartment = null, 
@State ='WA', 
@City='Seattle', 
@Zip= '98122', 
@phone ='2065551234',
@Email='psycho2@msn.com',
@DonationAmount =100.00
--@EmployeeKey =45

Select * From Person
Select * from PersonAddress where PersonKey=63
Select * from Donation

Select * From Employee

Tuesday, May 8, 2012

SQL for Getting Registered Customer Information

For Your ASP/ADO assignment: After you log in your will want to return some customer information on the next web page. You have the customer's email saved in the Session variable. You can use it to get the Customer information. Here is a SQL string you can use:


SELECT LastName, FirstName, Email, VehicleID, VehicleMake, VehicleYear
FROM Person p
INNER JOIN Customer.Vehicle v
ON p.PersonKey=v.PersonKey
INNER JOIN Customer.RegisteredCustomer rc
ON p.PersonKey=rc.PersonKey
WHERE Email = @email

You will need to resolve the variable @email with the parameters in the command object. First get the value from the Session variable than use the addwithvalue method of the parameter


string email = Session["user"].ToString();
. . .

cmd.Parameters.AddWithValue("@email", email);

I also retrieved the VehicleID, because you can use it to get the vehicle service information

Monday, May 7, 2012

Object Relations

Here is an attempt to make better sense out of the in class lecture on objects and types.

Classes that talk to each other are said to have an Association.

Association just means that one class calls methods in the other one.

Composition represents a whole/part relationship. Further it represents a relationship in which the part is contained in the whole. If the whole is destroyed, so is the part. This is represented by a line with a filled in diamond at the end. The diamond is attached to the class which represents the whole. In the example below, Scan is a part of Scanner. It is created by the scanner and when the scanner is destroyed the Scan is also.

Inheritance represents a generalization, specialization relationship. The parent represents the more general case--in the example below, person. The children represent more specific cases: Employee, Visitor. Inheritance is important for code reuse. A child class inherits all the public properties and methods of the parent. That means they can add just those properties and methods that are specific to them. It is also possible to override parent methods, if necessary, and give them different behaviors.

In most modern languages a child can have only one parent. But it can inherit from as many interfaces as desired. An interface consists only of method signatures. Interfaces are sometimes referred to as contracts. A class that implements an interface must implement any of the methods in the interface. It is a way of guaranteeing that a given class will have the appropriate methods to talk to existing objects in the ways they expect. An interface is represented like inheritance. In the example below an Observer object implements an interface called IUpdate that contains the signature for an Update method.

The final type of object I will show here is an enumeration. An enumeration just assigns a friendly name to an numeric value to make it easer to refer to in code.

I will upload code examples of each of these relations in the near future

Thursday, May 3, 2012

Updating an Employee

This is the code to update an employee. First we added in the Login class so we could have the employee login. The we created an employee class to store the Data related to the employee. We created an EmployeeManager class to get and update employee objects. We also added some error trapping and an error page. First I will show the classes and then the forms and code behind

Here is the LoginClass.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
//the Ado and config libraries
using System.Data;
using System.Data.SqlClient;
using System.Configuration;

/// 
/// Summary description for LoginClass
/// this class handles the logins
/// it connects to the database and
/// checks whether the username and
/// password(social Security number)
/// match and then returns a boolean
/// true if successful, false if not
/// 
public class LoginClass
{
    //private fields
    private string user;
    private string pass;
 
    //constructor gets username and password
        public LoginClass(string username, string password)
        {
            user=username;
            pass=password;
        }

        public bool ValidateLogin()
        {
            bool valid = false;
            //Initalize connection object
            //connection string in web config
            SqlConnection connect = 
                new SqlConnection
                    (ConfigurationManager.
                    ConnectionStrings["CommunityAssistConnection"].
                    ToString());

            //sql string to check if user exists
            string Sql = "SELECT LastName, SSNumber "
                            + "FROM Person "
                            + "Inner Join Employee "
                            + "On Person.PersonKey=Employee.PersonKey "
                            + " Where Lastname=@user "
                            + "And SSNumber=@pass";

            SqlCommand cmd = new SqlCommand(Sql, connect);
            //command object adds parameters to handle the variables
            //in the Sql string
            cmd.Parameters.AddWithValue("@user", user);
            cmd.Parameters.AddWithValue("@pass", pass);

            //a dataset is an object that can store tables
            DataSet ds = new DataSet();

            SqlDataReader reader = null;
            try //this is where the code can fail
            {
                connect.Open(); //open the connection
                reader = cmd.ExecuteReader(); //execute the SQL
                //load the data into the datset
                ds.Load(reader, System.Data.LoadOption.OverwriteChanges, "Validate");
                reader.Dispose(); //get rid of the reader
            }
            catch (Exception ex)
            {
                //if there are any errors throw it
                //back to the calling method
                throw ex;
            }
            finally
            {
                //no matter what close the connection
                connect.Close();
            }

            foreach (DataRow row in ds.Tables["Validate"].Rows)
            {
                //get the values from the dataset
                if (row["LastName"].ToString().Equals(user) 
                    && row["SSNumber"].ToString().Equals(pass))
                {
                    valid = true;
                    
                }
            }



            return valid;
        }
}


Employee.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// 
/// Summary description for Employee
/// this class is just a way to hold
/// all of the employee values in one
/// place. It consists of nothing but
/// fields and properties
/// 
public class Employee
{
    string sSNumber;

    public string SSNumber
    {
        get { return sSNumber; }
       
    }

    string lastName;

    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
    string firstName;

    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }
    int dependents;

    public int Dependents
    {
        get { return dependents; }
        set { dependents = value; }
    }

    private int personKey;

    public int PersonKey
    {
        get { return personKey; }
        set { personKey = value; }
    }

 public Employee(string ssn)
 {
        sSNumber = ssn;
 }
}

ManageEmployee.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;

/// 
/// Summary description for ManageEmployee
/// this class handles the employee class
/// in the method getEmployee it creates an 
/// employee object from the data in the database
/// In the UpdateEmployee method it takes 
/// an employee object as a parameter and 
/// updates the database with any changes
/// 
public class ManageEmployee
{
    private Employee emp;
    private SqlConnection connect;

 public ManageEmployee()
 {
        connect = 
            new SqlConnection
             (ConfigurationManager.ConnectionStrings["CommunityAssistConnection"].ToString());
       
 }

    public Employee GetEmployee(string ssn)
    {
        string sql = "Select LastName, FirstName, Dependents, e.PersonKey "
                        + " From Person p "
                        + "Inner Join Employee e "
                        + "On p.PersonKey=e.PersonKey "
                        + "where SSNumber=@ssn";

        SqlCommand cmd = new SqlCommand(sql, connect);
        cmd.Parameters.AddWithValue("@ssn", ssn);
        SqlDataReader reader = null;
        //the datatable is another object that can sore data
        //it is a lighter object than the dataset
        DataTable table = new DataTable();
        //there should be a try catch around this
        connect.Open();
        reader = cmd.ExecuteReader();
        table.Load(reader);
        reader.Close();
        connect.Close();

        emp = new Employee(ssn);

        //this loop writes the data from the table
        //to a new employee object
        foreach (DataRow row in table.Rows)
        {
            int dependents = 0;
            emp.LastName = row["LastName"].ToString();
            emp.FirstName = row["FirstName"].ToString();

            bool isInt = int.TryParse(row["Dependents"].ToString(), out dependents);
            emp.Dependents = dependents;
            emp.PersonKey = int.Parse(row["PersonKey"].ToString());
        }

        return emp;
    } //end get employee

    public bool UpdateEmployee(Employee employee)
    {
        bool success = false;

        //must update two tables
        string sql = "Update Person "
                             + " Set FirstName=@first, "
                             + " LastName=@last"
                             + " Where personKey=@PersonKey";

        string sql2 = "Update Employee "
                        + " Set Dependents = @depends "
                        + " Where SSNumber=@ssn";

        //a command for each of the sql strings
        SqlCommand cmd = new SqlCommand(sql, connect);
        cmd.Parameters.AddWithValue("@last", employee.LastName);
        cmd.Parameters.AddWithValue("@first", employee.FirstName);
        cmd.Parameters.AddWithValue("@PersonKey", employee.PersonKey);

        
        SqlCommand cmd2 = new SqlCommand(sql2, connect);
        cmd2.Parameters.AddWithValue("@depends", employee.Dependents);
        cmd2.Parameters.AddWithValue("@ssn", employee.SSNumber);

        //this also should have a try catch
        connect.Open();
        cmd.ExecuteNonQuery();
        cmd2.ExecuteNonQuery();
        connect.Close();

        success = true;
        return success;
    }


}//end class

The connection string is in the webconfig.xml file

<?xml version="1.0"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
 <connectionStrings>
  <add name="CommunityAssistConnection" 
connectionString="Data Source=localhost;initial catalog=CommunityAssist;integrated Security=true"/>
 </connectionStrings>
 <system.web>
  <compilation debug="true" targetFramework="4.0"/>
 </system.web>
</configuration>


Here is the Default.aspx source

<%@ Page Language="C#" AutoEventWireup="true" 
CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    
    <form id="form1" runat="server">
    <div>
    <asp:Login ID="Login1" runat="server" 
onauthenticate="Login1_Authenticate">
    </asp:Login>
    </div>
    </form>
</body>
</html>

Here is the code behind Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
    {
        //instantiate the login class 
        //and pass it the user and password
        LoginClass lc = new LoginClass(Login1.UserName, Login1.Password);

        bool isGood = false;
        try
        {
            //call the validatelogin method
            //it returns true or false
            isGood = lc.ValidateLogin();
        }
        catch (Exception ex)
        {
            //if there is an error write it to a session variable
            //and redirect to the error page
            Session["err"] = ex;
            Response.Redirect("Error.aspx");
        }

        if (isGood)
        {
            //if it is good set authenticated to true
            e.Authenticated = true;
            //write the ss number to a session variable
            Session["ss"] = Login1.Password;
            //redirect to the view edit page
            Response.Redirect("Default2.aspx");
        }
    }
}

Here is Default2.aspx

<%@ Page Language="C#" AutoEventWireup="true" 
CodeFile="Default2.aspx.cs" Inherits="Default2" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Label ID="Label1" runat="server" Text="First Name"></asp:Label>
        <asp:TextBox ID="txtFirstName"
            runat="server"></asp:TextBox><br />
            <asp:Label ID="Label2" runat="server" Text="Last Name"></asp:Label>
        <asp:TextBox ID="txtLastName"
            runat="server"></asp:TextBox><br />
            <asp:Label ID="Label3" runat="server" Text="Dependents"></asp:Label>
        <asp:TextBox ID="txtDependents"
            runat="server"></asp:TextBox><br />
        <asp:Button ID="Button1" runat="server" Text="Edit" onclick="Button1_Click" />
        <asp:Label ID="lblResult" runat="server" Text="Label"></asp:Label>
    </div>
    </form>
</body>
</html>


Here is the code behind Default2.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Default2 : System.Web.UI.Page
{
    Employee employee;
    int personKey;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            if (Session["ss"] != null)
            {
                //create a new employee and write the values
                //to the text boxes
                ManageEmployee me = new ManageEmployee();
                employee = me.GetEmployee(Session["ss"].ToString());
                txtFirstName.Text = employee.FirstName;
                txtLastName.Text = employee.LastName;
                txtDependents.Text = employee.Dependents.ToString();
                personKey = employee.PersonKey;
                //write the personkey to a session variable
                Session["personkey"] = personKey;
            }
        }
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        //get the personkey from the session variable
        int PK = (int)Session["personkey"];
        //create new employee and assign the values from the form
        Employee employee = new Employee(Session["ss"].ToString());
        employee.LastName = txtLastName.Text;
        employee.FirstName = txtFirstName.Text;
        employee.Dependents = int.Parse(txtDependents.Text);
        employee.PersonKey = PK; //assign PK from session variable

        ManageEmployee me = new ManageEmployee();
        //call the UpdateEmployee method
        bool result=me.UpdateEmployee(employee);
        if (result)
            lblResult.Text = "Your changes were successful";
    }
}

Finally, here is the source for Error.aspx

<%@ Page Language="C#" AutoEventWireup="true" 
CodeFile="Error.aspx.cs" Inherits="Error" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
    </div>
    </form>
</body>
</html>


Error.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Error : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Session["err"] != null)
        {
            Exception ex = (Exception)Session["err"];
            Label1.Text = ex.Message;
        }

    }
}

That was a lot of code!

Wednesday, May 2, 2012

Functions, Stored Procedures

--functions 

use CommunityAssist
-- some system views

select * from sys.indexes

select * from sys.tables

--returns info on the table donation
sp_Help 'Donation'


Go
--create a simple function

Create function fn_Cube
(@number int) --user provided parameter
returns int --return type
As 
Begin --begin function body
--must return an integers
return @number * @number * @number
End --end of function body

--use the function. It must be used with the schema
--owner, in this case dbo (data base owner)
Select Dependents, dbo.fn_Cube(Dependents) cubed
From Employee where Dependents is not null

Go
--for this function we will use an arbitrary rule
--every thing up to a 1000 100% deductable
--after 1000 80%
create function fn_TaxDeduction
(@PersonKey int)
returns money
as
Begin 
declare @total money --declare an internal variable
declare @deductible money
--assign a value to the variable with
--a select statement
Select @total = SUM(DonationAmount) 
 From Donation
 Where PersonKey=@personKey
--test the value with an if statement
if @total >1000
Begin --start of if true
 set @deductible=@total * .8
End --end of if block 
Else
Begin --else block
 set @deductible=@Total
End --else block
 Return @Deductible --return the results
End

--use the function
Select personkey, sum(donationAmount) as total, 
dbo.fn_TaxDeduction(personKey) Deductible
From donation
Where dbo.fn_TaxDeduction(personKey) is not null
Group by personkey, dbo.fn_TaxDeduction(personKey)
order by Deductible desc

Go
--this is a mess but shows a parameterized view
--it does point out some of the dangers of 
--inner joins
alter proc usp_DonorInfo
@personKey int
As
Select Distinct lastName, Firstname,
Street, City, [State], ContactInfo, Donationkey,DonationAmount
From Person p
inner join PersonAddress pa
on p.PersonKey=pa.PersonKey
inner join PersonContact pc
on p.personkey=pc.PersonKey
inner join donation d
on p.Personkey=d.personkey
where p.personkey=@PersonKey


--execute the stored procedure
--you must provide a value for the parameter
exec usp_donorInfo 3

Select * From donation
--another stored procedure
--a parameterized view
Create proc usp_DonationSummary
@Year int
As
Select YEAR(donationDate) [Year],
MONTH(donationDate) [Month],
SUM(donationAmount) total
From Donation
Where Year(donationDate)=@Year
Group by Year(donationDate), 
Month(DonationDate)

Select distinct YEAR(DonationDate) from Donation

--another way to assign the parameter
exec usp_DonationSummary 
@Year=2010

Tuesday, May 1, 2012

First Class Diagrams

Types of Classes Domain – classes for the basic business model Display—presentation UI Entity Classes – handle the data (files, database access) Control classes Utility classes Border Classes Relations among classes Inheritance--generalization specialization Association—talk to each other Composition—part to whole (where if you destroy the whole you destroy the part) Aggregation—whole part where the part has its own existence Here is the class diagram

Below is the code for the inheritance example Person class

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

namespace InheritanceExample
{
    class Person
    {
        private string name;

        public Person(string name)
        {
            Name = name;
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        private int number;

        public int Number
        {
            get { return number; }
            set { number = value; }
        }

        public override string ToString()
        {
            return Number.ToString() + ", " + Name;
        }
    }
}


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

namespace InheritanceExample
{
    class Employee : Person
    {

        
        public Employee(string name): base(name) 
        {
            
        }
        private DateTime hiredate;

        public DateTime Hiredate
        {
            get { return hiredate; }
            set { hiredate = value; }
        }
        private string phoneNumber;

        public string PhoneNumber
        {
            get { return phoneNumber; }
            set { phoneNumber = value; }
        }

        public override string ToString()
        {
            string name= base.ToString();
            return name + ", " + PhoneNumber + ", " + Hiredate;
        }

    }
}


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

namespace InheritanceExample
{
    class Salaried : Employee
    {
        double salary;

        public double Salary
        {
            get { return salary; }
            set { salary = value; }
        }

        public override string ToString()
        {
            string emp= base.ToString();
            return emp + "," + Salary.ToString();
        }
    }
}