概览
EF Core 6.0 是建立在ADO.NET框架之上的,它下面仍旧使用了ADO.NET方法和类来执行数据操作。DbContext负责将sqlite翻译成sqlite,跟踪数据状态。
EF Core 6.0底层是Miscrosoft.Data.sqlite。DbContext
,这个类是EF Code First的核心,在高层次上是数据库抽象,DbContext是一级缓存。
学习顺序
1、了解ORM概念、POCO 类型、linq、mvvm模式
2、了解EF Core 6.0的历史、为什么要使用EF Core、Entity Framework的三种开发风格
3、了解DbSet与DbContext、模型、配置模型
4、DbSet crud操作 ,详细查看https://learn.microsoft.com/zh-cn/ef/core/performance/advanced-performance-topics?tabs=with-di%2Cwith-constant#dbcontext-pooling
开始实操(CodeFirst的数据库初始化)
1)环境:vs2022+.net6.0+EF Core 6.0 +sqlite3+mvvm模式
2)创建WPF应用程序MvvmDemo并且安装实体框架 NuGet 包 Microsoft.EntityFrameworkCore.qlite(6.0.9)、安装 Sqlite 包后,并且安装Microsoft.EntityFrameworkCore 基础包。可以选择安装 Microsoft.EntityFrameworkCore.Proxies 包提供对“延迟加载”数据的支持。
3)创建sqlite数据库Data.db和PersonInfo表
4)C# 创建实体模型 PersonInfo.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; namespace MvvmDemo.Mvvm.Models { public class Student { [Key] public string Name { get; set; } public string Age { get; set; } } public class PersonInfo : IDataErrorInfo { /// <summary> /// 对应数据库中 表格 /// </summary> /// #region 实体 private string? _email; //字段不会有映射到数据库的表格 private string? _firstName; private string? _lastName; [Column("Company")] //对应数据库中表的列 public string? Company { get; set; } [Column("FirstName")] //对应数据库中表的列 public string FirstName { get { return _firstName; } set { _firstName = value; } } [Column("LastName")] //对应数据库中表的列 public string? LastName { get { return _lastName; } set { _lastName = value; } } [Column("Email")] //对应数据库中表的列 [Key]//主键 public string Email { get; set; } [Column("IsCompany")] //对应数据库中表的列 public bool IsCompany { get; set; } = false; [Column("TotalSales")] //对应数据库中表的列 public double? TotalSales { get; set; } #endregion //不映射到对应数据库中表的列 public bool IsValid { get { foreach (string item in ValidationProperties) { if (string.IsNullOrEmpty(ValidationError(item))) return true; } return false; } } [NotMapped] //不映射到对应数据库中表的列 public string? IsSelected { get; set; } public PersonInfo() { } string IDataErrorInfo.Error => throw new NotImplementedException();//用于表格的行验证 //用于单元格属性验证 string IDataErrorInfo.this[string propertyName] => ValidationError(propertyName); private string? ValidationError(string propertyName) { //哪些属性需要验证 if (Array.IndexOf(ValidationProperties, propertyName) < 0) return null; switch (propertyName) { case "FirstName": return ValidationFirstName(); case "LastName": return ValidationLastName(); case "Company": return ValidationCompany(); case "Email": return ValidationEmail(); default: return ""; } } private string? ValidationEmail() { if (String.IsNullOrEmpty(_email)) return GetPropertyValue("EmailIsNotNull"); string partn = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$"; ; if (!Regex.IsMatch(_email, partn, RegexOptions.IgnoreCase)) { return GetPropertyValue("EmailFormatIsError"); } return null; } private string ValidationCompany() { throw new NotImplementedException(); } private string? ValidationLastName() { //本地化错误提示 if (String.IsNullOrEmpty(_firstName)) return GetPropertyValue("FirstName_NameIsNotnull"); if (_firstName.Length <= 5) return GetPropertyValue("FirstName_NameLengthMore5char"); return null; } static readonly string[] ValidationProperties = { "Email", "FirstName", "LastName", }; private string ValidationFirstName() { //本地化错误提示 if (String.IsNullOrEmpty(_firstName)) return GetPropertyValue("FirstName_NameIsNotnull"); if (_firstName.Length <= 5) return GetPropertyValue("FirstName_NameLengthMore5char"); return ""; } string GetPropertyValue(string name) { return (string)Application.Current.Resources[name]; } private Dictionary<String, List<String>> errors = new Dictionary<string, List<string>>(); public PersonInfo(string firstName, string? lastName, string email, bool isCompany, double? totalSales) { FirstName = firstName; LastName = lastName; Email = email; IsCompany = isCompany; TotalSales = totalSales; } } }
5)配置数据连接 App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings > <!--相对与当前目录的路径--> <add name="LoginString" connectionString="Data Source=D:\程序开发\观察者\mvvmdemo\MvvmDemo\MvvmDemo\Repositories\Data.db; " providerName="Microsoft.EntityFrameworkCore.Sqlite" /> </connectionStrings> </configuration>
6)建立实体和数据库表格映射。
有两种方式建立实体和数据表格之间映射关系。
在自定义的上下文DataContext 中采用Fluent API方式建立实体和数据库表格映射关系。详细查看微软官网 FluentAPI详细用法
在实体中通过Attribute特性建立实体和数据库表格映射关系。详细查看微软官网
定制DataContext 上下文,模型映射(Model Mapping),用于连接数据和poco
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Sqlite; using MvvmDemo.Mvvm.Models; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MvvmDemo.Repositories { public class DataContext : DbContext { private readonly string _connection; public DbSet<PersonInfo> PersonInfos{get;set;}//实体表,提供给外部crud使用,PersonInfos内部有DataContext 的实例 public DataContext() { //1、获取连接数据库的字符串 _connection = ConfigurationManager.ConnectionStrings["LoginString"].ConnectionString; } //2、联接数据库 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite(_connection); } //3、建立实体和数据库表格 一 一 映射。 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<PersonInfo>() .ToTable("PersonInfos"); } } }
7)可选配置.Net EF中DbContext动态生成DbSet
平时我们在使用EF的过程中,都是有DbContext中每一个表加一个DbSet,如果我们一个项目有上千个表,就得加上千个DbSet,是很麻烦的一个工程,现在采用一个简单的方法处理,在DbContext类的OnConfiguring方法中加上如下代码:
protected override void OnModelCreating(ModelBuilder modelBuilder) { var assembly = Assembly.GetExecutingAssembly(); foreach (Type type in assembly.ExportedTypes) { if (type.IsClass && type != typeof(EntityBase) && typeof(EntityBase).IsAssignableFrom(type)) { var method = modelBuilder.GetType().GetMethods().Where(x => x.Name == "Entity").FirstOrDefault(); if (method != null) { method = method.MakeGenericMethod(new Type[] { type }); method.Invoke(modelBuilder, null); } } } base.OnModelCreating(modelBuilder); }
动态加载,不用再一个一个写了,简单方便