• EF使用CodeFirst方式生成数据库&技巧经验


    前言

    EF已经发布很久了,也有越来越多的人在使用EF。如果你已经能够非常熟练的使用EF的功能,那么就不需要看了。本文意在将自己使用EF的方式记录下来备忘,也是为了给刚刚入门的同学一些指导。看完此文,你应该就学会以CodeFirst的方式操作数据库了。

    本文主要内容

    • CodeFirst生成数据库的流程
    • 初始化配置
    • 数据库实体构造技巧
    • 主外键设置
    • decimal精度修改

    项目框架搭建

    本文所使用的开发工具是vs2015(EF6.1.3)

    第一步:新建一个空白项目

    第二步:引用EntityFramework

    DbContext的初始化配置

     DbContext作为操作数据库的网关,十分重要。我们需要对它进行一些类的初始化操作,例如:解决团队开发中,多人迁移数据库造成的修改覆盖问题。

    代码如下:

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Data.Entity.ModelConfiguration.Conventions;
    namespace EFDemo.Core.EF
    {
        /// <summary>
        /// EF访问数据库的接口   
        /// </summary>
        public class MyDbContext : System.Data.Entity.DbContext
        {        
            public MyDbContext()
                : base("EFDemo")
            {
                //解决团队开发中,多人迁移数据库造成的修改覆盖问题。
                Database.SetInitializer<MyDbContext>(null);
                //base.Configuration.AutoDetectChangesEnabled = false;
                ////关闭EF6.x 默认自动生成null判断语句
                //base.Configuration.UseDatabaseNullSemantics = true;           
            }    
            public MyDbContext(System.Data.Common.DbConnection oConnection)
                : base(oConnection, true)
            {
                this.Configuration.LazyLoadingEnabled = true;         
            }
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                //表名不用复数形式
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
                //移除一对多的级联删除约定,想要级联删除可以在 EntityTypeConfiguration<TEntity>的实现类中进行控制
                modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
                //多对多启用级联删除约定,不想级联删除可以在删除前判断关联的数据进行拦截
                modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();          
    
                base.OnModelCreating(modelBuilder);
            }
            //将实体对象写在这里,就可以生成对应的数据。 如下:
            //public DbSet<Demo> Demo { get; set; }
    
    
      
    
        }
    
    
    }
    复制代码

    项目位置:

    Migrations下Configuration类的初始化配置

     Configuration类的初始化配置十分重要,我们需要通过配置解决一系列迁移问题。例如:允许自动迁移,自动迁移默认情况下不扔掉列在我们的数据库中的表。如果我们不希望这样的行为,我们可以告诉迁移明确允许数据丢失的配置类的AutomaticMigrationDataLossAllowed属性设置为true。

    代码如下:

    复制代码
    namespace EFDemo.Core.Migrations
    {
        using System;
        using System.Data.Entity;
        using System.Data.Entity.Migrations;
        using System.Linq;
    
        internal sealed class Configuration : DbMigrationsConfiguration<EFDemo.Core.EF.MyDbContext>
        {
            public Configuration()
            {
                //允许自动迁移
                //不然会报错Unable to update database to match the current model because there are pending changes and automatic migration is disabled. Either write the pending model changes to a code-based migration or enable automatic migration. Set DbMigrationsConfiguration.AutomaticMigrationsEnabled to true to enable automatic migration.You can use the Add-Migration command to write the pending model changes to a code-based migration.
    
                //允许自动迁移
                AutomaticMigrationsEnabled = true;
                //自动迁移默认情况下不扔掉列在我们的数据库中的表。如果我们不希望这样的行为,我们可以告诉迁移明确允许数据丢失的配置类的AutomaticMigrationDataLossAllowed属性设置为true。
                AutomaticMigrationDataLossAllowed = true;
            }
    
            protected override void Seed(EF.MyDbContext context)
            {
                
                //  This method will be called after migrating to the latest version.
    
                //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
                //  to avoid creating duplicate seed data. E.g.
                //
                //    context.People.AddOrUpdate(
                //      p => p.FullName,
                //      new Person { FullName = "Andrew Peters" },
                //      new Person { FullName = "Brice Lambson" },
                //      new Person { FullName = "Rowan Miller" }
                //    );
                //
            }
        }
    }
    复制代码

    项目位置:

    数据库对应实体对象的定义

     CodeFirst模式需要我们先定义实体,然后通过实体生成数据。

    通常我们设计数据库表时,每个表都有(ID,是否删除,备注,添加人,添加时间,修改人,修改时间)等字段。我们可以用基类处理

    基类实体:

    复制代码
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EFDemo.Core.Entity
    {
        public class BaseEntity
        {
    
        }
        [Serializable]
        public class BaseEntity<TKey> : BaseEntity
        {
            public BaseEntity()
            {
                this.AddTime = DateTime.Now;
            }
    
            [Key]
            [Display(Name = "编号")]
            public TKey ID { get; set; }
            [Display(Name = "排序")]
            [Required(ErrorMessage = "{0}是必填项"), Range(0, int.MaxValue, ErrorMessage = "{0}的范围是{1}到{2}")]
            [DefaultValue(0)]
            public int Sort { get; set; }
            [Display(Name = "备注")]
            [MaxLength(256, ErrorMessage = "{0}最大长度{1}")]
            public string Remark { get; set; }
            [Display(Name = "是否删除")]
            [Required]
            public bool Deleted { get; set; }
            public int AddUser { get; set; }
            [Display(Name = "添加时间")]
            [DisplayFormat(ApplyFormatInEditMode = true, ConvertEmptyStringToNull = true, DataFormatString = "{0:yyyy-MM-dd HH mm}", HtmlEncode = false, NullDisplayText = "数据无效")]
            public DateTime AddTime { get; set; }
            public int ModUser { get; set; }
            [DisplayFormat(ApplyFormatInEditMode = true, ConvertEmptyStringToNull = true, DataFormatString = "{0:yyyy-MM-dd  HH mm}", HtmlEncode = false, NullDisplayText = "数据无效")]
            public DateTime? ModTime { get; set; }
    
        }
      
    
    }
    复制代码

    省市区表:

    复制代码
    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 EFDemo.Core.Entity
    {
        /// <summary>
        /// 省市区
        /// </summary>
        public class Public_Area
        {        
    
            [Key]
            public Guid ID { get; set; }
    
            [Display(Name = "父亲ID")]
            public Guid ParentID { get; set; }
    
            [Display(Name = "名称")]
            [MaxLength(32, ErrorMessage = "{0}最大长度{1}")]
            public String Name { get; set; }
        }
    }
    复制代码

    班级表:

    复制代码
    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 EFDemo.Core.Entity
    {
        /// <summary>
        /// 班级
        /// </summary>
       public class T_Classes : BaseEntity<int>
        {
            public T_Classes() {
                this.T_Student = new List<Entity.T_Student>();
            }
    
    
            [InverseProperty("T_Classes")]
            public virtual List<T_Student> T_Student { get; set; }
    
            [Display(Name = "班级名称")]
            [Required(ErrorMessage = "{0}是必填项")]
            [MaxLength(8, ErrorMessage = "{0}最大长度{1}")]
            public string Name { get; set; }
    
            [Display(Name = "人数")]
            public int Count { get; set; }
    
            [Display(Name = "班级经费")]
            public decimal Money { get; set; }
        }
    }
    复制代码

    学生表:

     View Code

    班级表和学生表是一对多的关系,省市区表和学生表是一对多的关系,同时学生表中有多个省市区表的外键。

    项目位置:

    使用命令生成数据库

    第一步:将实体对象加入到DbContext中,

    如下:

    //将实体对象写在这里,就可以生成对应的数据。 如下:
            //public DbSet<Demo> Demo { get; set; }
    
            public DbSet<Public_Area> Public_Area { get; set; }
            public DbSet<T_Classes> T_Classes { get; set; }
            public DbSet<T_Student> T_Student { get; set; }

    第二步:在EFDemo.Core项目下的App.config文件夹中添加生成数据库的配置项

    配置文件代码如下:

    name="EFDemo"中的EFDemo要和DbContex中的一致。 
    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <configSections>
        <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
      </configSections>
      <connectionStrings>
        <!--生成数据库的连接字符串-->
        <add name="EFDemo" connectionString="Data Source=.;Initial Catalog=EFDemoDB;User ID=sa;Password=123456;MultipleActiveResultSets=True;Application Name=EntityFramework" providerName="System.Data.SqlClient" />
      </connectionStrings>
      <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
          <parameters>
            <parameter value="mssqllocaldb" />
          </parameters>
        </defaultConnectionFactory>
        <providers>
          <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
        </providers>
      </entityFramework>
    </configuration>
    复制代码

    第三步:执行更新命令

    启动项目一定要选择EFDemo.Core

    生成数据库如下:

    主外键关系设置

     班级和学生一对多关系的设置:

    一个表中的多个外键是另一个表中的主键的情况:学生表和省市县表

    生成的数据库如下:

    需要注意的是:这种情况,在Public_Area表中不能反向设置 public virtual List<T_Student> T_Student ,不然会报错。

    decimal怎么保存四位小数  

     decimal默认保留两位小数,我们需要通过如下设置让其保留四位小数。

    在DbContext中配置班级表中的Money字段让其保留四位小数:

     执行Update-Database命令:

    结果如下:

      

    使用EF操作数据库数据

    第一步:

     让EFDemo.Web应用EFDemo.Core程序集。

    第二步:

    配置EFDemo.Web中的webconfig中的数据库连接字符串:

     <connectionStrings>
        <!--操作数据库的连接字符串-->
        <add name="EFDemo" connectionString="Data Source=.;Initial Catalog=EFDemoDB;User ID=sa;Password=123456;MultipleActiveResultSets=True;Application Name=EntityFramework" providerName="System.Data.SqlClient" />
      </connectionStrings>

    第三步:

    使用EF向数据库添加数据

    复制代码
        public ActionResult Index()
            {
                using (var db = new Core.EF.MyDbContext())
                {
                    Public_Area area1 = new Public_Area()
                    {
                        ID = Guid.NewGuid(),
                        Name = "河南",
                        ParentID = Guid.NewGuid()
    
                    };
                    db.Public_Area.Add(area1);
                    Public_Area area2 = new Public_Area()
                    {
                        ID = Guid.NewGuid(),
                        Name = "郑州",
                        ParentID = area1.ID
    
                    };
                    db.Public_Area.Add(area2);
                    Public_Area area3 = new Public_Area()
                    {
                        ID = Guid.NewGuid(),
                        Name = "新郑",
                        ParentID = area2.ID
    
                    };
                    db.Public_Area.Add(area3);
    
                    //添加测试数据
                    T_Classes classes = new T_Classes()
                    {
                        Name = "高中三班",
                        Money = 2000
                    };
                    db.T_Classes.Add(classes);
                    T_Student student = new T_Student()
                    {
                        ClassesID = classes.ID,
                        Name = "张三",
                        Phone = "15236265820",
                        Sex = true,
                        ProvinceID = area1.ID,
                        CityID = area2.ID,
                        CountyID = area3.ID,
                    };
                    db.T_Student.Add(student);
                    db.SaveChanges();
                }
                return View();
            }
    复制代码

    第四步:

    查看数据库数据

    Demo完整代码下载

    EFDemo.Core.7z

    转载自:http://www.cnblogs.com/eggTwo/p/5959158.html

  • 相关阅读:
    Http系列目录
    C# 锁系列目录
    RabbitMQ系列目录
    Zookeeper系列目录
    Spring Boot系列目录
    SOAP系列目录
    DynamicProxy系列目录
    网络通信系列目录
    分析windows .net程序dump文件的两种方式
    Code Review Checklist
  • 原文地址:https://www.cnblogs.com/icebutterfly/p/9254658.html
Copyright © 2020-2023  润新知