EF Core 笔记

回滚最近的一次迁移记录

remove-migration    会报错

加参数remove-migration --force 

一个程序集下面存在多个DbContext   指定DbContext进行迁移

add-migration --context XXXDbContext

一个事务中    先在数据库查出一条数据进行修改      然后在进行查询  他会直接在内存中找到这条数据  不会再数据库查询了

EF Core的 linq语句中可以使用C#方法或函数   在EF6或之前版本不可以

.Include()  在EF Core和 EF6中支持lamada表达式  之前的版本该方法只接受列名字符串

 使用原生sql

 FormSql已弃用

        using (var dataContext = new SampleDbContext()) {
        
            var query = dataContext.Categories.FromSqlRaw("select * from Category");

            var result = query.ToList();
        }

通过这种方式拼接sql  会自动拼接成带参数的sql语句

 var query = dataContext.Categories.FromSql($"select * from Category where CategoryID={categoryID}");

执行存储过程

 var query = dataContext.Categories.FromSql($"GetCategoryById {categoryID}");

配置一对一关系   在EF6.X或之前不支持     

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
       
    public StudentAddress Address { get; set; }
}

public class StudentAddress
{
    public int StudentAddressId { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Country { get; set; }

    public int StudentId { get; set; }
    public Student Student { get; set; }
}

在Student表中自动产生一个AddressId列    

   订单行关联订单头可以省略前两行代码     直接写最后一行

    public class SalesOrderLine : Entity<Guid>
    {
        /// <summary>
        /// 销售订单ID
        /// </summary>
        public virtual Guid? SalesOrderId { set; get; }
        /// <summary>
        /// 销售订单
        /// </summary>
        [ForeignKey(nameof(SalesOrderId))]
        public virtual SalesOrder SalesOrder { set; get; }

EF中已经有了默认的约定来实现一对多  如果想要自己写 可以扩展 Fluent API    这些一对多的配置在EF约定中就已经实现了  不需要自己配置    可以通过这个配置来实现级联删除

            //配置订单头实体和订单行实体的关系
            modelBuilder.Entity<SalesOrder>()
                //订单头实体对象包含了 多个的订单行
                .HasMany<SalesOrderLine>(t => t.Lines)
                //订单行实体对象包含了 唯一的个订单头
                .WithOne(g => g.SalesOrder)
                //通过行的SalesOrderId属性进行关联
                .HasForeignKey(g => g.SalesOrderId);

            //反过来配置
            modelBuilder.Entity<SalesOrderLine>()
                //订单行实体对象包含了 唯一的订单头
                .HasOne<SalesOrder>(t => t.SalesOrder)
                //订单头实体对象包含了 多个订单行
                .WithMany(g => g.Lines)
                //通过行的SalesOrderId属性进行关联
                .HasForeignKey(t => t.SalesOrderId);

 级联删除

            //级联删除
            //前面的配置都一样   只要在最后加上OnDelete
            modelBuilder.Entity<SalesOrder>()
                .HasMany<SalesOrderLine>(t => t.Lines)
                .WithOne(g => g.SalesOrder)
                .HasForeignKey(g => g.SalesOrderId)
                .OnDelete(DeleteBehavior.Cascade);
            //Cascade  删除主实体时将删除从属实体
            //ClientSetNull 删除主实体时将从属实体的的外键属性值设置为null
            //Restrict  防止级联删除
            //SetNull   删除主实体时将从属实体的的外键属性值设置为null

 多对多的关系只能自己配置

 Entity Framework Core中没有可自动配置多对多关系的默认约定。您必须使用Fluent API对其进行配置。 

学生表
public
class Student { public int StudentId { get; set; } public string Name { get; set; } public IList<StudentCourse> StudentCourses { get; set; } } 课程表 public class Course { public int CourseId { get; set; } public string CourseName { get; set; } public string Description { get; set; } public IList<StudentCourse> StudentCourses { get; set; } }
//通过一张中间表来实现学生跟课程的多对多关系
public
class StudentCourse { public int StudentId { get; set; } public Student Student { get; set; } public int CourseId { get; set; } public Course Course { get; set; } }
关系配置
modelBuilder.Entity<StudentCourse>().HasKey(sc => new { sc.StudentId, sc.CourseId });

 获取当前跟踪的所有实体

context.ChangeTracker.Entries()

可以使用 FromSql 扩展方法基于原生 SQL 查询开始 LINQ 查询。

var blogs = context.Blogs
    .FromSql("SELECT * FROM dbo.Blogs")
    .ToList();

原生 SQL 查询可用于执行存储过程。

var blogs = context.Blogs
    .FromSql("EXECUTE dbo.GetMostPopularBlogs")
    .ToList();

 单独配置给某一个实体添加租户过滤和软删除过滤

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>().Property<string>("TenantId").HasField("_tenantId");

    // Configure entity filters
    modelBuilder.Entity<Blog>().HasQueryFilter(b => EF.Property<string>(b, "TenantId") == _tenantId);
    modelBuilder.Entity<Post>().HasQueryFilter(p => !p.IsDeleted);
}

指定当前实体框架Linq查询不应用任何模型级实体查询筛选器。 不应用配置的软删除过滤和租户过滤 

blogs = db.Blogs
    .Include(b => b.Posts)
    .IgnoreQueryFilters()
    .ToList();

 程序和数据库中对应类型

关于在ABP中 是否手动写await customerRepository.UpdateAsync(cc); 更新这行代码的测试     (不写EF会自动监测到所有修改的字段  进行更新 ,  写了会更新所有字段)

1.不写这行代码  让事务自动提交

  在数据库监控日志中会产生两条sql语句记录    一条是查询  一条是更新  更新的语句只更新修改过的字段

2.写了这行代码

  在数据库监控日志中只有一条sql语句记录  查询和更新是在一起的  但是更新了所有字段

关于ef的迁移文件

add-migration   通过对比DBContext中的实体和总快照文件来生成迁移文件  

update-database  会查询__EFMigrationsHistory表中的迁移记录  知道了最后一次迁移记录   把这次一次之后的所有迁移文件都执行一遍

ModelSnapshot迁移快照文件   每次通过add-migration生成新的迁移文件的时候  会对比dbContext中的实体跟快照中的记录   以这个为标准来产生新的迁移文件

迁移文件 :通过对比DBContext中的实体和快照文件来生成迁移文件  

  当前迁移文件中有两个方法:一个是Up  Up就是使用update-database是执行的代码段       Down是回滚迁移文件执行的代码段     Up跟Down的的代码段肯定是相反的      比如在Up中新增一张表    在Down中就是删除这张表

迁移文件下面还有一个.Designer的文件    执行当前迁移文件后的快照文件

创建新库的时候: 因为不存在迁移记录表  所以会把所有迁移文件按顺序执行一遍    如果有丢失的迁移文件  则可能报错  迁移失败

修改库:找到当前迁移表中记录的迁移文件  执行在这之后新增的所有迁移文件

自动迁移

dbContext.Database.EnsureCreated();//不存在数据库则执行迁移  不执行更新操作

dbContext.Database.Migrate();每次都执行迁移文件  有最新就更新

https://docs.microsoft.com/zh-cn/ef/core/saving/cascade-delete

http://www.entityframeworktutorial.net/efcore/querying-in-ef-core.aspx

原文地址:https://www.cnblogs.com/jiangchengbiao/p/10272217.html