1. Donald Woodhouse's Portfolio
of work in the SetFocus LLC
.NET Master's Program
Donald Woodhouse
507 S Clayton St., Unit 2B
Wilmington, DE 19805
(302)691-8285
d.woodhouse10@comcast.net
2. At SetFocus, we each individually wrote an entire application to interact with a
Library database which was given to us. We wrote first the Windows interface (with
school generated database interaction in hidden DLL's). Then we wrote all the database
interaction in SQL stored procedures and ADO.NET code. Then we replaced in its
entirety the Windows interface with an ASP.NET website interface.
Here is my Windows interface. Choosing Display Member from the Member
Services menu gives the following screen, on which member 4004 has been chosen and
View Member has been pressed. This is a juvenile member, with the associated adult
4003 shown as Adult Member Id. He has four items checked out, as shown. The birth
date and adult member id are retrieved from the juvenile record. The address
information comes indirectly from the associated adult member, but this is invisible
from this level of code. The SQL stored procedure associates the information.
3. The code for the View Member Button follows. bl stands for Business Layer and
is the entity which intermediates to connect to the data access code in the Data Access
tier.
private void viewMemberButton_Click(object sender, EventArgs e)
{
try
{
if (Int16.TryParse(memberIdTextBox.Text, out memberId))
{
myMember = bl.GetInformation(memberId);
if (myMember == null)
{
MessageBox.Show("Not a member");
firstNameLabel.Text = "First Name";
middleInitialLabel.Text = "Middle Initial";
lastNameLabel.Text = "Last Name";
streetLabel.Text = "Street";
cityLabel.Text = "City";
stateLabel.Text = "State";
zipCodeLabel.Text = "Zip Code";
phoneNumberLabel.Text = "Phone Number";
expirationDateLabel.Text = "Expiration Date";
}
else
{
firstNameLabel.Text = "First Name " + myMember.FirstName;
middleInitialLabel.Text = "Middle Initial " + myMember.MiddleInitial;
lastNameLabel.Text = "Last Name " + myMember.LastName;
streetLabel.Text = "Street " + myMember.Street;
cityLabel.Text = "City " + myMember.City;
stateLabel.Text = "State " + myMember.State;
zipCodeLabel.Text = "Zip Code " + myMember.ZipCode;
phoneNumberLabel.Text = "Phone Number " + myMember.PhoneNumber;
expirationDateLabel.Text = "Expiration Date " + myMember.ExpirationDate.ToShortDateString();
if (myMember is DW.LibraryEntities.JuvenileMember)
{
DW.LibraryEntities.JuvenileMember jm = (DW.LibraryEntities.JuvenileMember)myMember;
adultMemberIDLabel.Text = "Adult Member Id " + jm.AdultMemberID;
birthDateLabel.Text = "Birth Date " + jm.BirthDate.ToShortDateString();
}
else
{
adultMemberIDLabel.Text = "";
birthDateLabel.Text = "";
}
if (myMember.ExpirationDate < DateTime.Today)
{
expiredLabel.Visible = true;
this.statusLabel.Text = "Membership is expired - member cannot check out books";
this.checkOutButton.Enabled = false;
}
else
{
4. expiredLabel.Visible = false;
}
DW.LibraryEntities.ItemsDataSet.ItemsDataTable items = bl.GetItems(memberId);
itemsBindingSource.DataSource = items;
if (items.Count > 3)
{
this.statusLabel.Text = "Member has reached the maximum # of books checked out";
this.checkOutButton.Enabled = false;
}
else
{
this.statusLabel.Text = "";
this.checkOutButton.Enabled = true;
}
}
}
else
{
MessageBox.Show("Invalid Member ID");
firstNameLabel.Text = "First Name";
middleInitialLabel.Text = "Middle Initial";
lastNameLabel.Text = "Last Name";
streetLabel.Text = "Street";
cityLabel.Text = "City";
stateLabel.Text = "State";
zipCodeLabel.Text = "Zip Code";
phoneNumberLabel.Text = "Phone Number";
expirationDateLabel.Text = "Expiration Date";
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
Since the member was tested to be a juvenile member, the adult member id and birth
date were retrieved.
5. The add member services, Add Adult and Add Juvenile, are also on the Member
Services menu. Add Adult gives the following screen on which I have added myself as a
member. The OK button is grayed as it has already been clicked and the record added to
the database.
Sample validation code follows, using regular expression:
private void lastNameTextBox_Validating(object sender, CancelEventArgs e)
{
//Regex regex = new Regex("^[A-Z][a-z, A-Z]*$");
//if (!(regex.IsMatch(lastNameTextBox.Text) && lastNameTextBox.Text.Length <= 15))
if (!(Regex.IsMatch(lastNameTextBox.Text, "^[A-Z][a-z]{0,14}$")
&& lastNameTextBox.Text.Length <= 15))
{
e.Cancel = true;
errorProvider1.SetError(lastNameTextBox, "Must be 1-15 letters, first letter capital");
}
else errorProvider1.SetError(lastNameTextBox, null);
}
The code for the OK button is this:
private void okButton_Click(object sender, EventArgs e)
{
foreach (Control c in this.Controls)
{
if (c is TextBox)
9. This is my SQL stored procedure which is used (GetMember). In all, I wrote 11
stored procedures for this project.
/****** Object: StoredProcedure [dbo].[GetMember] Script Date: 10/15/2008 00:15:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[GetMember]
@member_no smallint = Null,
@adult_or_juvenile int OUTPUT
AS
IF @member_no IS NULL --No null member-no may be passed
BEGIN
RAISERROR('The member number may not be null.', 12, 1)
RETURN
END
--If member is adult
IF EXISTS (SELECT * FROM dbo.adult WHERE member_no = @member_no)
BEGIN
SELECT lastname, firstname, middleinitial, street,
city, state, zip, phone_no, expr_date,
adult_member_no = dbo.adult.member_no, birth_date = GETDATE()
FROM dbo.member INNER JOIN dbo.adult
ON dbo.member.member_no = dbo.adult.member_no
WHERE dbo.adult.member_no = @member_no
SET @adult_or_juvenile = 0 --Identifies adult member
END
--If member is juvenile
IF EXISTS (SELECT * FROM dbo.juvenile WHERE member_no = @member_no)
BEGIN
SELECT lastname, firstname, middleinitial, street,
city, state, zip, phone_no, expr_date,
adult_member_no, birth_date
FROM dbo.member INNER JOIN dbo.juvenile
ON dbo.member.member_no = dbo.juvenile.member_no
INNER JOIN dbo.adult
ON dbo.adult.member_no = dbo.juvenile.adult_member_no
WHERE dbo.juvenile.member_no = @member_no
SET @adult_or_juvenile = 1 --Identifies juvenile member
END
GO
10. In the website version, first you are presented with a login screen. You must be a
member of the Librarian role to successfully log in to do work.
11. The View Member screen looks like this with member 4004 again selected:
Overdue items (only) are highlighted in red.
12. Check Out Item produces the following page. This is the display after the item
has been checked out and Find is clicked again. It shows the item found checked out to
the member. Best practice is to enter the ISBN and copy number and click Find to see if
an item is checked out before trying to check it out to a member.
13. View Member will now produce this screen for Member 10001 (item not overdue
and thus not in red):
An additional feature we added in this stage of the project was the Add Item feature,
which adds a new copy of a given ISBN, first checking to see if it is a copy of the
existing item, or an entirely new ISBN. For this the SQL proc follows:
/****** Object: StoredProcedure [dbo].[AddNewItem] Script Date: 10/15/2008 00:15:48 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[AddNewItem]
@isbn int,
@title varchar(63),
@author varchar(31)
AS
DECLARE @title_no int
14. IF EXISTS (SELECT * from dbo.copy WHERE isbn = @isbn)
BEGIN
RAISERROR('There is at least one copy of this isbn number in collection', 12, 1)
RETURN
END
BEGIN TRAN
INSERT INTO dbo.title (title, author)
VALUES (@title, @author)
SET @title_no = SCOPE_IDENTITY()
IF @@ERROR <> 0
BEGIN
RAISERROR('Failed to create title table entry', 12, 1)
ROLLBACK TRAN
RETURN
END
INSERT INTO dbo.item (isbn, title_no)
VALUES (@isbn, @title_no)
IF @@ERROR <> 0
BEGIN
RAISERROR('Failed to create item table entry', 12, 1)
ROLLBACK TRAN
RETURN
END
INSERT INTO dbo.copy (isbn, copy_no, title_no, on_loan)
VALUES(@isbn, 1, @title_no, 'N')
IF @@ERROR <> 0
BEGIN
RAISERROR('Failed to create copy table entry', 12, 1)
ROLLBACK TRAN
RETURN
END
COMMIT TRAN
GO
Multiple database tables need to be updated for this, as entries in the title table, item
table, and copy table need to be updated.