项目要求
本项目旨在熟悉在C#的环境下对数据库进行连接并进行相关的sql操作。
基本目标:
- 实现对不同数据库的连接
- 设计数据表以支持不同的Sql操作
实现思路
- 由于要连接不同的数据库,则可以直接定义一个连接数据库的工具类,用于处理数据库的连接
- 考虑到Navicat不能管理Access数据库,因此,设计一个界面,允许用户输入建表的sql语句,以此实现便捷化建表
- 此项目的目的是熟悉数据库的连接以及sql的使用,因此,在本项目中,未使用实体类来对应查询结果,而是将查询到的结果直接转换为DataTable,并据此来对 DataGridView中的数据进行绑定。
实现效果
数据设计
为了对Sql语句进行充分的练习,建表的背景是学生的选课信息以及每门课程的信息。
包含四个表:
- Students 表:存储学生的信息。
- Courses 表:存储课程的信息。
- Enrollments 表:存储学生选课的信息。
- Grades 表:存储学生每门课的成绩。
下面是详细的建表过程:
CREATE TABLE Enrollments (
EnrollmentID TEXT(36) PRIMARY KEY,
StudentID TEXT(36),
CourseID TEXT(36),
EnrollmentDate DATE,
CONSTRAINT FK_Student FOREIGN KEY (StudentID) REFERENCES Students(StudentID),
CONSTRAINT FK_Course FOREIGN KEY (CourseID) REFERENCES Courses(CourseID)
);
CREATE TABLE Students (
StudentID TEXT(36) PRIMARY KEY,
StudentName TEXT(50),
Age INT,
Gender TEXT(10),
Major TEXT(50)
);
CREATE TABLE Courses (
CourseID TEXT(36) PRIMARY KEY,
CourseName TEXT(100),
Credits INT
);
CREATE TABLE Grades (
GradeID TEXT(36) PRIMARY KEY,
StudentID TEXT(36),
CourseID TEXT(36),
Grade DECIMAL(3, 2),
CONSTRAINT FK_GradeStudent FOREIGN KEY (StudentID) REFERENCES Students(StudentID),
CONSTRAINT FK_GradeCourse FOREIGN KEY (CourseID) REFERENCES Courses(CourseID)
);
SQL语句练习
查询所有学生及其所选课程和成绩的信息:
SELECT s.StudentName, c.CourseName, e.EnrollmentDate, g.Grade
FROM (Enrollments e
JOIN Students s ON e.StudentID = s.StudentID)
JOIN Courses c ON e.CourseID = c.CourseID
LEFT JOIN Grades g ON e.StudentID = g.StudentID AND e.CourseID = g.CourseID;
查询每门课程的选课人数:
SELECT c.CourseName, COUNT(e.StudentID) AS NumberOfStudents
FROM Enrollments e
JOIN Courses c ON e.CourseID = c.CourseID
GROUP BY c.CourseName;
查询每位学生的选课总学分:
SELECT s.StudentName, SUM(c.Credits) AS TotalCredits
FROM (Enrollments e
JOIN Students s ON e.StudentID = s.StudentID)
JOIN Courses c ON e.CourseID = c.CourseID
GROUP BY s.StudentName;
查询每个专业的学生平均年龄:
SELECT s.Major, AVG(s.Age) AS AverageAge
FROM Students s
GROUP BY s.Major;
关键点实现
数据库帮助类的实现
通过 传入的数据库类型来进行不同的数据库连接操作,数据库连接字符串的配置放在App.config 里面,需要注意的是,App.config 的根目录是bin/debug文件。
数据库连接字符串
<connectionStrings>
<add name="SqlServerConnectionString" connectionString="Server = localhost; Database = Student; User Id = sa; Password = admin123;" providerName="System.Data.SqlClient" />
<add name="SqliteConnectionString" connectionString="Data Source=studentGrade.db;Version=3;" providerName="System.Data.SqlClient" />
<add name="AccessConnectionString" connectionString= "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=studentGrade.accdb;Persist Security Info=False;" providerName="System.Data.SqlClient" />
</connectionStrings>
通过ConfigurationManager类去获取值。
// 构造函数,接受数据库类型和连接字符串
public DbHelper(DatabaseType dbType)
{
switch (dbType)
{
case DatabaseType.SqlServer:
connectionString = ConfigurationManager.ConnectionStrings["SqlServerConnectionString"].ConnectionString;
connection = new SqlConnection(connectionString);
break;
case DatabaseType.SqLite:
connectionString = ConfigurationManager.ConnectionStrings["SqliteConnectionString"].ConnectionString;
connection = new SQLiteConnection(connectionString);
break;
case DatabaseType.Access:
connectionString = ConfigurationManager.ConnectionStrings["AccessConnectionString"].ConnectionString;
connection = new OleDbConnection(connectionString);
break;
default:
throw new NotSupportedException("不支持的数据库类型");
}
}
Dapper 数据转DataTable的实现
public static class DataTableHelper
{
public static DataTable ToDataTable(this IEnumerable<dynamic> items)
{
var dataTable = new DataTable();
if (items == null || !items.Any())
{
return dataTable;
}
var firstItem = (IDictionary<string, object>)items.First();
foreach (var key in firstItem.Keys)
{
dataTable.Columns.Add(key);
}
foreach (var item in items)
{
var dataRow = dataTable.NewRow();
var dictionary = (IDictionary<string, object>)item;
foreach (var key in dictionary.Keys)
{
dataRow[key] = dictionary[key] ?? DBNull.Value;
}
dataTable.Rows.Add(dataRow);
}
return dataTable;
}
}
遇到的问题
- Sqlite 在当前目录下创建了数据库,但是看不到,需要执行一个./database 才会显示
- 注意连接字符串的数据库存放的地址
- Access 的SQL语法与常用的有些许不同,需要单独考考虑
- Sqlite 的一个 xx.dll文件需要手动放到Debug文件下,还需要注意是32位的还是64位的
总结与展望
- 数据库连接类的是必不可少的,能简化很多操作。
- 目前程序很多地方都不完善,没有对异常进行处理,没有进行事务的操作等。