假设在数据库中有两个表:Person表和Book表,Person和Book是一对多关系

Person表数据:

Book表数据:

可以看到数据库Book表中所有的数据都属于Person表中"F"这个人

Person表,下面的Person类是该表在EF Core中的实体类型:

public partial class Person
{
public Person()
{
Book = new HashSet<Book>();
} public int Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public DateTime? CreateTime { get; set; }
public DateTime? UpdateTime { get; set; } public ICollection<Book> Book { get; set; }
}

因为一个Person对应多个Book,所以Person类中有个集合属性public ICollection<Book> Book { get; set; }

此外Person类的Code属性为EF Core中实体的Key属性:

modelBuilder.Entity<Person>(entity =>
{
entity.HasKey(e => e.Code);//设置Code为EF Core实体Person的Key属性 entity.HasIndex(e => e.Code)
.HasName("IX_Person")
.IsUnique(); entity.Property(e => e.Id).HasColumnName("ID"); entity.Property(e => e.Code)
.IsRequired()
.HasMaxLength(); entity.Property(e => e.CreateTime)
.HasColumnType("datetime")
.HasDefaultValueSql("(getdate())"); entity.Property(e => e.Name).HasMaxLength(); entity.Property(e => e.UpdateTime).HasColumnType("datetime");
});

Book表,下面的Book类是该表在EF Core中的实体类型:

public partial class Book
{
public int Id { get; set; }
public string BookCode { get; set; }
public string BookName { get; set; }
public string PersonCode { get; set; } public Person PersonCodeNavigation { get; set; }
}

同样因为一个Book只对应一个Person,所以Book类中有个导航属性public Person PersonCodeNavigation { get; set; }

此外Book类的BookCode属性为EF Core中实体的Key属性:

modelBuilder.Entity<Book>(entity =>
{
entity.HasKey(e => e.BookCode);//设置BookCode为EF Core实体Book的Key属性 entity.Property(e => e.Id).HasColumnName("ID");
entity.Property(e => e.Id).ValueGeneratedOnAddOrUpdate(); entity.Property(e => e.BookCode).HasMaxLength(); entity.Property(e => e.BookName).HasMaxLength(); entity.Property(e => e.PersonCode).HasMaxLength(); entity.HasOne(d => d.PersonCodeNavigation)
.WithMany(p => p.Book)
.HasPrincipalKey(p => p.Code)
.HasForeignKey(d => d.PersonCode)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_Book_Person");
});

现在假如我们想通过new一个Book b3,然后在Person类的集合属性Book中来删除b3,结果数据库Book表中的数据并不会被删除,原因见下面注释:

using (TestDBContext testDBContext = new TestDBContext())
{
var person = testDBContext.Person.Where(P => P.Code == "F").Include(p => p.Book).First(); Book b3 = new Book() { BookCode = "B3" }; var f = person.Book.Remove(b3);//不起作用,结果BookCode为"B3"的数据并没有从数据库Book表中删除,这是因为我们在上面的testDBContext.Person.Where(P => P.Code == "F").Include(p => p.Book).First()中调用了Include方法,导致BookCode为"B3"的实体已经被加载到EF Core的DbContext中被Track了,这时上面一行的Book b3 = new Book() { BookCode = "B3" }其BookCode也为"B3",Book b3将无法在person.Book.Remove(b3)时被Attach到DbContext内进行Track,因为DbContext中被Track的实体必须是Key属性值唯一的,前面已经有一个BookCode为"B3"实体实例在DbContext中了,就无法再加入另一个BookCode为"B3"的实体实例了,所以删除不会起任何作用。
//此外这里的删除不起作用还有个很重要的原因,那就是person.Book.Remove(b3)方法会先尝试在位于内存中的person.Book集合中匹配Book b3,但是由于Book b3是我们自己new出来的,它和person.Book中的集合成员指向的是不同的Book对象实例,所以Book b3无法和person.Book中的任何集合成员匹配,尽管它们的Key属性BookCode都为"B3"。由于Book b3和person.Book的集合成员匹配都失败了,那么person.Book.Remove(b3)不会删除数据库中的任何数据,只有当以Book b3和person.Book的一个集合成员匹配成功时,person.Book.Remove(b3)才会在数据库中删除对应的数据。 testDBContext.SaveChanges();
}

