ASP.NET Core 三: ADO,Ef core,Mysql,服务器资源管理器
说明概念:
ADO是一套数据库访问规范API,每个数据库厂商都有对这个API的具体实现的类库。此文章采用的范例是基于Mysql
ADO.Net访问数据库:
有几个要点。连接(连接池,连接信息),命令(ExcuteNonQuery,ExcuteReader,ExcuteScalar,调用存储过程),异步数据访问, 事务。
对于事务的Transection,在Windows上作为Framework的一部分作为分布式事务协调器,具体这里以后在做深入研究
对于Mysql需要使用的类库是MySql.Data。
下面的例子是一个简单的Mysql数据库访问,并执行select查询语句。
static void Main(string[] args) { //连接数据库 string connectStr = "Database='world';Data Source='localhost';User Id='root';Password='mysql2333';charset='utf8';pooling=true"; var connection = new MySqlConnection(connectStr); connection.Open(); Console.WriteLine("Connection Opened"); //数据库操作 string selectCmd = "select * from city";//Sql查询语句 MySqlCommand mySqlCommand = new MySqlCommand(selectCmd, connection);//实例化Sql命令 MySqlDataReader reader = mySqlCommand.ExecuteReader();//执行Sql命令 //读取结果 while (reader.Read()) { int id = reader.GetInt32(0); string name = reader.GetString(1); Console.WriteLine($"{id}, {name}"); } //连接关闭 connection.Close(); }
Visual Studio服务器资源管理窗口
为了像Sql Sever那样可以在Visual Studio上可以直接操作Mysql数据库,需要安装MySQL for Visual Studio,从而在创建连接的时候有MySQL Database选项。
EF Core解析
下面是一个使用Ef core的简单例子,使用的数据库是Mysql,使用的依赖包为Microsoft.EntityFrameworkCore和Mysql.EntityFrameworkCore,在写本文章时,使用的Mysql的依赖包与以前的依赖包有所不同,应该是随着数据库版本更新,官方提供的程序也随之更新。(Mysql会有长度等限制,好吧,设置数据库是真的麻烦,尤其是在你专心学习某个框架或者应用的时候却要被其他的问题分散精力。使用Mysql.EntityFrameworkCore建立表时会有Specified key was too long; max key length is 3072 bytes这样的报错提示,去他大爷,我才不想在学习框架的时候浪费时间去解决这个问题,因此我找到了Pomelo.EntityFrameworkCore.MySql这个包来代替Mysql.EntityFrameworkCore)
几个要点:数据库上下文,数据模型(数据关系,迁移,数据库创建,数据注释,创建数据库,在数据库中创建模型),使用对象状态,冲突处理(最后一个获胜,第一个获胜),事务(隐式事务,显式事务)
数据库上下文即DbContext就相当于对一个数据库的映射。数据属性成员如DBSet<Book> books相当于数据库的表。
数据关系默认是根据类的定义生成的(看书和文档),并且数据类型如Book可以通过数据注释确定具体的数据描述。但也可以通过Dbcontext的流利API即OnModelCreating来确立数据的描述和生成的表以及表之间的关系。
而迁移的创建命令会根据DbContext创建具体的数据库操作类,然后执行更新命令的时候创建或者更新具体的数据库以及对应的表。
在例子中使用了booksContext.Database.EnsureCreated();来确保数据库及其表存在。相当于执行了迁移命令。
根据Code First即代码优先原则,如果我们在写代码的过程中不想去弄具体的数据库以及安装数据等一些列数据库的相关操作,那么可以直接去操作DbSet对象。如果不想使用任何数据库,那么不需要optionsBuilder.UseMySQL(ConnectionString,null);这个命令,而是可以直接使用内容作为测试用临时数据库(依赖包Microsoft.EntityFrameworkCore.InMemory),只不过关闭应用的数据就消失了。使用内存作为数据:config.UseInMemoryDatabase("Memory");
小技巧:在使用migration的Update-database时,会出现表失败,那么可以直接修改migration相关类文件里面的对应的字段长度,再重新执行update命令。
有关具体操作过程和细节,读者可翻阅数据和官方文档。
数据模型
[Table("Books")] public class Book { public int BookId { get; set; } public string Title { get; set; } public string Publisher { get; set; } }
数据库上下文
public class BooksContext:DbContext { private const string ConnectionString = "Database='book';Data Source='localhost';User Id='root';Password='mysql2333';charset='utf8';pooling=true"; protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); optionsBuilder.UseMySQL(ConnectionString,null); } public DbSet<Book> Books { get; set; } }
业务逻辑操作类
public class BooksService { private readonly BooksContext _BooksContext; public BooksService(BooksContext booksContext) { _BooksContext = booksContext; } public async Task AddBooksAsync() { var b1 = new Book { Title = "book01", Publisher = "publiser01" }; var b2 = new Book { Title = "book02",Publisher = "publiser02" }; var b3 = new Book { Title = "book03",Publisher = "publiser03" }; var b4 = new Book { Title = "book04", Publisher = "publiser04" }; _BooksContext.AddRange(b1, b2, b3, b4); int records = await _BooksContext.SaveChangesAsync(); Console.WriteLine($"{records} recoreds added"); } public void ReadBooks() { var books = _BooksContext.Books; foreach(var b in books) { Console.WriteLine($"{b.BookId},{b.Title},{b.Publisher}"); } Console.WriteLine(); } }
class Program { static void Main(string[] args) { BooksContext booksContext = new BooksContext(); booksContext.Database.EnsureCreated(); BooksService booksService = new BooksService(booksContext); booksService.AddBooksAsync().Wait(); booksService.ReadBooks(); //var services = new ServiceCollection(); //services.AddTransient<BooksService>(); //services./*AddEntityFrameworkCore().*/AddDbContext<BooksContext>(); //IServiceProvider container = services.BuildServiceProvider(); //var service = container.GetService<BooksService>(); //service.AddBooksAsync().Wait(); //service.ReadBooks(); } }