Lập trình Web – Bài tập / Đề thi – Quản lý thư viện

Lập trình Web – Bài tập / Đề thi – Quản lý thư viện

ASP.NET MVC4 & ADO.NET & KnockoutJs

Bài viết này của tôi nằm trong series ‘các bài tập tham khảo’. Series này chia sẻ một số cách tiếp cận, hiện thực mức căn bản nhất, tóm tắt nhất các bài tập, bài tập lớn ngành Khoa học máy tính, trường ĐH Mở Tp.HCM.

Lập trình web – một môn học chuyên sâu hướng mạng máy tính, nhưng lại được nhiều sự quan tâm của hướng ngành khác. Và điển hình là tôi đã và đang theo hướng cơ sở dữ liệu, đã đăng ký môn này dưới hình thức là môn tự chọn. Môn học này cung cấp kiến thức và kỹ năng phát triển ứng dụng web. Hiện thực trên 2 công nghệ phổ biến hiện nay là ASP.NET Web form và PHP.

Tôi hy vọng bài viết này sẽ hữu ích với các bạn sinh viên IT đang quan tâm đến web.

1.     Giới thiệu

Bài viết này tôi xin trình bày thực hiện một bài tập lập trình web đơn giản. Thực ra thì đây cũng là đề thi thực hành môn lập trình web năm 2010.

a.      Yêu cầu:

Xin tóm tắt đề như sau:

Cho csdl: ThuVien.mdb

clip_image002[6]

Xây dựng ứng dụng ASP.NET với yêu cầu sau:

  Trang chủ quản lý thư viện:

clip_image004[6]

 Xem danh sách độc giả: hiển thị thông tin độc giả

clip_image006[6]

  Cập nhật thông tin độc giả: sau khi chọn độc giả, form dưới sẽ hiển thị và cho chỉnh sửa thông tin độc giả. Đồng ý sẽ lưu lại, hủy bỏ sẽ xóa trắng form.

clip_image008[6]

 

b.      Các kiến thức sử dụng:

ASP.NET MVC4: C#, Razer View Engine

ADO.NET

KnockoutJs, jQuery

 

2.     Thiết kế chương trình

Tóm lại, đề bài yêu cầu thực hiện thao tác đọc, hiển thị và cập nhật dữ liệu.

Hoạt động, dữ liệu đã có sẵn, nên sau đây sẽ là kiến trúc:

clip_image009[6] 

 

Vậy chương trình theo kiến trúc MVC và sẽ có Rich-client.

 

3.     Lập trình

Việc đầu tiên là chép cơ sở dữ liệu vào project.

a.      Model

Tôi sẽ thực hiện đủ theo yêu cầu đề bài nên tôi cũng sẽ chỉ tạo ra model vừa đủ dùng. Vì vậy sẽ không cần quan tâm đến bảng MuonSach.

DiaChi và DocGia quan hệ 1-1 nên tôi sẽ chọn model:

    public class Author
    {
        public short authorId { get; set; }
        public string firstName { get; set; }
        public string lastName { get; set; }
        public DateTime birthDate { get; set; }

        public string addressNumber { get; set; }
        public string streetName { get; set; }
        public string district { get; set; }
        public string phoneNumber { get; set; }
    }

 

b.      Data Access