接下来,我们通过从Person.Book集合中找出BookCode为"B3"的实体实例赋值给Book b3,然后从Person.Book集合中再删除该实例,这次我们会发现数据库Book表中的数据就被删除了,原因见下面注释:

using (TestDBContext testDBContext = new TestDBContext())
{
var person = testDBContext.Person.Where(P => P.Code == "F").Include(p => p.Book).First(); Book b3 = person.Book.First(b => b.BookCode == "B3"); EntityState s = testDBContext.Entry(b3).State;//状态为EntityState.Unchanged var f = person.Book.Remove(b3);//起作用,因为这时上面一行的Book b3指向的就是testDBContext.Person.Where(P => P.Code == "F").Include(p => p.Book).First()中Include方法加载的实体实例,所以相当于Book b3已经被加载到EF Core的DbContext中被Track了,所以这里调用person.Book.Remove(b3)之后Book b3的State将被标记为EntityState.Deleted,然后执行下面的testDBContext.SaveChanges()后,从数据库Book表中将BookCode为 "B3"的数据行删除掉 s = testDBContext.Entry(b3).State;//状态为EntityState.Deleted testDBContext.SaveChanges();
}

注意采用Person.Book集合删除Book b3这种方式,会根据EF Core中DeleteBehavior的不同设置会有不同的结果,因为本例中我们设置了DeleteBehavior.Cascade,所以EF Core会从数据库Book表中将BookCode为 "B3"的数据行删除掉,但是如果采用DeleteBehavior的其它设置,那么会得到不同的结果,详情可以查看:Cascade Delete

最后我们来看看new一个Book b3,通过DbContext的DbSet属性来删除b3,同样这次数据库Book表中的数据也会被成功删除,原因见下面注释:

using (TestDBContext testDBContext = new TestDBContext())
{
Book b3 = new Book() { BookCode = "B3" }; EntityState s = testDBContext.Entry(b3).State;//状态为EntityState.Detached
var f = testDBContext.Book.Remove(b3);//起作用,因为testDBContext.Book.Remove(b3)是通过DbContext的DbSet<Book>属性来删除数据的,在此之前也没有BookCode为"B3"的实体实例被加载到DbContext进行Track,所以这里调用testDBContext.Book.Remove(b3)会把Book b3加载到DbContext进行Track,并将Book b3的State标记为EntityState.Deleted,然后执行下面的testDBContext.SaveChanges()后,从数据库Book表中将BookCode为 "B3"的数据行删除掉 s = testDBContext.Entry(b3).State;//状态为EntityState.Deleted testDBContext.SaveChanges();
}

