【EF框架】DbContext的使用:
DBComtext使用
DbContext
类是EntityFramework
(简称 EF
)中的一个类,可以理解为一个数据库对象的实例。在EF
中,无需手动的拼接SQL
语句对数据库进行增删改查,而是通过DbContext
来进行相应操作。
DbContext类
DbContext是负责与数据交互作为对象的主要类。DbContext负责以下活动:
(1)EntitySet: DbContext包含映射到数据库表的所有实体的实体集(DbSet )。 (2)查询(Querying): DbContext将LINQ-to-Entities查询转换为SQL查询并将其发送到数据库。 (3)更改跟踪(Change Tracking):跟踪实体在从数据库查询后发生的更改。 (4)持久数据(Persisting Data):它还根据实体的状态对数据库执行插入,更新和删除操作。 (5)缓存(Caching): DbContext默认进行一级缓存。它存储在上下文类生命周期中已经被检索的实体。 (6)管理关系(Manage Relationship): DbContext还使用DB-First或Model-First方法使用CSDL,MSL和SSDL或者使用Code-First方法使用流利的API来管理关系。 (7)对象实现(Object Materialization): DbContext将原始表数据转换为实体对象。EF core跟以前的EF差距非常大,view(视图)无法通过dbfirst生成了,存储过程也一样(虽然我现在开始转codEFirst了)。 然而,如果真的想直接执行sql语句怎么办? 我们发现context下的Database属性跟以前也不一样了,只能做些事务操作,没有执行sql了。可以执行sql的变成了每张具体的表(DbSet)下面的FromSql方法了(需要显式引用Microsoft.EntityFrameworkCore命名空间)。 但是这个方法存在问题,只能返回该表类型的结果,无法返回任意类型。
可以使用linq查询多张表的数据
public ListQueryAUser(){ //定义了上下文实体 excellentmcoinEntities dbcontext = new excellentmcoinEntities(); var allUser = (from u in dbcontext.t_user join g in dbcontext.t_grade on u.gradeID equals g.gradeID orderby u.totalMcoin descending select new userModel() { userID = u.userID, userName = u.userName, userGrade = g.userGrade, totalMcoin = u.totalMcoin, gradeID = g.gradeID, }).ToList(); return allUser;}
EFCore的级联删除(可优化)减少查询
public override async Task> DeleteAsync(Guid Id){ var data = await DbSet.Include(x => x.UserAuthApplyOfDriver) .Include(x => x.UserAuthApplyOfVehicle) .Include(x => x.UserAuthApplyOfEnterprise) .Include(x => x.UserAuthApplyOfLinePrice) .Include(x => x.User) .FirstOrDEFaultAsync(x => x.Id ==Id); if (data.UserAuthApplyOfVehicle != null) { var vehicles = Context.Set ().Where(x => x.UserAuthApplyId == Id); Context.Set ().RemoveRange(vehicles); } if (data.UserAuthApplyOfDriver != null) { var drivers = Context.Set ().Where(x => x.UserAuthApplyId == Id); Context.Set ().RemoveRange(drivers); } if (data.UserAuthApplyOfEnterprise != null) { var enterprises = Context.Set ().Where(x => x.UserAuthApplyId == Id); Context.Set ().RemoveRange(enterprises); } if (data.UserAuthApplyOfLinePrice != null) { var linePrices = Context.Set ().Where(x => x.UserAuthApplyId == Id); Context.Set ().RemoveRange(linePrices); } return await base.DeleteAsync(Id);}
使用FluentAPI
流畅接口是由Martin Fowler和Eric Evans创造的,流畅API意味着你构建一个API需要遵循以下要点:
1.API用户能够容易理解API 2.API为完成一个任务能够执行一系列动作,比如Java中可以看成是一系列方法调用,方法链。 3.每个方法名称应该是与业务领域相关的专门术语 4.API应该能提示指导API用户下一步用什么,以及某个时刻用户可能采取的操作。 参考:
为了更改约定和映射,可以使用 DbContext 类中的 OnModelCreating 方法。
注意 : 数据库将某个字段从不能为空改为可以非空,需要在数据库中去除约束,还得在OnModelCreating
中去除必填代码约束。因为 OnModelCreating
执行的优先级也高
在OnModelCreating方法下使用
public class FluentApiDb:DbContext { public DbSetCourses { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity ().Property(o => o.Title).HasMaxLength(20); } }
新增一个类,在OnModelCreating中引用
public class FluentApiDb:DbContext { public DbSetTeacher { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new TeacherMap()); modelBuilder.Configurations.Add(new StudentMap()); base.OnModelCreating(modelBuilder); } }
通过反射动态加入。利:自动加入,无需人工反复加;弊:影响性能
public class FluentApiDb:DbContext { public DbSetTeacher { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { var typesToRegister = Assembly.GetExecutingAssembly().GetTypes() .Where(type => !String.IsNullOrEmpty(type.Namespace)) .Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDEFinition() == typeof(EntityTypeConfiguration<>)); foreach (var type in typesToRegister) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.Configurations.Add(configurationInstance); } base.OnModelCreating(modelBuilder); } }
FluentAPI详细用法
- 设置主键
cs modelBuilder.Entity<x>().HasKey(t => t.Name);
- 设置联合主键
cs modelBuilder.Entity<x>().HasKey(t =>new{t.Name,t.ID} );
- 取消数据库字段标识(取消自动增长)
cs modelBuilder.Entity<x>().Property(t=>t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
- 设置数据库字段标识(自动增长)
cs modelBuilder.Entity<Teacher>().Property(t =>t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
设置字段最大长度
modelBuilder.Entity
().Property(t => t.Name).HasMaxLength(100); - 设置字段为必需
cs modelBuilder.Entity<ClassA>().Property(t =>t.Id).IsRequired();
属性不映射到数据库
modelBuilder.Entity
().Ignore(t => t.A); - 将属性指定数据库列名:
cs modelBuilder.Entity<ClassA>() .Property(t => t.A) .HasColumnName("A_a");
- 级联删除(数据库默认是不级联删除的)
cs modelBuilder.Entity<Course>().HasRequired(t => t.Department).WithMany(t => t.Courses).HasForeignKey(d => d.DepartmentID).WillCascadeOnDelete();
- 设置为Timestamp
cs modelBuilder.Entity<OfficeAssignment>() .Property(t => t.Timestamp) .IsRowVersion();
表1对0..1(Instructor实体可以包含零个或一个OfficeAssignment)
modelBuilder.Entity
().HasRequired(t => t.Instructor).WithOptional(t => t.OfficeAssignment); - 表1对1
cs modelBuilder.Entity<Instructor>().HasRequired(t => t.OfficeAssignment).WithRequiredPrincipal(t => t.Instructor);
- 表1对n(Department为主表)
cs modelBuilder.Entity<Staff>() .HasRequired(c => c.Department) .WithMany(t => t.Staffs)
- 指定外键名(指定表Staff中的字段DepartmentID为外键)
cs modelBuilder.Entity<Staff>() .HasRequired(c => c.Department) .WithMany(t => t.Staffs) .Map(m => m.MapKey("DepartmentID"));
- 表n对n
cs modelBuilder.Entity<Course>() .HasMany(t => t.Instructors) .WithMany(t => t.Courses)
表n对n指定连接表名及列名
cs modelBuilder.Entity<Course>() .HasMany(t => t.Instructors) .WithMany(t => t.Courses) .Map(m => { m.ToTable("CourseInstructor"); m.MapLEFtKey("CourseID"); m.MapRightKey("InstructorID"); });
参考:
EF Core中如何正确地设置两张表之间的关联关系: 官方文档: 翻译官方文档: