• DB表的关系及EF中Fluent API的使用


    现在使用多数的数据库是关系型数据库,那么表与表之间的关系就会显得尤其重要,对于数据的CRUD处理和以后数据的分析有很大的好处。下面是对于数据库中对表关系的理解以及在EF中使用Fluent API来创建这种关系的例子.

    数据库中实体之间的联系

    书中语录:在现实世界中,事务内部以及事务之间是有联系的,这些联系在计算机里面叫做实体之间的联系和实体内部的联系,内部的联系就是组成实体属性之间的联系,而实体之间的联系可以分为三类。(1:1, 1:n, n:n)

    一:一对一联系(1:1)

       A实体集中每一个实体在实体集B中至多有一个实体与之联系,反之亦然,这就是一对一联系。

    eg:一个班只有一个班长,而一个班长只在一个班中任职。班级与班长就是一对一关系。

      属性模型

        /// <summary>
        /// Monitor代表班长类
        /// </summary>
        public class Monitor
        {
            public Guid MonitorId { get; set; }
            public string MName { get; set; }
            public int MAge { get; set; }
            public virtual TheClass TheClass { get; set; }                        //导航属性
        }
        /// <summary>
        /// TheClass表示班级
        /// </summary>
        public class TheClass
        {
            public TheClass()
            {
                this.Students = new HashSet<Student>();
            }
            public virtual Monitor Monitor { get; set; }                          // 导航属性   
             public Guid TheClassId { get; set; }
            public string TcName { get; set; }
            public int TcNumber { get; set; }
            public virtual ICollection<Student> Students { get; set; }            //班级里面有很多学生
        }

    Fluent API(1:1)

        public class MonitorMap : EntityTypeConfiguration<Monitor>
        {
            public MonitorMap()
            {
                this.ToTable("Monitor");
                this.HasKey(x=>x.MonitorId);            
                Property(x => x.MName).HasMaxLength(128);
                Property(x => x.MAge);
                this.HasRequired(x => x.TheClass).WithOptional(x => x.Monitor).Map(x => x.MapKey("TheClassId"));    //这里设置Monitor为依赖类,且TheClassId为外键。            
            }
        }
    
        public class TheClassMap:EntityTypeConfiguration<TheClass>
        {
            public TheClassMap()
            {
                ToTable("TheClass");
                HasKey(x => x.TheClassId);
                Property(x => x.TcName).HasMaxLength(128);
                Property(x => x.TcNumber);
                HasMany(x => x.Students);              
                HasOptional(x => x.Monitor);               
            }
        }

    数据库中的表

     

    在实现一对一的过程中,出现了很多的问题,说是外键设置的问题,依赖类和主类关系不清.这些刚开始的时候一直出错,导致数据库中模型创建不了,浪费很长时间,出现这种情况就是我们代码里面设置的问题,此时我们百度,博客园等均可解决 ,上面Fluent API代码中是正确的。

    二:一对多联系(1:n)

       A实体集中每一个实体在B实体集中有n个实体与之对应(n>=0),反过来,B实体集中的每一个实体在A中只有1个与之对应。这种形式就是一对多联系。

    eg:班集和班集里面学生的关系。学校和学生的关系。

    属性

        /// <summary>
        /// TheClass表示班级
        /// </summary>
        public class TheClass
        {
            public TheClass()
            {
                this.Students = new HashSet<Student>();
            }
            public virtual Monitor Monitor { get; set; }                                  // 导航属性   
             public Guid TheClassId { get; set; }
            public string TcName { get; set; }
            public int TcNumber { get; set; }
            public virtual ICollection<Student> Students { get; set; }            //班级里面有很多学生
        }
        /// <summary>
        /// 学生表
        /// </summary>
          public class Student
        {
            public Student()
            {
                this.Courses=new Collection<Course>();
            }
            public Guid StudentId { get; set; }
              public string SName { get; set; }
              public int SAge { get; set; }
              public Guid TheClassId { get; set; }
              public virtual  TheClass TheClass { get; set; }          //学生属于一个班级
            public virtual ICollection<Course> Courses { get; set; }
        }

    Fluent API(1:n)

        public class TheClassMap:EntityTypeConfiguration<TheClass>
        {
            public TheClassMap()
            {
                ToTable("TheClass");
                HasKey(x => x.TheClassId);
                Property(x => x.TcName).HasMaxLength(128);
                Property(x => x.TcNumber);
                HasMany(x => x.Students);              
                HasOptional(x => x.Monitor);               
            }
        }
        public class StudentMap : EntityTypeConfiguration<Student>
        {
            public StudentMap()
            {
                ToTable("Student");
                HasKey(x => x.StudentId);
                Property(x => x.SName).HasMaxLength(128);
                HasRequired(x => x.TheClass).WithMany(x => x.Students).HasForeignKey(x => x.TheClassId);
                HasMany(x => x.Courses).WithMany(x => x.Student);
            }
        }

    数据库中的表

    image_thumb[16]

    三:多对多联系(n:n)

       A实体集中的每一个实体在实体集B中有n个实体与之对应(n>=0),反过来,B实体集中每一个实体在实体集A中有m个实体与之对应,这种关系就是多对多联系。

    eg:学生和选修课。(一个学生可选修多门课程,一门课程可由多名学生选修),订单和产品(一个订单里面有多个产品,一个产品可在多个订单中)。

    属性模型

        /// <summary>
        /// 课程类
        /// </summary>
        public class Course
        {
            public Course()
            {
                this.Student=new Collection<Student>();
            }
            public Guid CourseId { get; set; }
            public string CName { get; set; }
            public virtual ICollection<Student> Student { get; set; }
        }
        /// <summary>
        /// 学生表
        /// </summary>
          public class Student
        {
            public Student()
            {
                this.Courses=new Collection<Course>();
            }
              public Guid StudentId { get; set; }
              public string SName { get; set; }
              public int SAge { get; set; }
              public Guid TheClassId { get; set; }
              public virtual  TheClass TheClass { get; set; }          //学生属于一个班级
               public virtual ICollection<Course> Courses { get; set; }
        }

    Fluent API

        public class CourseMap:EntityTypeConfiguration<Course>
        {
            public CourseMap()
            {
                ToTable("Course");
                HasKey(x => x.CId);
                Property(x => x.CName).HasMaxLength(128);
                HasMany(x => x.Students).WithMany(x=>x.Courses).Map(m =>
                {
                    m.ToTable("CourseStudentId");
                    m.MapLeftKey("CourseId");
                    m.MapRightKey("StudentId");
                });                                                     //这里设置多对多关系中间表的表名和列名
            }
        }

           

        public class StudentMap:EntityTypeConfiguration<Student>
        {
            public StudentMap()
            {
                ToTable("Student");
                HasKey(x => x.SId);
                Property(x => x.SName).HasMaxLength(128);
                HasRequired(x => x.TheClass).WithMany(x=>x.Students).HasForeignKey(x=>x.TheClassId);
                HasMany(x => x.Courses).WithMany(x=>x.Students);
            }
        }

    数据库中的表

    image_thumb[20]

       在多对多关系中,我们可以设置中间表的表名和列名,就如同上面那样子。

       上面就是数据库表的三中关系,其中里面的一对一是一对多的特例,一对多是多对多的特例,我们只有掌握好这些最基本的知识,才能理解更加复杂表中的关系。

    出现错误

    image_thumb[17]

    *:这是我在使用数据迁移的时候出现的错误。原因是我前面的主键设置的是(SId,CId,TCId,MId).EF在生成数据库的时候报错,我们应该把他们设置为(StudentId,CourseId,TheClassId,MonitorId),这样子就会出现我们的表。

    * 上面的错误很大一定程度是因为我没有重写EF里面的OnModelCreating类导致的,我前面多对多表创建时出现的问题也是由于这个原因导致的。

    image_thumb[21]

    下面数据上下文中的代码

        public class BlogDbContent : DbContext, IDisposable
        {
            public BlogDbContent()
                : base("name=BlogsEntities")
            {
            }
    
            public DbSet<BlogUser> BlogUser { get; set; }
            public DbSet<Post> Post { get; set; }
            public DbSet<Course> Course { get; set; }
            public DbSet<Student> Students { get; set;}
            public DbSet<TheClass> TheClass { get; set; }
            public DbSet<Monitor> Monitor { get; set; }
    
            /// <summary>
            /// 重写配置类
            /// </summary>
            /// <param name="modelBuilder"></param>
            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);
            }
        }

    数据库的连接字符串<App.Config>

      <connectionStrings>
        <add name="BlogsEntities" connectionString="Data Source=localhost;Initial Catalog=Ahui_Blog;Integrated Security=False;
             Persist Security Info=False;User ID=sa;Password=******" providerName="System.Data.SqlClient" />
      </connectionStrings>

    附件:

    Fluent API参考 

     http://www.cnblogs.com/oppoic/p/ef_one-to-one_one-to-many_many-to-many_cascadedelete.html

     http://www.cnblogs.com/panchunting/p/entity-framework-code-first-fluent-api-configuring-relationships.html

    理解一对一关系

     http://www.cnblogs.com/dudu/archive/2011/07/08/entity_framework_one_to_one_two_way.html

  • 相关阅读:
    EasyBPM进销存之物料管理
    水厂流程三维场景可视化解决方案
    构造器
    可变形参
    重写
    拥塞处理(一)——拥塞处理的历史概述
    idea的各种乱码问题
    MySQL的主键也想使用uuid
    使用spring security明文密码校验时报错-BadCredentialsException: Bad credentials
    ValueError: check_hostname requires server_hostname
  • 原文地址:https://www.cnblogs.com/netxiaohui/p/4925892.html
Copyright © 2020-2023  润新知