100分求解 EF CodeFirst 环境下外键关联和独立关联的问题

xaugust2014 2014-09-30 10:30:48
在CodeFirst实体定义时,Model中可以不显示定义外键属性,由EF约定默认生成外键列,如 主类名_ID
显示指定外键属性与不显示除了生成数据表的外键列名有些区别外,其它似乎一样,但实际上在EF中,这两种方式还是有些区别的

假设有一个Paper文章类和ReaderA和ReaderB两种读者类,其中ReaderA中显示指定了外键属性,而ReaderB中使用仅有导航属性


//文章
public class Paper
{
public Paper()
{
ReaderAs = new HashSet<ReaderA>();
ReaderBs = new HashSet<ReaderB>();
}

public int ID { get; set; }

public string Title { get; set; }

public virtual ICollection<ReaderA> ReaderAs { get; set; }

public virtual ICollection<ReaderB> ReaderBs { get; set; }

}

//A类读者
public class ReaderA
{
public int ID { get; set; }

public string Name { get; set; }

public int? PaperID { get; set; }

public Paper Paper { get; set; }
}

//B类读者
public class ReaderB
{
public int ID { get; set; }

public string Name { get; set; }

public Paper Paper { get; set; }
}


数据访问代码如下:


Paper paper = new Paper
{
Title = "paper01"
};

ReaderA readerA = new ReaderA
{
Name = "readerA"
};

ReaderB readerB = new ReaderB
{
Name = "readerB"
};


paper.ReaderAs.Add(readerA);
paper.ReaderBs.Add(readerB);

dbContext.Papers.Add(paper);

dbContext.SaveChanges();

Debug.WriteLine("ReaderA:{0}", dbContext.Entry<ReaderA>(readerA).State);
Debug.WriteLine("ReaderB:{0}", dbContext.Entry<ReaderB>(readerB).State);
Debug.WriteLine("");

readerA.Paper = null;
//readerA.PaperID = null; //the same
readerB.Paper = null;

//dbContext.ChangeTracker.DetectChanges(); //the same

Debug.WriteLine("ReaderA:{0}", dbContext.Entry<ReaderA>(readerA).State);
Debug.WriteLine("ReaderB:{0}", dbContext.Entry<ReaderB>(readerB).State);
Debug.WriteLine("");

Console.WriteLine("press any key to save");
Console.ReadKey();

dbContext.SaveChanges();


输出结果如下:
ReaderA:Unchanged
ReaderB:Unchanged

ReaderA:Modified
ReaderB:Unchanged

对于显示指定了外键属性的类ReaderA,通过置外键属性或导航属性来更改关系时,对象的State由会发生改变,而对于仅使用导航属性的类,通导航属性来更改关系时,对象的状态不会发生变化
但令人费解的是,虽然对象状态没有发生变化,但之后的SaveChange调用的行为readerA和readerB几乎一样,外键列都被置NULL了


exec sp_executesql N'UPDATE [dbo].[ReaderA]
SET [PaperID] = NULL
WHERE ([ID] = @0)
',N'@0 int',@0=1

exec sp_executesql N'UPDATE [dbo].[ReaderB]
SET [Paper_ID] = NULL
WHERE (([ID] = @0) AND ([Paper_ID] = @1))
',N'@0 int,@1 int',@0=1,@1=1


SaveChanges不是依赖对象State来进行执行操作吗,为什么会这样呢
...全文
716 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
沫沫1023 2016-05-25
  • 打赏
  • 举报
回复
楼主问题最后解决了吗?也遇见同样问题了,求教
xaugust2014 2014-10-14
  • 打赏
  • 举报
回复

                readerA.Paper = null; //the same
                //readerA.PaperID = null;
                readerB.Paper = null;
                //readerB.Name = "fucking";

                //dbContext.ChangeTracker.DetectChanges(); //the same

                Debug.WriteLine("ReaderA:{0}", dbContext.Entry<ReaderA>(readerA).State);
                Debug.WriteLine("ReaderB:{0}", dbContext.Entry<ReaderB>(readerB).State);
                Debug.WriteLine("");

                var objContext = ((IObjectContextAdapter)dbContext).ObjectContext;
                Debug.WriteLine("ReaderA:{0}", objContext.ObjectStateManager.GetObjectStateEntry(readerA).State);
                Debug.WriteLine("ReaderB:{0}", objContext.ObjectStateManager.GetObjectStateEntry(readerB).State);
                Debug.WriteLine("");

                Console.WriteLine("press any key to save");
                Console.ReadKey();
试过了,使用ObjectContet获取到的状态和DBContext一样 ReaderA_db:Modified ReaderB_db:Unchanged ReaderA_obj:Modified ReaderB_obj:Unchanged 我就纳闷了,EF是到底是跟踪到变化的呢,求正解
threenewbee 2014-09-30
  • 打赏
  • 举报
回复
你显式定义了外键,那么为了防止并发冲突,EF就会判断一下,否则EF会让对外键的操作透明。
jshi123 2014-09-30
  • 打赏
  • 举报
回复
DbChangeTracker不公开一对多独立关联的变更状态。 可以把DbContext转换成ObjectContext,然后通过调用 ObjectStateManager 的 ObjectStateEntries 来判断独立关联的变更情况。 http://stackoverflow.com/questions/5809620/dbcontexts-changetracker-problem
xaugust2014 2014-09-30
  • 打赏
  • 举报
回复
readerB.Paper = null;后ReaderB的State是Unchanged,在这种情况在调用SaveChanges,为什么会更新数据库呢
xaugust2014 2014-09-30
  • 打赏
  • 举报
回复
关键是SaveChanges不是依赖对象State来进行执行操作吗,为什么ReaderB明明是Unchanged,也会更新数据库呢
帅得_被人砍 2014-09-30
  • 打赏
  • 举报
回复
版主说的有理噢

62,025

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