一、前言
任何一个应用程序都离不开数据的存储,数据可以在内存中存储,但只能在程序运行时存取,无法持久保存。
数据还可以在磁盘中以文件的形式存储,但文件的管理和查找又十分烦琐无法胜任大数量的存储。
将数据存储到数据库中是在应用程序中持久存储数据的常用方式。
在 C# 语言中提供了 ADO.NET 组件来实现连接数据库以及操作数据库中数据的功能。
二、使用ADO.NET操作数据库
在 C#语言中 ADO.NET 是在 ADO 的基础上发展起来的,ADO (Active Data Object) 是一个 COM 组件类库,用于访问数据库,而 ADO.NET 是在 .NET 平台*问数据库的组件。
ADO.NET 是以 ODBC (Open Database Connectivity) 技术的方式来访问数据库的一种技术。下面我们通过winform窗体应用来使用ADO.NET。
1.新建winform程序,放置一个按钮,用来测试数据库连接。
2.在forms1.cs里引用using System.Data.SqlClient;并写一个连接sql的方法
static SqlConnection Conn() { //编写数据库连接串 string connStr = "Data source=.;Initial Catalog=test;User ID=sa;Password=sa123"; //创建SqlConnection的实例 SqlConnection conn = null; try { conn = new SqlConnection(connStr); //打开数据库连接 conn.Open(); MessageBox.Show("数据库连接成功!"); } catch (Exception ex) { conn.Close(); MessageBox.Show("数据库连接失败!" + ex.Message); } finally { if (conn != null) { //关闭数据库连接 conn.Close(); } } return conn; }
3.新建全局变量 conn,并绑定按钮点击事件,这样就不用每次操作都要连接一下数据库:
public SqlConnection conn; private void test_conn_Click(object sender, EventArgs e) { conn = Conn(); }
4.运行程序,点击按钮,如果连接成功会提示连接成功,如果失败提示失败原因。
5.数据库连接成功,下面开始插入数据。新建表t_product,定义三个字段,id,name,stock,id设为主键并自增。
6.放置一个添加按钮,并绑定点击事件。
private void add_Click(object sender, EventArgs e) { if (conn!=null) { try { conn.Open(); string sql = "insert into t_product(Name,Stock) values(‘{0}‘,{1})"; //填充SQL语句 sql = string.Format(sql, "商品1", 53); //创建SqlCommand对象 SqlCommand cmd = new SqlCommand(sql, conn); //执行SQL语句 int returnvalue = cmd.ExecuteNonQuery(); //判断SQL语句是否执行成功 if (returnvalue != -1) { MessageBox.Show("插入数据成功!"); } } catch (Exception ex) { MessageBox.Show("插入数据失败!" + ex.Message); } finally { if (conn != null) { //关闭数据库连接 conn.Close(); } } } else { MessageBox.Show("请检查数据库连接!"); } }
7.多次点击添加按钮,提示添加成功,数据库查看数据。
8.插入数据没问题,下面开始查询数据,页面放置查询按钮,用来查询数据,一个listview控件,用来显示信息。
9.绑定查询事件,点击查询按钮,listview显示数据库的数据:
private void query_all_Click(object sender, EventArgs e) { if (conn != null) { try { string sql = "select Name from t_product"; //创建 SqlDataAdapter 类的对象 SqlDataAdapter sda = new SqlDataAdapter(sql, conn); //创建 DataTable 类的对象 DataTable dt = new DataTable(); //使用 SqlDataAdapter 对象 sda 将查询结果填充到 DataSet 对象 dt 中 sda.Fill(dt); //设置 ListBox 控件的数据源(DataSource)属性 pro_list.DataSource = dt; //在 ListBox 控件中显示 name 列的值 pro_list.DisplayMember = dt.Columns[0].ToString(); } catch (Exception ex) { MessageBox.Show("插入数据失败!" + ex.Message); } finally { if (conn != null) { //关闭数据库连接 conn.Close(); } } } else { MessageBox.Show("请检查数据库连接!"); } }
三、什么是ORM
ORM(Object Relational Mapping)是对象关系映射。它的实质就是将关系数据(库)中的业务数据用对象的形式表示出来,并通过面向对象(Object-Oriented)的方式将这些对象组织起来,实现系统业务逻辑的过程。在ORM过程中最重要的概念是映射(Mapping),通过这种映射可以使业务对象与数据库分离。从面向对象来说,数据库不应该和业务逻辑绑定到一起,ORM则起到这样的分离作用,使数据库层透明,开发人员真正的面向对象 。
ORM是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
一般的ORM包括以下四部分:
一个对持久类对象进行CRUD操作的API;
一个语言或API用来规定与类和类属性相关的查询;
一个规定mapping metadata的工具;
一种技术可以让ORM的实现同事务对象一起进行dirty checking, lazy association fetching以及其他的优化操作。
三、使用Entity Framework
1.安装EF
2.创建实体类User
namespace WindowsFormsApp1 { [Table("t_user")]//设置表名 public class User { [Key] public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } }
3.为实体类创建一个数据库上下文类DbContext:
using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsFormsApp1 { class UserDbContext: System.Data.Entity.DbContext { /// <summary> /// /// 数据库上下文类中存在了一个构造函数,一个用来操作的数据库的上下文,被DbSet定义的user。 ///构造函数的作用是定义一个连接数据库的字符串"Conn"。 /// </summary> public UserDbContext() : base("Conn") { } /// <summary> /// 被DbSet定义的user就是我们用来操作数据库的上下文,里面存在了常用的Add,Delete,Save等增删改查方法。 /// </summary> public DbSet<User> user{ get; set; } } }
4.配置app.config文件,添加<connectionStrings>属性<add>里面主要存在三个重要配置信息,name为上下文类设置的连接字符串,connectionStrings为连接数据库信息,providerName定义了连接不同数据库的类型,这里为sqlserver
<connectionStrings> <add name="Conn" connectionString="server=.;uid=sa;pwd=sa123;database=." providerName="System.Data.SqlClient" /> </connectionStrings>
5.页面新建一个按钮,用来操作EF插入数据,并绑定点击事件。
private void ef_add_Click(object sender, EventArgs e) { try { UserDbContext db = new UserDbContext(); User pd = new User(); pd.Name = "张三"; pd.Age = 11; db.user.Add(pd); db.SaveChanges(); MessageBox.Show("EF插入数据成功!"); } catch (Exception ex) { MessageBox.Show("EF插入数据失败!" + ex.Message); } }
点击按钮提示插入成功。
6.EF查询有三种方式,所以我们在页面新建三个按钮用来查询数据,分别绑定三个按钮的点击事件。
初始数据:
private void ef_query1_Click(object sender, EventArgs e) { try { UserDbContext db = new UserDbContext(); //查询年龄为11的人,并按照ID倒序排序 var persons = from p in db.user where p.Age == 11 orderby p.Id descending select p; foreach (var p in persons) { user_list.Items.Add(p.Name); } MessageBox.Show("查询数据成功!"); } catch (Exception ex) { MessageBox.Show("查询数据失败!" + ex.Message); } }
private void ef_query3_Click(object sender, EventArgs e) { try { UserDbContext db = new UserDbContext(); var age =11; //查询年龄为11的人,并按照ID倒序排序 var persons = db.user.SqlQuery($"select * from t_user where Age=‘{age}‘ order by id desc"); foreach (var p in persons) { user_list.Items.Add(p.Name); } //不仅如此,EF还支持非实体类型的查询 //var persons = db.Database.SqlQuery<string>($"select Name from t_user where Age=‘{age}‘ order by id desc"); //foreach (var p in persons) //{ // user_list.Items.Add(p); //} MessageBox.Show("查询数据成功!"); } catch (Exception ex) { MessageBox.Show("查询数据失败!" + ex.Message); } }
结果: