目录
1.什么是ORM:
ORM(object relational mapping,对象关系映射)“对象”是指的就是C#中的对象,而“关系”指的是关系型数据库(如SQLsever,MySQL,Oracle),“映射”指的是在关系型数据库和C#对象之间搭建一座“桥梁”。常用的ORM框架:EF Core,Dapper,SqlSugar,FreeSql。
注:这里只注重讲EF Core
EF Core与其他ORM框架比较:
(1)EF Core(Entity Framework Code ):是微软官方的ORM框架。优点:功能强大,官方支持,生产效率高,力求屏蔽底层数据库差异。缺点:复杂,上手门槛高
(2)Dapper:优点:简单,N分钟即可上手,行为可预期强。缺点:生产效率低,需处理底层数据库差异。
(3)性能:Dapper等不等于性能高;EF Core不等于性能差
(4)EF Core是官方推荐,推进的框架,尽量屏蔽底层数据库差异。.NET开发者必须熟悉,根据项目情况决定用哪个。
2.EF Core入门:
(1)EF Core环境搭建
-
安装.NET Core SDK。可以从Microsoft的官方网站下载并安装最新的.NET Core SDK。
-
创建.NET Core项目。可以使用Visual Studio或命令行创建.NET Core项目。
-
安装EF Core。在项目中使用NuGet包管理器安装EF Core。
-
配置数据库连接。在项目中添加数据库提供程序的NuGet包,并配置连接字符串。
下面是一个使用SQLsever数据库的示例:
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace EFCoreDemo
{
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=blog.db;)
}
}
class Program
{
static void Main(string[] args)
{
using (var context = new BlogContext())
{
context.Database.EnsureCreated();
var blog = new Blog { Url = "http://blogs.msdn.com/adonet" };
context.Blogs.Add(blog);
context.SaveChanges();
var blogs = context.Blogs.ToList();
foreach (var b in blogs)
{
System.Console.WriteLine(b.Url);
}
}
}
}
}
在这个示例中,我们首先定义了一个Blog实体类,并创建了一个DbContext类,表示与数据库交互的上下文。在OnConfiguring方法中,我们使用SQLite数据库提供程序配置了连接字符串。然后,在Main方法中,我们使用DbContext的SaveChanges方法将Blog实体添加到数据库中,并使用ToList方法查询所有博客。最后,我们遍历博客列表,并打印出博客的URL。
(2)插入数据
要插入数据,可以使用Add方法将实体添加到DbSet中,并调用SaveChanges方法将更改保存到数据库中:
using (var context = new BlogContext())
{
var blog = new Blog { Url = "http://blogs.msdn.com/visualstudio" };
context.Blogs.Add(blog);
context.SaveChanges();
}
(3)查询数据
要查询数据,可以使用LINQ语言编写查询,并使用ToList、FirstOrDefault、Count等方法获取查询结果:
using (var context = new BlogContext())
{
var blogs = context.Blogs
.Where(b => b.Url.Contains("msdn"))
.OrderBy(b => b.BlogId)
.ToList();
}
(4)修改和删除数据
要修改数据,可以先查询实体,然后修改属性值,并调用SaveChanges方法将更改保存到数据库中
using (var context = new BlogContext())
{
var blog = context.Blogs.Find(1);
if (blog != null)
{
blog.Url = "http://blogs.msdn.com/efcore";
context.SaveChanges();
}
}
3.EF Core的实体类配置
(1)约定大于配置:
约定大于配置(Convention over Configuration)是一种软件开发中的设计思想,旨在通过使用默认约定来降低系统的复杂性。在EF Core中,约定大于配置指的是,如果不指定任何配置信息,则EF Core会使用默认的约定来推断实体类与数据库之间的映射关系。
例如,EF Core默认假定实体类名称与数据库表名相同,并将实体类的属性映射到与其名称相同的数据库列中。如果实体类的属性是整数,则假定它是数据库表的主键。这意味着,如果没有指定任何配置信息,EF Core会根据这些默认约定来配置实体类和数据库之间的映射关系。
当然,如果需要更精细的控制,也可以使用Data Annotations或Fluent API来配置实体类和数据库之间的映射关系。这些配置信息会覆盖默认的约定,以实现更准确的控制。但是,使用约定大于配置的设计思想,可以将大部分的配置工作交给框架来完成,从而减少了代码量,提高了开发效率。
总之,约定大于配置的设计思想在EF Core中非常重要,它使得开发人员可以根据默认约定快速开发应用程序,同时也提供了灵活的方式来进行自定义配置,以满足更精细的需求。
(2)Data Annotations
Data Annotations是一种基于属性的注释,可以将它们添加到实体类的属性上,以配置实体类和数据库之间的映射关系。Data Annotations的示例包括:
-
Key: 指定实体类的主键属性。
-
Column: 指定实体属性与数据库字段的映射关系。
-
Required: 指定实体属性是否为必需属性。
以下是一个使用Data Annotations的示例:
using System.ComponentModel.DataAnnotations;
public class Blog
{
[Key]
public int BlogId { get; set; }
[Required]
public string Url { get; set; }
[Column("BlogName")]
public string Name { get; set; }
}
在这个示例中,我们使用Key注释指定了实体类的主键属性。使用Required注释指定了实体属性是否为必需属性。使用Column注释指定了实体属性与数据库字段的映射关系。
(3)Fluent API:
除了Data Annotations之外,还可以使用Fluent API来配置实体类。Fluent API是一种基于方法调用的配置方式,可以在DbContext类的OnModelCreating方法中使用。
Fluent API的示例包括:
-
HasKey: 指定实体类的主键属性。
-
Property: 指定实体属性与数据库字段的映射关系。
-
HasColumnType: 指定数据库字段的数据类型。
以下是一个使用Fluent API的示例:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasKey(b => b.BlogId);
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
modelBuilder.Entity<Blog>()
.Property(b => b.Name)
.HasColumnName("BlogName")
.HasColumnType("varchar(100)");
}
在这个示例中,我们在DbContext的OnModelCreating方法中使用Fluent API来配置Blog实体类。使用HasKey方法指定实体类的主键属性。使用Property方法指定实体属性与数据库字段的映射关系。使用HasColumnType方法指定数据库字段的数据类型。
4.数据库迁移:
数据库迁移(Database Migration)是EF Core的一个强大功能,它可以自动更新数据库模式以反映数据模型的更改,或者创建新的数据库。
下面是使用EF Core进行数据库迁移的一些基本步骤:
-
安装Microsoft.EntityFrameworkCore.Tools包:在Visual Studio中,可以通过NuGet包管理器来安装Microsoft.EntityFrameworkCore.Tools包。或者,也可以在命令行中使用以下命令来安装该包:
dotnet add package Microsoft.EntityFrameworkCore.Tools
-
创建DbContext类:创建一个继承自DbContext类的类,并在构造函数中配置数据库连接字符串。
-
创建初始迁移:在控制台中,使用以下命令来创建初始迁移:
dotnet ef migrations add InitialCreate
这个命令将在应用程序中创建一个迁移文件,其中包含一个CreateTable操作,用于创建数据库表。
-
应用迁移:在控制台中,使用以下命令来将迁移应用于数据库:
dotnet ef database update
这个命令将在数据库中创建一个新的表,并将初始数据插入该表。
-
更新数据模型:在DbContext类中更新数据模型,并使用以下命令创建新的迁移:
dotnet ef migrations add <migration_name>
-
应用新的迁移:在控制台中,使用以下命令来将新的迁移应用于数据库:
dotnet ef database update
这个命令将更新数据库模式以反映新的数据模型。
需要注意的是,如果更新数据模型中包含重要的更改,例如删除表或更改列名,那么在更新数据库之前,应该先备份现有的数据库,以免丢失数据。
总之,EF Core的数据库迁移功能可以帮助开发人员快速而方便地更新数据库模式,使其与应用程序的数据模型保持同步。这是一个非常有用的功能,可以提高开发效率,减少错误。
5.如何查看EF Core生成的SQL语句
(1)使用EF Core的日志记录功能:
在应用程序启动时,可以启用EF Core的日志记录功能,并将日志级别设置为Debug,以便查看生成的SQL语句。在ASP.NET Core应用程序中,可以在Configure方法中添加以下代码:
using Microsoft.Extensions.Logging;
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
loggerFactory.AddDebug(LogLevel.Debug);
// other middleware
}
在控制台中,将显示生成的SQL语句和其他EF Core的日志记录信息。
(2)使用ToSqlString方法:
在EF Core中,可以使用DbQuery类和DbSet类中的ToSqlString方法来获取生成的SQL语句。例如,以下代码将从DbSet中获取所有记录的SQL语句:
using Microsoft.EntityFrameworkCore;
var dbContext = new MyDbContext();
var sql = dbContext.MyDbSet.ToSqlString();
这个方法会返回一个字符串,其中包含生成的SQL语句。
无论使用哪种方式,都可以方便地查看EF Core生成的SQL语句,以便调试和优化应用程序。
6.关系配置
以下我都将通过两种方式来配置实体类
(1)一对多:
以下是使用Data Annotation的示例:
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("Department")]
public int DepartmentId { get; set; }
public Department Department { get; set; }
}
在上面的示例中,Department和Employee之间是一个一对多的关系。使用Data Annotation中的ForeignKey特性来指定外键属性和导航属性之间的关系。
以下是使用Fluent API的示例:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.HasOne<Department>(e => e.Department)
.WithMany(d => d.Employees)
.HasForeignKey(e => e.DepartmentId);
}
在上面的示例中,使用HasOne和WithMany方法指定关系,使用HasForeignKey方法指定外键属性。
(2)一对一:
以下是使用Data Annotation的示例:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
[ForeignKey("Person")]
public int PersonId { get; set; }
public Person Person { get; set; }
}
在上面的示例中,Person和Address之间是一个一对一的关系。使用Data Annotation中的ForeignKey特性来指定外键属性和导航属性之间的关系。
以下是使用Fluent API的示例:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOne<Address>(p => p.Address)
.WithOne(a => a.Person)
.HasForeignKey<Address>(a => a.PersonId);
}
(3)多对多(需要创建一个中间表):
在EF Core中,配置多对多关系需要创建一个中间实体类来映射两个实体之间的关系,称为联接表或关系表。中间实体类通常包含两个外键属性,分别指向另外两个实体的主键,用于表示两个实体之间的关系。(这里就只用Fluent API来创建)
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<CourseStudent> CourseStudents { get; set; }
}
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<CourseStudent> CourseStudents { get; set; }
}
public class CourseStudent
{
public int StudentId { get; set; }
public Student Student { get; set; }
public int CourseId { get; set; }
public Course Course { get; set; }
}
// 在OnModelCreating方法中配置多对多关系
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<CourseStudent>()
.HasKey(cs => new { cs.StudentId, cs.CourseId });
modelBuilder.Entity<CourseStudent>()
.HasOne(cs => cs.Student)
.WithMany(s => s.CourseStudents)
.HasForeignKey(cs => cs.StudentId);
modelBuilder.Entity<CourseStudent>()
.HasOne(cs => cs.Course)
.WithMany(c => c.CourseStudents)
.HasForeignKey(cs => cs.CourseId);
}
在上面的示例中,CourseStudent是中间实体类,包含两个外键属性StudentId和CourseId,分别指向Student和Course的主键。
使用HasKey方法指定联合主键,使用HasOne和WithMany方法指定实体之间的关系,并使用HasForeignKey方法指定外键属性。这些配置都在OnModelCreating方法中完成。
通过这样的配置,EF Core会自动创建一个CourseStudent表来存储两个实体之间的关系。