• [转]Entity Framework 的实体关系


    通过 Entiy Framework实践系列 文章,理了理 Entity Framework 的实体关系。

    为什么要写文章来理清这些关系?“血”的教训啊,刚开始使用 Entity Framework 的时候,由于没有静下心来认真理清关系,走了一些"痛不欲生"的弯路。而我们目前开发的项目都在使用 Entity Framework,为了避免其他人再经历"痛不欲生"的弯路。于是下定决心边“理清关系”边“写博客”。而写博客可以逼着自己把问题完整地解决,避免半 途而废。当写出这些文章,自己不知不觉对问题有了更深的理解。

    温故而知新,通过这篇总结将自己对EF实体关系的理解回锅热一热,也许会有新的收获;感情也一样,当感情冷下来的时候,别忘了回锅热一热。

    1. 一对一关系(one-to-one)

    a) 单向一对一(文章链接

    类图:

    数据库表结构:

    Entity Framework中实体关系的定义:

    modelBuilder.Entity<BlogSite>()
    .HasRequired(b => b.BlogUser)
    .WithMany()
    .HasForeignKey(b => b.UserID);

    b) 双向一对一(文章链接

    类图:

    数据库表结构:

    Entity Framework中实体关系的定义:

    复制代码
    modelBuilder.Entity<BlogSite>()
    .HasRequired(b => b.BlogUser)
    .WithMany()
    .HasForeignKey(b => b.UserID);

    modelBuilder.Entity<BlogUser>()
    .HasRequired(u => u.BlogSite)
    .WithMany()
    .HasForeignKey(u => u.BlogID);
    复制代码


    2. 一对多关系(one-to-many,文章链接

    类图:

    数据库表结构:

    Entity Framework中实体关系的定义:

    modelBuilder.Entity<BlogSite>()
    .HasMany(b => b.BlogPosts)
    .WithRequired(p => p.BlogSite);


    3. 多对多关系(many-to-many,文章链接

    类图:

    数据库表结构:

    Entity Framework中实体关系的定义:

    复制代码
    modelBuilder.Entity<BlogPost>()
    .HasMany(b => b.Categories)
    .WithMany(c => c.BlogPosts)
    .Map
    (
    m =>
    {
    m.MapLeftKey("BlogPostID");
    m.MapRightKey("CategoryID");
    m.ToTable("BlogPost_Category");
    }
    );
    复制代码
     
     
    -------------------------------

    HasMany() = (1..*), HasOptional() = (1..0,1), HasRequired() = (1..1)

    -------------------------------

    在演示Fluent API如何配置Person类和PersonPhoto的一对一关系之前,先系统的学习下EF里实体关系配置的方法。EF里的实体关系配置分为Has和With系列的方法:Optional 可选的、Required 必须的、Many 多个。举例:

    A.HasRequired(a => a.B).WithOptional(b => b.A);

    这里的a=>a.B是lambda表示写法,就是找到A类里的导航属性B。命名a不固定,可以随意,q=>q.B也是可以的。但是B是A类的属性,故习惯用小写a。

    Has方法:

    1. HasOptional:前者包含后者一个实例或者为null
    2. HasRequired:前者(A)包含后者(B)一个不为null的实例
    3. HasMany:前者包含后者实例的集合

    With方法:

    1. WithOptional:后者(B)可以包含前者(A)一个实例或者null
    2. WithRequired:后者包含前者一个不为null的实例
    3. WithMany:后者包含前者实例的集合

    摘自这里 这是较为好的理解方式。上面一句配置意思就是A类包含B类一个不为null的实例,B类包含A类一个实例,也可以不包含。最标准的一对一配置。ok,现在试着写下上面Person类和PersonPhoto类的一对一的关系如何配置:

    this.HasRequired(p => p.PhotoOf).WithOptional(p => p.Photo);

    再跑下程序,数据库就生成了,是一对一的关系。Person表可以没有对应的PersonPhoto表数据,但是PersonPhoto表每一条数据都必须对应一条Person表数据。意思就是人可以没有照片,但是有的照片必须属于某个人。关系配置是这样的效果,其实可以随便改,也可以配置成每个人都必须有对应的照片。把上面的WithOptional改成WithRequired,对应到数据库里就是null变成了not null。

    数据库里可以可视化的设置不级联删除,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) 单独开启
  • 相关阅读:
    Android拍照、摄像方向旋转的问题 代码具体解释
    Java 实现桥接(Bridge)模式
    C++标准I/O库:iostream, fstream, sstringstream
    Android 使用 DownloadManager 管理系统下载任务的方法
    JavaScript提高:005:ASP.NET使用easyUI TABS标签显示问题
    使用c++的cocos2d-x-3.0rc1程序公布apk
    UVA 146 ID Codes(下一个排列)
    C/C++:C++伪函数
    开源项目AndroidUtil-採用Fragment实现TabHost
    系统编程是什么
  • 原文地址:https://www.cnblogs.com/luohengstudy/p/6225091.html
Copyright © 2020-2023  润新知