最近完成了一个基于.NET平台的WPF图书管理系统开发项目,这个系统采用了标准的C#三层架构,使用SQL Server作为后端数据库。作为一名有多年开发经验的程序员,我想通过这篇文章详细分享整个项目的技术实现细节和开发心得。
这个图书管理系统主要实现了图书信息的增删改查、用户管理、借阅记录等核心功能。系统界面采用WPF技术构建,后端使用SQL Server 2012数据库存储数据。整个项目从设计到实现大约花费了两周时间,代码量约5000行,包含了完整的业务逻辑和异常处理。
项目使用Visual Studio 2019作为主要开发环境,这是经过多方面考虑后的决定:
提示:虽然VS2022已经发布,但考虑到项目规模和团队熟悉度,最终选择了更稳定的VS2019。
SQL Server 2012被选作数据库管理系统,主要基于以下考虑:
性能与可靠性:
开发便利性:
sql复制-- 示例:创建图书表
CREATE TABLE Books (
BookId INT PRIMARY KEY IDENTITY(1,1),
Title NVARCHAR(100) NOT NULL,
Author NVARCHAR(50) NOT NULL,
ISBN NVARCHAR(20) UNIQUE,
PublishDate DATE,
Price DECIMAL(10,2),
StockQuantity INT DEFAULT 0
);
系统严格遵循经典的三层架构设计:
表示层(Presentation Layer):
业务逻辑层(Business Logic Layer):
数据访问层(Data Access Layer):
csharp复制// 数据访问层示例
public class BookRepository : IBookRepository
{
private readonly string _connectionString;
public BookRepository(string connectionString)
{
_connectionString = connectionString;
}
public IEnumerable<Book> GetAllBooks()
{
using (var connection = new SqlConnection(_connectionString))
{
return connection.Query<Book>("SELECT * FROM Books");
}
}
}
系统的主要实体类设计如下:
Book类:
User类:
BorrowRecord类:
csharp复制public class Book : INotifyPropertyChanged
{
private string _title;
public int BookId { get; set; }
public string Title
{
get => _title;
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("书名不能为空");
_title = value;
OnPropertyChanged();
}
}
// 其他属性和方法...
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
图书管理是系统的核心功能,主要包括:
新增图书:
图书查询:
图书编辑与删除:
csharp复制// 图书查询实现示例
public IEnumerable<Book> SearchBooks(BookSearchCriteria criteria)
{
var query = "SELECT * FROM Books WHERE 1=1";
var parameters = new DynamicParameters();
if (!string.IsNullOrEmpty(criteria.Title))
{
query += " AND Title LIKE @Title";
parameters.Add("@Title", $"%{criteria.Title}%");
}
if (!string.IsNullOrEmpty(criteria.Author))
{
query += " AND Author LIKE @Author";
parameters.Add("@Author", $"%{criteria.Author}%");
}
// 其他条件...
using (var connection = new SqlConnection(_connectionString))
{
return connection.Query<Book>(query, parameters);
}
}
借阅管理模块实现了以下功能:
借书流程:
还书流程:
借阅记录查询:
csharp复制public class BorrowService : IBorrowService
{
private readonly IBookRepository _bookRepo;
private readonly IUserRepository _userRepo;
private readonly IBorrowRecordRepository _borrowRepo;
public BorrowService(IBookRepository bookRepo,
IUserRepository userRepo,
IBorrowRecordRepository borrowRepo)
{
_bookRepo = bookRepo;
_userRepo = userRepo;
_borrowRepo = borrowRepo;
}
public BorrowResult BorrowBook(int userId, int bookId)
{
// 验证用户和图书是否存在
var user = _userRepo.GetById(userId);
var book = _bookRepo.GetById(bookId);
if (user == null || book == null)
return BorrowResult.NotFound;
// 检查库存
if (book.StockQuantity <= 0)
return BorrowResult.OutOfStock;
// 创建借阅记录
var record = new BorrowRecord
{
UserId = userId,
BookId = bookId,
BorrowDate = DateTime.Now,
DueDate = DateTime.Now.AddDays(30)
};
_borrowRepo.Add(record);
// 更新库存
book.StockQuantity--;
_bookRepo.Update(book);
return BorrowResult.Success;
}
}
MVVM最佳实践:
性能优化:
UI设计建议:
xml复制<!-- XAML样式定义示例 -->
<Style TargetType="Button" x:Key="PrimaryButton">
<Setter Property="Background" Value="#FF0078D7"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Padding" Value="10 5"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="4">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
连接管理:
查询优化:
事务处理:
csharp复制// 事务处理示例
public void UpdateBookInventory(int bookId, int quantityChange)
{
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
try
{
// 获取当前库存
var current = connection.ExecuteScalar<int>(
"SELECT StockQuantity FROM Books WHERE BookId = @id",
new { id = bookId }, transaction);
// 更新库存
var newQuantity = current + quantityChange;
if (newQuantity < 0)
throw new InvalidOperationException("库存不足");
connection.Execute(
"UPDATE Books SET StockQuantity = @qty WHERE BookId = @id",
new { qty = newQuantity, id = bookId }, transaction);
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
}
WPF绑定失效:
数据库并发冲突:
跨线程UI更新:
界面卡顿:
查询缓慢:
内存泄漏:
csharp复制// 处理并发冲突示例
public void UpdateBook(Book book)
{
try
{
_dbContext.Entry(book).State = EntityState.Modified;
_dbContext.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var databaseValues = entry.GetDatabaseValues();
var clientValues = entry.Entity as Book;
// 解决冲突逻辑...
if (databaseValues == null)
{
throw new Exception("记录已被删除");
}
else
{
// 合并策略:客户端优先
var databaseBook = (Book)databaseValues.ToObject();
clientValues.RowVersion = databaseBook.RowVersion;
entry.OriginalValues.SetValues(databaseValues);
// 重试保存
_dbContext.SaveChanges();
}
}
}
多租户支持:
高级搜索功能:
移动端适配:
迁移到.NET 6/7:
微服务改造:
前端现代化:
csharp复制// .NET 6新特性示例:记录类型
public record BookDto(
int BookId,
string Title,
string Author,
string ISBN,
DateTime PublishDate,
decimal Price);
// 使用示例
var book = new BookDto(1, "C#高级编程", "John Smith", "123-456", new DateTime(2022,1,1), 99.99m);
var (id, title, author, _, _, price) = book; // 解构
在开发这个图书管理系统的过程中,我深刻体会到良好的架构设计和编码规范的重要性。特别是在处理数据一致性和用户界面响应性方面,需要仔细权衡各种技术方案的优缺点。对于初学者来说,建议从理解三层架构开始,逐步掌握WPF的数据绑定和命令模式,这些都是构建企业级应用程序的基础技能。