• EF实体框架之CodeFirst二


    在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("1001", "张三", SexType.Female, 26);
                    db.Persons.Add(person);
                    Student stu = new Student("001", "软件工程", "蓝翔", "1000", "CYW", SexType.Female, 25);
                    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("1000", DateTime.Now);
                    Person person = new Person("1001", "张三", SexType.Female, 26, 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("1000", DateTime.Now);
                    Person person = new Person("1001", "张三", SexType.Female, 26, card);
                    db.Persons.Add(person);
                    IDCard card2 = new IDCard("1000", DateTime.Now);
                    Student stu = new Student("001", "挖掘机", "蓝翔", "1000", "赵铁蛋", SexType.Male, 25, 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("1001", "张三", SexType.Female, 26);
                    db.Persons.Add(person);
    
                    Student stu = new Student("001", "挖掘机", "蓝翔", "1000", "赵铁蛋", SexType.Male, 25);
                    db.Persons.Add(stu);
                    db.SaveChanges();
                    Console.WriteLine("Success");
                }

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

  • 相关阅读:
    HTTP协议【详解】——经典面试题
    原生JS的地区二级联动,很好理解的逻辑
    js操作字符串的常用方法
    移除input框type="number"在部分浏览器的默认上下按钮
    atom
    解决gitHub下载速度慢的问题
    ATOM常用插件推荐
    脚踝扭伤肿了怎么办
    这才是真正的电子科大
    月入 7000,怎么存钱?
  • 原文地址:https://www.cnblogs.com/5ishare/p/5814785.html
Copyright © 2020-2023  润新知