Làm nhiệm vụ thao tác với Database, cung cấp khả năng CRUD lên model cho controller. Để phục vụ cho 2 trang nghiệp vụ theo đề bài thì ở đây tôi chỉ thực hiện 2 hàm Read và Update:

        public List<Author> GetListOfAuthors() 
        {
            OleDbConnection dataConnection = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + _databasePath + ";Persist Security Info=True");
            OleDbDataAdapter dataAdapter = new OleDbDataAdapter("select Ma, HoLot, Ten, NgaySinh, SoNha, Duong, Quan, DienThoai from DocGia, DiaChi where Ma = MaDG", dataConnection);
            DataTable dataTable = new DataTable();
            dataAdapter.Fill(dataTable);
            return dataTable.AsEnumerable().Select(row =>
                new Author
                {
                    authorId = row.Field<short>("Ma"),
                    firstName = row.Field<string>("HoLot"),
                    lastName = row.Field<string>("Ten"),
                    birthDate = row.Field<DateTime>("NgaySinh"),
                    addressNumber = row.Field<string>("SoNha"),
                    streetName = row.Field<string>("Duong"),
                    district = row.Field<string>("Quan"),
                    phoneNumber = row.Field<string>("DienThoai")
                }).ToList();
        }

        public void UpdateAuthor(Author author)
        {
            OleDbConnection dataConnection = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + _databasePath + ";Persist Security Info=True");
            OleDbCommand commandToUpdateAuthor = new OleDbCommand(@"update DocGia set HoLot=?, Ten=?, Ngaysinh=? where Ma=? ", dataConnection);

            //các tham số của command trong oledb phải giữ đúng thứ tự như trong command đã khai báo. khác với sqlcommand 
            commandToUpdateAuthor.Parameters.AddWithValue("@firstName", author.firstName);
            commandToUpdateAuthor.Parameters.AddWithValue("@lastName", author.lastName);
            commandToUpdateAuthor.Parameters.AddWithValue("@birthDate", author.birthDate);
            commandToUpdateAuthor.Parameters.AddWithValue("@authorId", author.authorId);

            OleDbCommand commandToUpdateAddress = new OleDbCommand(@"update DiaChi set SoNha=?, Duong=?, Quan=?, DienThoai=? where MaDG=? ", dataConnection);

            //các tham số của command trong oledb không có định danh rõ ràng nên cần giữ đúng thứ tự như trong command đã khai báo. khác với sqlcommand 
            commandToUpdateAddress.Parameters.AddWithValue("@addressNumber", author.addressNumber);
            commandToUpdateAddress.Parameters.AddWithValue("@streetName", author.streetName);
            commandToUpdateAddress.Parameters.AddWithValue("@district", author.district);
            commandToUpdateAddress.Parameters.AddWithValue("@phoneNumber", author.phoneNumber);
            commandToUpdateAddress.Parameters.AddWithValue("@authorId", author.authorId);

            using (dataConnection)
            {
                dataConnection.Open();
                commandToUpdateAuthor.ExecuteNonQuery();
                commandToUpdateAddress.ExecuteNonQuery();
            }
}

 

Thông thường, ở lớp này chỉ cần sử dụng Entity Framework. Nhưng hiện tại, Entity Framework chỉ hỗ trợ chính thức cho cơ sở dữ liệu SQL Server. N-Hibernate đã có hỗ trợ nhưng lại khá cồng kềnh. Vì vậy, sử dụng ADO.NET để kết nối và truy xuất csdl Access cũng không hẳn ý kiến tồi.

 

c.       Controller

Theo nhu cầu đề bài sẽ cần ít nhất 3 action cho 3 trang. Để tiện quản lý, tôi phân nhóm như sau:

HomeController: sẽ chứa action gọi đến trang chủ

BusinessController: sẽ chứa các action đến 2 trang nghiệp vụ

Với mục đích là xây dựng rich-client,  tôi tạo thêm 1 DataServiceController làm nhiệm vụ cung cấp cho client các API thao tác lên dữ liệu. Nó sẽ gọi đến các hàm của lớp Data Access và chuyển những đối tượng thành JSON. Cũng vì toàn bộ các phương thức thao tác với dữ liệu thông qua DataServiceController nên Các Action trang chủ, nghiệp vụ chỉ làm một nhiệm vụ duy nhất là trả về View

 

d.      View

Tôi sẽ tập trung vào 2 trang nghiệp vụ. Cấu trúc như sau:

clip_image010[6]

  Knockout Model:

2 trang không khác biệt quá về nghiệp vụ nên có thể sử dụng cùng Model

  AuthorModel.js