EF Core中如何通过实体集合属性删除从表的数据的更多相关文章

  1. EF Core中,通过实体类向SQL Server数据库表中插入数据后,实体对象是如何得到数据库表中的默认值的

    我们使用EF Core的实体类向SQL Server数据库表中插入数据后,如果数据库表中有自增列或默认值列,那么EF Core的实体对象也会返回插入到数据库表中的默认值. 下面我们通过例子来展示,EF ...

  2. EF Core中怎么实现自动更新实体的属性值到数据库

    我们在开发系统的时候,经常会遇到这种需求数据库表中的行被更新时需要自动更新某些列. 数据库 比如下面的Person表有一列UpdateTime,这列数据要求在行被更新后自动更新为系统的当前时间. Pe ...

  3. [小技巧]EF Core中如何获取上下文中操作过的实体

    原文地址:https://www.cnblogs.com/lwqlun/p/10576443.html 作者:Lamond Lu 源代码:https://github.com/lamondlu/EFC ...

  4. EF Core 中多次从数据库查询实体数据,DbContext跟踪实体的情况

    使用EF Core时,如果多次从数据库中查询一个表的同一行数据,DbContext中跟踪(track)的实体到底有几个呢?我们下面就分情况讨论下. 数据库 首先我们的数据库中有一个Person表,其建 ...

  5. EF Core 中DbContext不会跟踪聚合方法和Join方法返回的结果,及FromSql方法使用讲解

    EF Core中: 如果调用Queryable.Count等聚合方法,不会导致DbContext跟踪(track)任何实体. 此外调用Queryable.Join方法返回的匿名类型也不会被DbCont ...

  6. EF Core中如何正确地设置两张表之间的关联关系

    数据库 假设现在我们在SQL Server数据库中有下面两张表: Person表,代表的是一个人: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ...

  7. EF Core 2.0 已经支持自动生成父子关系表的实体

    现在我们在SQL Server数据库中有Person表如下: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ) NULL, ) NULL, [Cr ...

  8. EF Core 三 、 骚操作 (导航属性,内存查询...)

    EF Core 高阶操作 本文之前,大家已经阅读了前面的系列文档,对其有了大概的了解 我们来看下EF Core中的一些常见高阶操作,来丰富我们业务实现,从而拥有更多的实现选择 1.EF 内存查找 wh ...

  9. EF Core中避免贫血模型的三种行之有效的方法(翻译)

    Paul Hiles: 3 ways to avoid an anemic domain model in EF Core 1.引言 在使用ORM中(比如Entity Framework)贫血领域模型 ...

随机推荐

  1. python decode和encode

    摘抄: 字符串在Python内部的表示是Unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符解码(decode)成unicode,再从unicode编码 ...

  2. VUE的两种跳转push和replace对比区别

    router.push(location) 在vue.js中想要跳转到不同的 URL,需要使用 router.push 方法. 这个方法会向 history 栈添加一个新的记录,当用户点击浏览器后退按 ...

  3. nodejs的get与post

    index.html <html> <body> <form action="/api/v1/records" method="post&q ...

  4. Docker 简单运用

    Docker 帮助系统管理员和程序员在容器中开发应用程序,并且可以扩展到成千上万的节点,容器和 VM(虚拟机)的主要区别是,容器提供了基于进程的隔离,而虚拟机提供了资源的完全隔离.虚拟机可能需要一分钟 ...

  5. linux下通过NFS将远程磁盘mount到本地

    最近由于项目原因需要和其他两家公司对接,需要取对方服务器中的图像数据,原本约定是三方都通过http协议来进行通讯,奈何对接方不配合,说文件就在他们服务器放着,怎么取他们不管.所以采取将对方服务器磁盘挂 ...

  6. Sqlite 数据库分页查询(ListView分页显示数据)

    下面介绍一下我的这个demo. 流程简述: 我在raw文件夹下面放了名称为city的数据库,里面包含全国2330个城市,以及所属省,拼音简写等信息. 首先 在进入MainActivity的时候,创建数 ...

  7. 【Udacity】数据的集中程度:众数、平均数和中位数

    重视Code Review 极致--目标是成为优秀的开发者 Data tells a story!(数据会讲故事) 分析过程对于建模非常的重要,可以帮助我们减少实际上不相关的特征被错误的加入到模型中, ...

  8. 二维数组中的查找(C++和Python实现)

    (说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列 ...

  9. Mysql 优化配置2

    服务器物理硬件的优化 来源社区,个人作为收集 在挑选硬件服务器时,我们应该从下面几个方面着重对MySQL服务器的硬件配置进行优化,也就是说将项目中的资金着重投入到如下几处: 1.磁盘寻道能力(磁盘I/ ...

  10. C++11标准之右值引用(rvalue reference)

    1.右值引用引入的背景 临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题.但是C++标准允许编译器对于临时对象的产生具有完全的自由度,从而发展出了Copy Elision.RVO(包 ...