在codefirst一中也说了Mapping是实体与数据库的纽带,model通过Mapping映射到数据库,我们可以从数据库的角度来分析?首先是映射到数据库,这个是必须的。数据库里面一般包括表、列、约束、主外键、级联操作、实体关系(E-R图)、存储过程、视图、锁、事务、数据库结构更新等。在接下来的日子里,通过数据库的这些名词,来学习C#是如何实现或者调用它们来通过代码操作数据库。

在code first一中主要是学习了对数据库的映射,今天主要是学习表的映射。一个model映射一个表,多个modle映射一个表,一个model映射多个表,子类映射表。

一、表名的映射

学习model与表的映射肯定要知道表名的映射,可以通过using System.ComponentModel.DataAnnotations.Schema;命名空间下的[Table("TestStudent")]特性来约定表名的映射。

二、一个model映射一个表

这个就不用多说,一般情况都是一个model映射一个表,在code first一中也有Student类映射到Student表。

三、子类映射表

面向对象的三大特征之一就是继承,model中也会有继承实体,那子类如何映射到表中呢?

首先定义了一个Person类,一个继承Person的Student类。

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EFCodeFirstModels
{
public enum SexType { Male, Female } public class Person
{
[Key]
public string PersonId { get; set; }
//姓名
public string Name { get; set; }
//性别
public SexType Sex { get; set; }
//年龄
public int Age { get; set; } public Person(string personId, string name, SexType sex, int age)
{
PersonId = personId;
Name = name;
Sex = sex;
Age = age;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EFCodeFirstModels
{
public class Student : Person
{
public string StuId { get; set; } public string Major { get; set; } public string School { get; set; } public Student(string stuId, string major, string school, string personId, string name, SexType sex, int age) : base(personId, name, sex, age)
{
this.StuId = stuId;
this.Major = major;
this.School = major;
this.PersonId = personId;
this.Name = name;
this.Sex = sex;
this.Age = age;
}
} }

数据库上下文还是一默认的

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
using EFCodeFirstModels;
using System.Configuration; namespace EFCodeFirstDataAccess
{
public class EFCodeFirstDbContext:DbContext
{ public EFCodeFirstDbContext() : base("MyStrConn")
{
}
public DbSet<Person> Persons { get; set; } }
}

在Main中增加一个Person对象,一个Student对象。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EFCodeFirstModels;
using EFCodeFirstDataAccess; namespace EFCodeFirstDemo
{
class Program
{
static void Main(string[] args)
{
//using能及时释放资源,例如数据库连接异常,可以即使将上下文释放
using (var db=new EFCodeFirstDbContext())
{
Person person = new Person("", "张三", SexType.Female, );
db.Persons.Add(person);
Student stu = new Student("", "软件工程", "蓝翔", "", "CYW", SexType.Female, );
db.Persons.Add(stu);
db.SaveChanges();
Console.WriteLine("Success");
}
Console.ReadLine(); }
}
}

运行之后可以看到数据库生成了一个People表,多了一列:Discriminator,用来区别子类和父类对象

如果你想改名Discriminator列名,可以使用Fluent API来设置,需要在数据库上下文中重写OnModelCreating()方法。

public class EFCodeFirstDbContext:DbContext
{ public EFCodeFirstDbContext() : base("MyStrConn")
{
}
public DbSet<Person> Persons { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().Map(m =>
{
m.ToTable("Person");
m.Requires("PersonType").HasValue("Person");
}).Map<Student>(m =>
{
m.Requires("PersonType").HasValue("Student");
}); }
}

如果Person只有一个派生类,那我们可以使用布尔值来区别

            modelBuilder.Entity<Person>().Map(m =>
{
m.ToTable("Person");
m.Requires("IsStudent").HasValue(false);
}).Map<Student>(m =>
{
m.Requires("IsStudent").HasValue(true);
});

上面是两个Model生成一个表,基类和派生类都映射到同一张表中,通过使用鉴别列来识别是否为子类型。这是Code First默认规则使用的表映射方法TPH(Table Per Hierarchy)。其实还有两种映射方法。一种是TPT,一种是TPC.

TPT:Table Per Type,TPH将所有层次的类都放在了一个表里,而TPT在一个单独的表中储存来自基类的属性,在派生类定义的附加属性储存在另一个表里,并使用外键与主表相连接。这种方式只需指定子类表名。

 [Table("Student")]

TPC:Table Per Concrete Type,基类与派生类都映射在不同的表中,不同的是派生类中还包括了基类的字段。TPC只能用Fluent API来配置

            modelBuilder.Entity<Person>().Map(m =>
{
m.ToTable("Person");
}).Map<Student>(m =>
{
m.ToTable("Student");
m.MapInheritedProperties();
});

四、多个Model映射一个表

上面虽然是两个类Person、Student映射到一个表中,但主键都在基类上定义的,映射一个表还比较容易。如果是两个没有继承关系的Model如何映射到同一张表呢?这个我们在上面Person类Student类的基础上增加了一个IDCard类,主要是表示身份证类。假设Person的PersonId就是IDCard的PersonId。两个Model映射一个表,那两个Molde肯定是一对一的关系,映射的表名相同,主键名和类型也要相同,这些是必须的。同时还要指明两个类的外键,只指明一个都不行。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; namespace EFCodeFirstModels
{
[Table("Person")]
public class IDCard
{
//身份证号
[Key,ForeignKey("People")]
public string PersonId { get; set; } //法定出生日期
public DateTime BirthDate { get; set; } public Person People { get; set; } public IDCard(string personId, DateTime birstDate)
{
PersonId = personId;
BirthDate = birstDate;
} }
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EFCodeFirstModels
{
public enum SexType { Male, Female } [Table("Person")]
public class Person
{
[Key, ForeignKey("Card")]
public string PersonId { get; set; }
//姓名
public string Name { get; set; }
//性别
public SexType Sex { get; set; }
//年龄
public int Age { get; set; } public IDCard Card { get; set; } public Person(string personId, string name, SexType sex, int age, IDCard card)
{
PersonId = personId;
Name = name;
Sex = sex;
Age = age;
Card = card;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EFCodeFirstModels
{
public class Student : Person
{
public string StuId { get; set; } public string Major { get; set; } public string School { get; set; } public Student(string stuId, string major, string school, string personId, string name, SexType sex, int age, IDCard card) : base(personId, name, sex, age, card)
{
this.StuId = stuId;
this.Major = major;
this.School = major;
this.PersonId = personId;
this.Name = name;
this.Sex = sex;
this.Age = age;
this.Card = card;
}
} }

在Mian中先添加一个Person来看下运行结果。

            //using能及时释放资源,例如数据库连接异常,可以即使将上下文释放
using (var db=new EFCodeFirstDbContext())
{ IDCard card = new IDCard("", DateTime.Now);
Person person = new Person("", "张三", SexType.Female, , card);
db.Persons.Add(person);
db.SaveChanges();
Console.WriteLine("Success");
}
Console.ReadLine(); }

从上面的截图看到Person表中也有Student的属性,感觉真是不可思议,amazing.

我们添加一个Person一个Student来看下效果

        static void Main(string[] args)
{
//using能及时释放资源,例如数据库连接异常,可以即使将上下文释放
using (var db=new EFCodeFirstDbContext())
{ IDCard card = new IDCard("", DateTime.Now);
Person person = new Person("", "张三", SexType.Female, , card);
db.Persons.Add(person);
IDCard card2 = new IDCard("", DateTime.Now);
Student stu = new Student("", "挖掘机", "蓝翔", "", "赵铁蛋", SexType.Male, , card2);
db.Persons.Add(stu);
db.SaveChanges();
Console.WriteLine("Success");
}
Console.ReadLine(); }

IDCard和Person生成了同一表,我们可以像上面的Fluent API来改变Discriminator列名。也可以使用TPT的方式生成两个表,只需在Student类上指明映射的表名。

但是TPC就不行了。就会报错,这可能也是只新增Person的时候Student中的属性也会自动添加上的原因吧。

五、一个Model映射多个表

一个Model映射多个表和上面多个Model映射一个表正好反过来,还用上面Student和Person举例。

            modelBuilder.Entity<Student>().Map(m=> {
m.ToTable("Person");
m.Properties(p => p.PersonId);
m.Properties(p=>p.Name);
m.Properties(p=>p.Age);
m.Properties(p => p.Sex); }).Map(m=> {
m.ToTable("Student");
m.Properties(p => p.PersonId);
m.Properties(p=>p.StuId);
m.Properties(p => p.Major);
m.Properties(p => p.School); });

上面将一个Student类映射给两个表一个Student一个person.

            //using能及时释放资源,例如数据库连接异常,可以即使将上下文释放
using (var db=new EFCodeFirstDbContext())
{ Person person = new Person("", "张三", SexType.Female, );
db.Persons.Add(person); Student stu = new Student("", "挖掘机", "蓝翔", "", "赵铁蛋", SexType.Male, );
db.Persons.Add(stu);
db.SaveChanges();
Console.WriteLine("Success");
}

我们上面添加了一个Person类对象,一个Student类对象,这是Student对象会添加到两个表中。

EF实体框架之CodeFirst二的更多相关文章

  1. EF实体框架之CodeFirst四

    在EF实体框架之CodeFirst二中也提到数据库里面一般包括表.列.约束.主外键.级联操作.实体关系(E-R图).存储过程.视图.锁.事务.数据库结构更新等.前面几篇博客把表.存储过程.视图这些算是 ...

  2. EF实体框架之CodeFirst一

    对于SQL Server.MySql.Oracle等这些传统的数据库,基本都是关系型数据库,都是体现实体与实体之间的联系,在以前开发时,可能先根据需求设计数据库,然后在写Model和业务逻辑,对于Mo ...

  3. EF实体框架之CodeFirst五

    上一博客学习了下基本的约定配置,留下几个遗漏的,这篇就是学习下遗漏一复杂类型. 一.什么是复杂类型? 书中说道:“复杂类型也可视作值类型(?)可以作为附加属性添加到其他类.复杂类型与实体类型的区别在于 ...

  4. EF实体框架之CodeFirst七

    前面的6篇博客基本把Code First学习的差不多了,今天这篇学习下code first中的并发控制和事务,基本也快学完了,顶多就差数据迁移. 在数据库中也是有锁和事务的概念,在C#中也是存在,当然 ...

  5. EF实体框架之CodeFirst六

    上午的时候把复杂类型学习了一下,想着趁着周六日把Code First学习完,所以下午还是把Code First中的关系学习下.在数据库中最重要的恐怕就是E-R图了,E-R体现了表与表直接的关系.使用C ...

  6. EF实体框架之CodeFirst三

    前两篇博客学习了数据库映射和表映射,今天学习下数据库初始化.种子数据.EF执行sql以及执行存储过程这几个知识. 一.数据库初始化策略 数据库初始化有4种策略 策略一:数据库不存在时重新创建数据库 D ...

  7. EF实体框架之CodeFirst八

    前面七篇基本把Code First学习了一下,不过code first中会出现一个问题,就是数据迁移的问题. 一.数据准备 还是在前面的demo上修改,这次使用Province和City类. publ ...

  8. 【MVC 1】MVC+EF实体框架—原理解析

    导读:在之前,我们学过了三层框架,即:UI.BLL.DAL.我们将页面显示.逻辑处理和数据访问进行分层,避免了一层.两层的混乱.而后,我们又在经典三层的基础上,应用设计模式:外观.抽象工厂+反射,使得 ...

  9. 【EF 1】EF实体框架 原理+实例

    一.知识回顾 到目前为止,自己学到的链接数据库操作已经经历了几个阶段,分别是:学生信息管理和(第一次)机房收费时的直接连接数据库操作表格,然后是机房个人重构中应用的操作实体,在其中还利用了一个很重要的 ...

随机推荐

  1. Java中的显示锁 ReentrantLock 和 ReentrantReadWriteLock

    在Java1.5中引入了两种显示锁,分别是可重入锁ReentrantLock和可重入读写锁ReentrantReadWriteLock.它们分别实现接口Lock和ReadWriteLock.(注意:s ...

  2. 用memoization优化递归算法[JS/PHP实现]

    递归函数,通过把一个大而复杂问题简化为许多但规模较小的问题,以同一个相似模式来计算,降低了解题的难度:通过调用自身函数,极大地减少了函数代码量的优点而为开发者喜爱.但因其不断调用自身函数开辟新栈,且大 ...

  3. private成员变量真的私有吗?(用指针刨他祖坟)

    今天写程序时突然想到的,为什么不用指针去获取类的成员变量呢.于是做了这个实验.首先定义了一个类: class Test { private: int i; char c; int* p; public ...

  4. UVALive 6470 Chomp --记忆化搜索

    题意:给一个只有三行的方块阵(横向最多100个),然后p,q,r分别代表第1,2,3层的方格数,两人轮流去掉一个格子,此时这个格子的右上方都会被去掉,面临只剩最左下角的一个格子的状态的人输,问先手能否 ...

  5. HDU 2955 Robberies --01背包变形

    这题有些巧妙,看了别人的题解才知道做的. 因为按常规思路的话,背包容量为浮点数,,不好存储,且不能直接相加,所以换一种思路,将背包容量与价值互换,即令各银行总值为背包容量,逃跑概率(1-P)为价值,即 ...

  6. RMQ之ST算法模板

    #include<stdio.h> #include<string.h> #include<iostream> using namespace std; ; ],M ...

  7. 使用List的addAll()方法请判空指针

    在写代码的时候经常会用到List,Set的addAll()方法,但是要注意addAll()方法不能传入空指针. package link.mengya.utils; import link.mengy ...

  8. php安全配置记录

    Php环境部署完成后,通常我们会进行一些安全设置.除了熟悉各种PHP漏洞外,还可以通过配置php.ini来加固PHP的运行环境.PHP官方也曾经多次修改php.ini的默认设置. 接下来,推荐php. ...

  9. WPF好看的进度条实现浅谈(效果有点类似VS2012安装界面)

    为了界面友好,一般的操作时间较长时,都需要增加进度条提示.由于WPF自带的进度条其实不怎么好看,而且没啥视觉效果.后来,装VS2012时,发现安装过程中进度条效果不错,于是上网查了资料.学习了Mode ...

  10. [资源]PHP使用消息队列

    利用PHP操作Linux消息队列完成进程间通信 基于HTTP协议的轻量级开源简单队列服务:HTTPSQS[原创] Redis队列——PHP操作简单示例 入队操作 <?php $redis = n ...