var AuthorModel = function (author) {
    var self = this;
    if (!author) {
        self.authorId = ko.observable("");
        self.firstName = ko.observable("");
        self.lastName = ko.observable("");
        self.addressNumber = ko.observable("");
        self.streetName = ko.observable("");
        self.district = ko.observable("");
        self.phoneNumber = ko.observable("");
        self.birthDate = ko.observable("");
    }
    else {
        self.authorId = ko.observable(author.authorId);
        self.firstName = ko.observable(author.firstName);
        self.lastName = ko.observable(author.lastName);
        self.addressNumber = ko.observable(author.addressNumber);
        self.streetName = ko.observable(author.streetName);
        self.district = ko.observable(author.district);
        self.phoneNumber = ko.observable(author.phoneNumber);

        //cần chuyển định dạng json date sang chuỗi dd/mm/yyyy
        var birthDateObj = new Date(parseInt(author.birthDate.substr(6)));
        var curr_date = birthDateObj.getDate();
        var curr_month = birthDateObj.getMonth() + 1; //getMonth() == 0 tức là tháng 1
        var curr_year = birthDateObj.getFullYear();
        self.birthDate = ko.observable(curr_date + "/" + curr_month + "/" + curr_year);
    }

    self.fullName = ko.computed(function () {
        return self.firstName() + " " + self.lastName();
    });

    //lấy dữ liệu
    self.getData = function () {
        return {
            authorId: self.authorId(),
            firstName: self.firstName(),
            lastName: self.lastName(),
            birthDate: self.birthDate(),
            addressNumber: self.addressNumber(),
            streetName: self.streetName(),
            district: self.district(),
            phoneNumber: self.phoneNumber()
        };
    };

    //sao chép
    self.copyFrom = function (authorModel) {
        self.authorId(authorModel.authorId());
        self.firstName(authorModel.firstName());
        self.lastName(authorModel.lastName());
        self.birthDate(authorModel.birthDate());
        self.addressNumber(authorModel.addressNumber());
        self.streetName(authorModel.streetName());
        self.district(authorModel.district());
        self.phoneNumber(authorModel.phoneNumber());
    };
};

  Knockout ViewModel:

  ViewAuthorsViewModel.js

var AuthorsViewModel = function () {
    var self = this;
    self.listOfAuthors = ko.observableArray([]);

    self.initData = function () {
        $.getJSON("/DataService/GetJsonListOfAuthors", function (data) {

            //thêm dữ liệu vào danh sách độc giả
            $.each(data, function (key, value) {
                self.listOfAuthors.push(new AuthorModel(value));
            });

            //sắp xếp độc giả trong danh sách theo chiều tăng dần của mã độc giả
            self.listOfAuthors.sort(function (left, right) {
                if (left.authorId() == right.authorId())
                    return 0;
                else if (left.authorId() < right.authorId())
                    return -1;
                else
                    return 1;
            });
        });
    };
}

  EditAuthorViewModel.js

var EditAuthorViewModel = function () {
    var self = this;
    self.listOfAuthors = ko.observableArray([]);

    self.initData = function () {
        $.getJSON("/DataService/GetJsonListOfAuthors", function (data) {

            //thêm dữ liệu vào danh sách độc giả
            $.each(data, function (key, value) {
                self.listOfAuthors.push(new AuthorModel(value));
            });
        });
    };

    self.selectingAuthor = ko.observable();

    self.editingAuthor = ko.observable(new AuthorModel());

    //chọn độc giả để chỉnh sửa
    self.editAuthor = function () {
        self.editingAuthor().copyFrom(self.selectingAuthor());
    };

    //cập nhật độc giả
    self.updateData = function() {
        $.post("/DataService/UpdateAuthor",
            self.editingAuthor().getData(),
            function (data) {
                if (data.completed == true) {
                    //sau khi thêm thành công trên server, cập nhật toàn bộ các biến không được tham chiếu
                    var length = self.listOfAuthors().length;
                    for (var i = 0; i < length; i++)
                    {
                        if (self.listOfAuthors()[i].authorId() == self.editingAuthor().authorId()) {
                            self.listOfAuthors()[i].copyFrom(self.editingAuthor());
                            break;
                        }
                    }
                } else {
                    alert(data.message);
                }
            }
        );
    };

    //xóa trạng thái chọn
    self.clearEditData = function () {
        self.editingAuthor(new AuthorModel());
    };
}

  Knockout View:

  ViewAuthors.cshtml

