一.One-to-One Relationship【一对一关系】

两个表之间,只能由一个记录在另外一个表中。每一个主键的值,只能关联到另外一张表的一条或者零条记录。请记住,这个一对一的关系不是非常的普遍,并且大多数的一对一的关系,是商业逻辑使然,并且数据也不是自然地。缺乏这样一条规则,就是在这种关系下,你可以把两个表合并为一个表,而不打破正常化的规则。

为了理解一对一关系,我们创建两个实体,一个是User另外一个是UserProfile,一个User只有单个Profile,User表将会有一个主键,并且这个字段将会是UserProfile表的主键和外键。我们看下图:

创建两个实体,一个是User实体,另外一个是UserProfile实体。我们的User实体的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EF.Core.Data
{
public class User:BaseEntity
{
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; } /// <summary>
/// 电子邮件
/// </summary>
public string Email { get; set; } /// <summary>
/// 密码
/// </summary>
public string Password { get; set; } /// <summary>
/// 导航属性--用户详情
/// </summary>
public virtual UserProfile UserProfile { get; set; }
}
}

  

UserProfile实体的代码快如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace EF.Core.Data
{
/// <summary>
/// 用户详情实体
/// </summary>
public class UserProfile:BaseEntity
{
/// <summary>
/// 姓
/// </summary>
public string FirstName { get; set; } /// <summary>
/// 名
/// </summary>
public string LastName { get; set; } /// <summary>
/// 地址
/// </summary>
public string Address { get; set; } /// <summary>
/// 导航属性--User
/// </summary>
public virtual User User { get; set; }
}
}

  

就像你看到的一样,上面的两个部分的代码块中,每个实体都使用彼此的实体,作为导航属性,因此你可以从任何实体中访问另外的实体。

使用Fluent Api配置Users实体:

using EF.Core.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EF.Data.Mapping
{
public class UserMap:EntityTypeConfiguration<User>
{
public UserMap()
{
//配置主键
this.HasKey(s => s.ID); //给ID配置自动增长
this.Property(s => s.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
//配置字段
this.Property(s => s.UserName).IsRequired().HasColumnType("nvarchar").HasMaxLength(25);
this.Property(s => s.Email).IsRequired().HasColumnType("nvarchar").HasMaxLength(25);
this.Property(s => s.AddedDate).IsRequired();
this.Property(s => s.ModifiedDate).IsRequired();
this.Property(s => s.IP); //配置表
this.ToTable("User"); }
}
}

  

使用Fluent Api配置UserProfile实体

using EF.Core.Data;
using System;
using System.Collections.Generic;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EF.Data.Mapping
{
public class UserProfileMap:EntityTypeConfiguration<UserProfile>
{
public UserProfileMap()
{
this.HasKey(s=>s.ID); this.Property(s => s.FirstName).IsRequired();
this.Property(s => s.LastName).IsRequired();
this.Property(s => s.Address).HasMaxLength(100).HasColumnType("nvarchar").IsRequired(); this.Property(s => s.AddedDate).IsRequired();
this.Property(s => s.ModifiedDate).IsRequired();
this.Property(s => s.IP); //配置关系[一个用户只能有一个用户详情!!!]
this.HasRequired(s => s.User).WithRequiredDependent(s => s.UserProfile); this.ToTable("UserProfile"); }
}
}

  

现在,我们创建一个数据库上下文类EFDbContext,这个类继承DbContext类,在这个数据库上下文类中,我们重写OnModelCreating方法,这个OnModelCreating方法,在数据库上下文(EFDbContext)已经初始化的完成的时候,被调用,在OnModelCreating方法中,我们使用了反射,来为每个实体生成配置类。

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace EF.Data
{
public class EFDbContext:DbContext
{
public EFDbContext()
: base("name=DbConnectionString")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
{
var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(type => type.BaseType != null && type.BaseType.IsGenericType
&& type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
base.OnModelCreating(modelBuilder);
} }
}
}

  

二.One-to-Many Relationship【一对多关系】

主键表的一个记录,关联到关联表中,存在,没有,或者有一个,或者多个记录。这是最重要的也是最常见的关系
为了更好的理解一对多的关系,可以联想到电子商务系统中,单个用户可以下很多订单,所以我们定义了两个实体,一个是客户实体,另外一个是订单实体。我们看看下面的图片:

实体Customers代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EF.Core.Data
{
public class Customer:BaseEntity
{
/// <summary>
/// 客户名称
/// </summary>
public string Name { get; set; } /// <summary>
/// 客户电子邮件
/// </summary>
public string Emial { get; set; } /// <summary>
/// 导航属性--Order
/// </summary>
public virtual ICollection<Order> Orders { get; set; }
}
}

  

实体Orders代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace EF.Core.Data
{
public class Order:BaseEntity
{
/// <summary>
/// 数量
/// </summary>
public byte Quantity { get; set; } /// <summary>
/// 价格
/// </summary>
public decimal Price { get; set; } /// <summary>
/// 客户ID
/// </summary>
public int CustomerId { get; set; } /// <summary>
/// 导航属性--Customer
/// </summary>
public virtual Customer Customer { get; set; }
}
}

  

你已经在上面的代码中注意到了导航属性,Customer实体有一个集合类型的Order属性,Order实体有一个Customer实体的导航属性,也就是说,一个客户可以有很多订单。
使用Fluent Api配置Customer实体
using EF.Core.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EF.Data.Mapping
{
public class CustomerMap:EntityTypeConfiguration<Customer>
{
public CustomerMap()
{
this.HasKey(s => s.ID);
//properties
Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(t => t.Name);
Property(t => t.Email).IsRequired();
Property(t => t.AddedDate).IsRequired();
Property(t => t.ModifiedDate).IsRequired();
Property(t => t.IP); //table
ToTable("Customers");
}
}
}

  

使用Fluent Api配置Orders实体
using EF.Core.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EF.Data.Mapping
{
public class OrderMap:EntityTypeConfiguration<Order>
{
public OrderMap()
{
this.HasKey(s=>s.ID);
//fields
Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(t => t.Quanatity).IsRequired().HasColumnType("tinyint");
Property(t => t.Price).IsRequired();
Property(t => t.CustomerId).IsRequired();
Property(t => t.AddedDate).IsRequired();
Property(t => t.ModifiedDate).IsRequired();
Property(t => t.IP); //配置关系【一个用户有多个订单,外键是CusyomerId】
this.HasRequired(s => s.Customer).WithMany(s => s.Orders).HasForeignKey(s => s.CustomerId).WillCascadeOnDelete(true); //table
ToTable("Orders");
}
}
}

  

上面的代码表示:用户在每个Order中是必须的,并且用户可以下多个订单,两个表之间通过外键CustomerId联系,我们使用了四个方法来定义实体之间的关系,Withmany方法允许多个。HasForeignKey方法表示哪个属性是Order表的外键,WillCascadeOnDelete方法用来配置是否级联删除。

三.Many-to-Many Relationship【多对多关系】

每条记录在两个表中,都可以关联到另外一个表中的很多记录【或者0条记录】。多对多关系,需要第三方的表,也就是关联表或者链接表,因为关系型数据库不能直接适应这种关系。

为了更好的理解多对多关系,我们想到,有一个选课系统,一个学生可以选秀很多课程,一个课程能够被很多学生选修,所以我们定义两个实体,一个是Syudent实体,另外一个是Course实体。我们来通过图表看看,多对多关系吧:

Student实体

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EF.Core.Data
{
public class Student:BaseEntity
{
public string Name { get; set; }
public byte Age { get; set; }
public bool IsCurrent { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
}

  

Courses实体

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace EF.Core.Data
{
public class Course:BaseEntity
{
public string Name { get; set; }
public Int64 MaximumStrength { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
}

  

使用Fluent Api配置Student实体

using EF.Core.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EF.Data.Mapping
{
public class StudentMap:EntityTypeConfiguration<Student>
{
public StudentMap()
{
//key
HasKey(t => t.ID); //property
Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(t => t.Name);
Property(t => t.Age);
Property(t => t.IsCurrent);
Property(t => t.AddedDate).IsRequired();
Property(t => t.ModifiedDate).IsRequired();
Property(t => t.IP); //table
ToTable("Students"); //配置关系[多个课程,可以被多个学生选修]
//多对多关系实现要领:hasmany,hasmany,然后映射生成第三个表,最后映射leftkey,rightkey
this.HasMany(s => s.Courses).
WithMany(s => s.Students)
.Map(s => s.ToTable("StudentCourse").
MapLeftKey("StudentId").
MapRightKey("CourseId"));
}
}
}

  

上面的代码中,表示,一个学生可以选修多个课程,并且每个课程可以有很多学生,你知道,实现多对多的关系,我们需要第三个表,所以我们映射了第三个表,mapLeftkey和maprightkey定义了第三个表中的键,如果我们不指定的话,就会按照约定生成类名_Id的键。

使用Fluent Api配置Courses实体

using EF.Core.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EF.Data.Mapping
{
public class CourseMap:EntityTypeConfiguration<Course>
{
public CourseMap()
{
this.HasKey(t => t.ID);//少了一行代码
//property
Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(t => t.Name);
Property(t => t.MaximumStrength);
Property(t => t.AddedDate).IsRequired();
Property(t => t.ModifiedDate).IsRequired();
Property(t => t.IP); //table
ToTable("Courses");
}
}
}

  

出处:https://www.cnblogs.com/caofangsheng/p/5715876.html

EF CodeFirst方式 Fluent Api配置的更多相关文章

  1. EF CodeFirst 之 Fluent API

    如何访问Fluent API: 在自定义上下文类中重写OnModelCreating方法,在方法内调用. 注:用法基本一样,配置类中的this就相当于modelBuilder.Entity<Pe ...

  2. 1.【使用EF Code-First方式和Fluent API来探讨EF中的关系】

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/relationship-in-entity-framework-using-code-firs ...

  3. 10.翻译系列:EF 6中的Fluent API配置【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/fluent-api-in-code-first.aspx EF 6 Code-Firs ...

  4. EF里的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射

    I.EF里的默认映射 上篇文章演示的通过定义实体类就可以自动生成数据库,并且EF自动设置了数据库的主键.外键以及表名和字段的类型等,这就是EF里的默认映射.具体分为: 数据库映射:Code First ...

  5. EF——默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射 02 (转)

    EF里的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射   I.EF里的默认映射 上篇文章演示的通过定义实体类就可以自动生成数据库,并且EF自动设置了数据库 ...

  6. EF的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射

    I.EF的默认映射 上节我们创建项目,通过定义实体类就可以自动生成数据库,并且EF帮我们自动设置了数据库的主键.外键以及表名和字段的类型等,这就是EF的默认映射.具体分为: 数据库映射:Code Fi ...

  7. Fluent API 配置

    EF里实体关系配置的方法,有两种: Data Annotation方式配置 也可以 Fluent API 方式配置 Fluent API 配置的方法 EF里的实体关系 Fluent API 配置分为H ...

  8. Entity Framework 实体框架的形成之旅--Code First模式中使用 Fluent API 配置(6)

    在前面的随笔<Entity Framework 实体框架的形成之旅--Code First的框架设计(5)>里介绍了基于Code First模式的实体框架的经验,这种方式自动处理出来的模式 ...

  9. 使用Fluent API 配置/映射属性和类型

    Code First约定-Fluent API配置 使用Fluent API 配置/映射属性和类型 简介 通常通过重写派生DbContext 上的OnModelCreating 方法来访问Code F ...

随机推荐

  1. Maven-06: 插件的内置绑定

    Maven的生命周期与插件相互绑定,用以完成实际的构建任务.具体而言,是生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务.例如项目编译这一任务,它对应default生命周期的compile ...

  2. Ajax与服务器(JSON)通信介绍

    本文主要介绍使用Ajax与服务器(JSON)通信方法,谈谈Ajax提供的两类服务器通信手段:同步通信和异步通信.有需要的可以了解一下.毕竟这个时代出了很多东西,自动化构建工具,mvvm框架等等.Jav ...

  3. curl 获取外网IP

    #curl http://members.3322.org/dyndns/getip121.204.134.10

  4. Mybatis 常用标签

    MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格,还要注意省掉 ...

  5. 201621123060《JAVA程序设计》第十二周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 面向系统综合设计-图书馆管理系统或购物车 使用流与文件改造你的图书馆管理系统或购物车. 2.1 简述如何 ...

  6. 团队作业6——展示博客(Alpha版本)

    Deadline: 2017-12-3  23:00PM,以博客发表日期为准   评分基准 按时交 - 有分,检查的项目包括后文的两个方面 团队成员介绍 Alpha阶段进展 团队合作,各成员分工 Be ...

  7. 作业01-Java基本概念

    1.本周学习总结 本周学习了JVM,JDK,JRE三者之间的区别及联系,知道JDK包括JRE,JRE包括JVM,知道java语言与C语言的不同之处在于java语言可以依赖于虚拟机实现"编译一 ...

  8. beta冲刺计划安排

    经过紧张的Alpha阶段,很多组已经从完全不熟悉语言和环境,到现在能够实现初步的功能.下一阶段即将加快编码进度,完成系统功能.强化软件工程的体会. 凡事预则立,在Beta开始前,以小组为单位,在敏捷冲 ...

  9. Flask 文件和流

    当我们要往客户端发送大量的数据比较好的方式是使用流,通过流的方式来将响应内容发送给客户端,实现文件的上传功能,以及如何获取上传后的文件. 响应流的生成 Flask响应流的实现原理就是通过Python的 ...

  10. 【iOS】OC-时间转化的时区问题

    -(void)testTime{ NSDate *now = [NSDate date];//根据当前系统的时区产生当前的时间,绝对时间,所以同为中午12点,不同的时区,这个时间是不同的. NSDat ...