目录
一、前言
1.Database.ExecuteSqlCommand 方法不被EF7.0支持
2.SET IDENTITY_INSERT Blog {ON,OFF}不起作用
3.主键和标识列分离,成功实现插入与修改
二、新建本文涉及的项目
三、程序设计
1.Form1.cs源码
2.Form1.cs[设计]
四、生成和测试
1.原始表
2.空内容追加
3.有内容追加、删除记录ID=2、插入记录ID=3
4.插入记录ID=33
5.修改记录ID=31
五、后记
在发布这篇文章之前,先说一下作者为了实现通过EF修改已有数据库记录和在任意空位置插入数据库记录所做过的一些尝试,做这些尝试很累甚至一度失望。因为EF已经更新到7.0(刚刚又更新到了8.0),EF7相对于EF6之前的版本有了一些改变,甚至放弃了一些不安全的对数据库操作的函数,缺少经验的人在知道到的情况下,继续使用那些在EF7以后得版本不再支持的函数,找不到原因的时候是很崩溃的。现在总结一下在写本文时遭遇的EF6函数不再被EF7支持的“花絮”。
我的环境:VS2022,Windows窗体应用,.NET 7.0,NuGet程序包:microsoft.entityframeworkcore.7.0.14、microsoft.entityframeworkcore.design.7.0.14、microsoft.entityframeworkcore.relational.7.0.14、microsoft.entityframeworkcore.sqlserver.7.0.14、microsoft.entityframeworkcore.tools.7.0.14。
数据库:Blogging 。
严重性 |
代码 |
说明 |
项目 |
文件 |
行 |
禁止显示状态 |
错误 |
CS1061 |
“DatabaseFacade”未包含“ExecuteSqlCommand”的定义,并且找不到可接受第一个“DatabaseFacade”类型参数的可访问扩展方法“ExecuteSqlCommand”(是否缺少 using 指令或程序集引用?) |
10_10 |
C:\Users\YCZN_MT\Desktop\10_10\10_10\Form1.cs |
71 |
活动 |
在db.db.Database.后面的方法里根本就找不到ExecuteSqlCommand()了。
db.Database.ExecuteSql($"SET IDENTITY_INSERT Blog ON")
对数据库记录的写入操作
db.Database.ExecuteSql($"SET IDENTITY_INSERT Blog OFF")
以上组合根本就不起作用,网络上的 db.Database.ExecuteSqlCommand ()各种经验因为不被.NET 7.0支持,即使替换上 db.Database.ExecuteSql()也不起作用,在 db2.SaveChanges()处就停下来了,根本就不能将数据写入数据库。无法改变标识列的开与关。
提示“当 IDENTITY_INSERT 设置为 OFF 时,不能向表 ' Blog' 中的标识列插入显式值。”
当主键和IDENTITY列是同一列时,由于EF7废弃了Database.ExecuteSqlCommand ()方法,致使无法在C#中编程实现对SET IDENTITY_INSERT Blog ON或OFF。SQL里的标识列始终起作用,SQL不接受插入不存在记录和修改数据已有记录。
采用主键和IDENTITY列分离,新增加一个列作为标识列,起辅助作用,用途只为了实现插入和修改记录。
采用主键和IDENTITY列分离后,依赖原来的IDENTITY列的追加功能,需要用编程的方法,对BlogId字段进行赋值,本文采用的复制算法是:BlogId=InsertId-1,即BlogId始终等于上一条记录的IDENTITY值。
下面发布正文:
由于作者前期的文章关于这一步都有涉及,因此,此处只写过程的操作摘要:
VS2022,新建Windows窗体应用,.NET 7.0,NuGet程序包版本7.0.14→工具、连接到数据库,Blogging → 逆向工程,生成EF实体模型及数据库上下文→设计Form1.cs[设计]和Form1.cs→生成测试。
其中:PM> Scaffold-DbContext "Server=DESKTOP-3LV13FS;Database=Blogging;Trusted_Connection=True;TrustServerCertificate=true;integrated security=SSPI;" Microsoft.EntityFrameworkCore.SqlServer
数据库更新时:PM> Scaffold-DbContext-Force "Server=DESKTOP-3LV13FS;Database=Blogging;Trusted_Connection=True;TrustServerCertificate=true;integrated security=SSPI;" Microsoft.EntityFrameworkCore.SqlServer
//Form1.cs
//EF7对已有数据库增加、删除、修改、插入
using System.Data;
namespace _10_10
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
///
/// 初始化Form1
/// 初始化表格,显示数据表
///
#region Form1_Load
private void Form1_Load(object sender, EventArgs e)
{
button1.Text = "追加";
button2.Text = "删除";
button3.Text = "插入/覆盖";
label1.Text = "追加的Url:";
label2.Text = "删除的ID:";
label3.Text = "插入记录:";
button1.Size = new Size(40, 23);
button2.Size = new Size(40, 23);
textBox2.Size = new Size(30, 23);
textBox3.Size = new Size(30, 23);
textBox4.Size = new Size(125, 23);
dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;
dataGridView1.AllowUserToResizeColumns = false;
dataGridView1.AllowUserToResizeRows = false;
dataGridView1.RowHeadersVisible = false;
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
using var db = new BloggingContext();
dataGridView1.DataSource = db.Blogs.ToList();
}
#endregion Form1_Load
///
/// 追加Add()
/// 无论ID是否连续,都在数据库末尾追加新纪录
///
#region 追加记录
private void Button1_Click(object sender, EventArgs e)
{
int _rows = dataGridView1.Rows.Count;
using var db = new BloggingContext();
if (textBox1.Text != "")
{
var table = new Blog
{
BlogId = Convert.ToInt32(dataGridView1.Rows[_rows - 1].Cells[2].Value.ToString()),
Url = textBox1.Text.Trim().ToString()
};
db.Blogs.Add(table); //追加记录
db.SaveChanges();
dataGridView1.DataSource = db.Blogs.ToList();
}
else
{
var table = new Blog
{
BlogId = Convert.ToInt32(dataGridView1.Rows[_rows-1].Cells[2].Value.ToString()),
Url = "http://www.hao123.com/"
};
db.Blogs.Add(table);//追加记录
db.SaveChanges();
dataGridView1.DataSource = db.Blogs.ToList();
}
}
#endregion 追加记录
///
/// 删除Remove()
///
#region 删除记录
private void Button2_Click(object sender, EventArgs e)
{
if (textBox2.Text != string.Empty)
{
using var db = new BloggingContext();
var data = (from tb in db.Blogs where tb.BlogId == Convert.ToInt32(textBox2.Text.Trim())
select tb).FirstOrDefault(); //判断数据表中是否包含要删除的ID
if (data != null)
{
using var db2 = new BloggingContext();
var tableNew = new Blog
{
BlogId = Convert.ToInt32(textBox2.Text.Trim())
};
db2.Blogs.Remove(tableNew); //删除记录按ID
db2.SaveChanges();
dataGridView1.DataSource = db2.Blogs.ToList();
}
else
{
MessageBox.Show("数据表中没有这个ID,请重新输入", "提示");
}
}
else
{
MessageBox.Show("请输入要删除记录的编号", "提示");
}
}
#endregion 删除记录
///
/// 插入或覆盖
/// 要插入的ID存在则覆盖原纪录;
/// 要插入的ID不存在则添加记录;
/// Linq无法直接更新主键的数据,只能是先将此条信息复制出来,把原来的那条数据删除,
/// 再重新插入一条修改后的数据,若不是主键数据,则直接更新
///
#region 插入或覆盖记录
private void Button3_Click(object sender, EventArgs e)
{
if (textBox3.Text.Trim() == string.Empty)
{
MessageBox.Show("ID不能为空,请重新输入","提示");
}
else
{
using var db = new BloggingContext();
//db.Database.ExecuteSql($"SET IDENTITY_INSERT Blog ON");
var data = (from tb in db.Blogs
where tb.BlogId == Convert.ToInt32(textBox3.Text.Trim())
select tb).FirstOrDefault();//判断数据表中是否包含要插入的ID
if (data != null)
{
using var db2 = new BloggingContext();
//db2.Database.ExecuteSql($"SET IDENTITY_INSERT Blog ON");
var tableNew = new Blog
{
BlogId = Convert.ToInt32(textBox3.Text.Trim()),
Url = textBox4.Text.Trim().ToString()
};
db2.Blogs.Remove(data); //移除老数据
db2.Blogs.Add(tableNew); //添加新数据
db2.SaveChanges(); //执行更新操作
//db2.Database.ExecuteSql($"SET IDENTITY_INSERT Blog OFF");
dataGridView1.DataSource = db2.Blogs.ToList();
}
else
{
using var db2 = new BloggingContext();
//db2.Database.ExecuteSql($"SET IDENTITY_INSERT Blog ON");
var table = new Blog
{
BlogId = Convert.ToInt32(textBox3.Text.Trim()),
Url = textBox4.Text.Trim().ToString()
};
db2.Blogs.Add(table); //执行插入操作
db2.SaveChanges();
//db2.Database.ExecuteSql($"SET IDENTITY_INSERT Blog OFF");
dataGridView1.DataSource = db2.Blogs.ToList();
}
//db.Database.ExecuteSql($"SET IDENTITY_INSERT Blog OFF");
}
}
#endregion 插入或覆盖记录
}
}
本文所使用的主键和标识列分离的方法实现对数据库已有记录的修改,不存在的记录的插入操作,仅代表作者的一种实现方法,不代表是唯一的实现方法。也许读者们有更好的实现办法。希望在日后的工作中此方面能与读者共勉共研。