<h2>Xem danh sách độc giả</h2>
<hr />
<a href="/Home/Index">&lt;&lt; Trở về trang chủ</a>
<table class="business-viewAuthors-dataTable">
    <thead>
        <tr>
            <th>Mã</th>
            <th>Họ lót</th>
            <th>Tên</th>
            <th>Số Nhà</th>
            <th>Đường</th>
            <th>Quận</th>
            <th>Điện thoại</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: listOfAuthors">
        <!-- ko if: $index() < 10 -->
        <tr>
            <td data-bind="text: authorId"></td>
            <td data-bind="text: firstName"></td>
            <td data-bind="text: lastName"></td>
            <td data-bind="text: addressNumber"></td>
            <td data-bind="text: streetName"></td>
            <td data-bind="text: district"></td>
            <td data-bind="text: phoneNumber"></td>
        </tr>
        <!-- /ko -->
    </tbody>
</table>

  EditAuthor.cshtml

<span class="business-editAuthor-title">Danh sách độc giả</span>
<select class="business-editAuthor-dropdown"  data-bind="options: listOfAuthors,
                    optionsText: function(author){
                        return author.fullName;
                    },
                    value: selectingAuthor,
                    optionsCaption: 'Chọn...'"></select>
<input type="button" value="Chọn" data-bind="click: editAuthor" />

<table class="business-editAuthor-form">
    <tr>
        <td><span>Mã ĐG:</span></td>
        <td>
            <input type="text" style="color: gray;" disabled="disabled" data-bind="value: editingAuthor().authorId()"/></td>
    </tr>
    <tr>
        <td><span>Họ Lót:</span></td>
        <td>
            <input type="text" data-bind="value: editingAuthor().firstName"/></td>
    </tr>
    <tr>
        <td><span>Tên:</span></td>
        <td>
            <input type="text" data-bind="value: editingAuthor().lastName"/></td>
    </tr>
    <tr>
        <td><span>Ngày Sinh:</span></td>
        <td>
            <input type="text" data-bind="value: editingAuthor().birthDate"/></td>
    </tr>
    <tr>
        <td><span>Số Nhà:</span></td>
        <td>
            <input type="text" data-bind="value: editingAuthor().addressNumber"/></td>
    </tr>
    <tr>
        <td><span>Đường:</span></td>
        <td>
            <input type="text" data-bind="value: editingAuthor().streetName"/></td>
    </tr>
    <tr>
        <td><span>Quận:</span></td>
        <td>
            <input type="text" data-bind="value: editingAuthor().district"/></td>
    </tr>
    <tr>
        <td><span>Điện thoại:</span></td>
        <td>
            <input type="text" data-bind="value: editingAuthor().phoneNumber"/></td>
    </tr>
</table>
<input type="button" value="Đồng Ý" data-bind="click: updateData"/>
<input type="button" value="Hủy Bỏ" data-bind="click: clearEditData" />

<a href="/Home/Index">&lt;&lt; Trở về trang chủ</a>

  Code behind:

  ViewAuthors.js

$(function () {
    $(document).ready(function () {
        
        var viewAuthorsViewModel = new ViewAuthorsViewModel();
        viewAuthorsViewModel.initData();
        ko.applyBindings(viewAuthorsViewModel);
    });
});

  EditAuthor.js

 

$(function () {
    $(document).ready(function () {
        
        var editAuthorViewModel = new EditAuthorViewModel();
        editAuthorViewModel.initData();
        ko.applyBindings(editAuthorViewModel);
    });
});

 

4.     CSS cho đẹp nữa là hoàn tất 😛

5.     Tài nguyên

Link download CSDL thuvien.mdb: http://www.mediafire.com/?6623sij71cjd1cv

 

Bài viết đến đây là hết. Cám ơn các bạn đã quan tâm. Rất vui nhận được góp ý của các bạn

2 responses to “Lập trình Web – Bài tập / Đề thi – Quản lý thư viện

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Google photo

Bạn đang bình luận bằng tài khoản Google Đăng xuất /  Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s