您的位置:首页 > 其它

EF里一对一、一对多、多对多关系的配置和级联删除

2016-09-28 15:23 369 查看
http://www.cnblogs.com/oppoic/p/ef_one-to-one_one-to-many_many-to-many_cascadedelete.html

本章节开始了解EF的各种关系。如果你对EF里实体间的各种关系还不是很熟悉,可以看看我的思路,能帮你更快的理解。

I.实体间一对一的关系

添加一个PersonPhoto类,表示用户照片类

View Code
直接复制到数据库执行查询,发现它会返回一条主表数据和两条相关联的从表数据。除非必须查出外键记录才使用Include贪婪加载,否则千万不要,EF中跟手写ado不一样,很容易生成很冗余的sql。这里其实只需要主键的记录就可以了,修改下方法:

    //级联删除(仅加载主键记录)
private static void DeleteDestinationInMemeryAndDbCascade()
{
int destinationId;
using (var context = new CodeFirst.DataAccess.BreakAwayContext())
{
var destination = new CodeFirst.Model.Destination
{
Name = "Sample Destination",
Lodgings = new List<CodeFirst.Model.Lodging>
{
new CodeFirst.Model.Lodging {Name="Lodging One"},
new CodeFirst.Model.Lodging {Name="Lodging Two"}
}
};
context.Destinations.Add(destination);
context.SaveChanges();
destinationId = destination.DestinationId;
}
using (var context = new CodeFirst.DataAccess.BreakAwayContext())
{
var destination = context.Destinations
.Single(d => d.DestinationId == destinationId);  //只取一条主键记录
context.Destinations.Remove(destination);  //然后移除主键记录,外键记录又数据库级联删除
context.SaveChanges();
}
}


监控的sql干干净净,只会查出主表数据。

exec sp_executesql N'SELECT TOP (2)
[Extent1].[DestinationId] AS [DestinationId],
[Extent1].[Name] AS [Name],
[Extent1].[Country] AS [Country],
[Extent1].[Description] AS [Description],
[Extent1].[image] AS [image]
FROM [dbo].[Destinations] AS [Extent1]
WHERE [Extent1].[DestinationId] = @p__linq__0',N'@p__linq__0 int',@p__linq__0=1


补充:这里只查一条记录却使用SELECT TOP (2)... 是保证能查到记录。

删除sql更干净,只删除主表数据,相关联的从表数据删除由数据库级联删除完成:

exec sp_executesql N'delete [dbo].[Destinations]
where ([DestinationId] = @0)',N'@0 int',@0=1


级联删除虽然方便,但是并不常用。试想我们在博客园写了很多随笔,为不同随笔加了不同的标签好区分和管理。某一天突然发现之前定的某个标签并不合理,但是这个标签已经在很多随笔里用了,如果此时删除标签,数据库级联的把标注此标签的随笔都删了,这个肯定不合适。应该是标签删了,之前贴过此标签的文章没了这个标签,这个才符合逻辑。

数据库里可以可视化的设置不级联删除,Fluent API配置此外键关系时可以设置不级联删除:

this.HasMany(d => d.Lodgings).WithRequired(l => l.Destination)
.Map(l => l.MapKey("DestinationId")) //一对多并指定外键名
.WillCascadeOnDelete(false);   // 关闭级联删除


再跑下程序,去看下数据库本外键自然就没了级联删除。

园友郭明锋提供了一个很好的建议:考虑到EF中的级联删除并不常用,所以可以在全局里关掉所有主外键关系的级联删除,如果需要可以打开某个主外键的级联删除。

@郭明锋:好文章,很久没有看到这么好的EF文章了,推荐
EF默认开启级联删除,确实是挺操蛋的设置,所以我的做法是在上下文的OnModelCreating方法中
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
移除这个默认约定,再在需要开启级联删除的FluentAPI关系映射中用. WillCascadeOnDelete(true) 单独开启

ok,本文就到此结束,后续还有更通俗易懂的文章介绍EF,请保持关注。本章源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: