前言

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(, int.MaxValue, ErrorMessage = "{0}的范围是{1}到{2}")]
[DefaultValue()]
public int Sort { get; set; }
[Display(Name = "备注")]
[MaxLength(, 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(, 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(, ErrorMessage = "{0}最大长度{1}")]
public string Name { get; set; } [Display(Name = "人数")]
public int Count { get; set; } [Display(Name = "班级经费")]
public decimal Money { 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_Student : BaseEntity<int>
{ /// <summary>
/// 外键
/// </summary>
[ForeignKey("ClassesID")]
public virtual T_Classes T_Classes { get; set; }
[Display(Name = "班级ID")]
public int ClassesID { get; set; } [Display(Name = "姓名")]
[Required(ErrorMessage = "{0}是必填项")]
[MaxLength(, ErrorMessage = "{0}最大长度{1}")]
public string Name { get; set; } [Display(Name = "性别")]
public bool Sex { get; set; } [Display(Name = "年龄")]
public int Age { get; set; } [Display(Name = "电话")]
[Required(ErrorMessage = "{0}是必填项")]
[RegularExpression(@"^(13[0-9]|15[0-9]|18[0-9])\d{8}$", ErrorMessage = "不是手机号格式")]
[MaxLength(, ErrorMessage = "{0}最大长度{1}")]
public string Phone { get; set; } /// <summary>
/// 省市县外键
/// </summary> [ForeignKey("ProvinceID")]
public virtual Public_Area Public_Area_Province { get; set; }
[Display(Name = "省ID")]
public Guid ProvinceID { get; set; } [ForeignKey("CityID")]
public virtual Public_Area Public_Area_City { get; set; }
[Display(Name = "市ID")]
public Guid CityID { get; set; } [ForeignKey("CountyID")]
public virtual Public_Area Public_Area_County { get; set; }
[Display(Name = "县ID")]
public Guid CountyID { get; set; }
}
}

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

项目位置:

使用命令生成数据库

第一步:将实体对象加入到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 =
};
db.T_Classes.Add(classes);
T_Student student = new T_Student()
{
ClassesID = classes.ID,
Name = "张三",
Phone = "",
Sex = true,
ProvinceID = area1.ID,
CityID = area2.ID,
CountyID = area3.ID,
};
db.T_Student.Add(student);
db.SaveChanges();
}
return View();
}

第四步:

查看数据库数据

Demo完整代码下载

EFDemo.Core.7z

下一篇:EF查询之性能优化技巧

EF使用CodeFirst方式生成数据库&技巧经验的更多相关文章

  1. 2.EF中 Code-First 方式的数据库迁移

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/code-first-migrations-with-entity-framework/ 系列目 ...

  2. EF中 Code-First 方式的数据库迁移

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/code-first-migrations-with-entity-framework/ 系列目 ...

  3. 学习EF之CodeFirst二(数据库对应映射)

    在上一篇文章我们简单通过一个实例完成对CodeFirst的理解,我们通过实体生成数据库里的表和字段,虽然有一些默认的配置生成规定,但其实我们可以能过对实体进一步控制从而对生成的表字段进行更加符合我们要 ...

  4. EntityFramework系列:SQLite.CodeFirst自动生成数据库

    http://www.cnblogs.com/easygame/p/4447457.html 在Code First模式下使用SQLite一直存在不能自动生成数据库的问题,使用SQL Server C ...

  5. ASP.NET MVC5利用EF,反向自动生成数据库

    1.在Model类里面,写好相应的属性. using System; using System.Collections.Generic; using System.Linq; using System ...

  6. 【EF6学习笔记】(一)Code First 方式生成数据库及初始化数据库实际操作

    本篇参考原文地址: Creating an Entity Framework Data Model 说明:学习笔记参考原文中的流程,为了增加实际操作性,并能够深入理解,部分地方根据实际情况做了一些调整 ...

  7. EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作

    EF6 学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 本篇参考原文地址: Creating an Entity Framework Data Model 说明:学习 ...

  8. .Net Core建站(2):EF Core+CodeFirst数据库迁移

    上一篇的话,说了下怎么使用EF7 实现 CodeFirst去生成数据库, 其实还有好多问题的,这次一点一点的解决吧,都挺简单,不过零零散散的,, 1.读取配置文件,获得链接字符串 2.使用数据库进行增 ...

  9. 第十七节: EF的CodeFirst模式的四种初始化策略和通过Migration进行数据的迁移

    一. 四种初始化策略 EF的CodeFirst模式下数据库的初始化有四种策略: 1. CreateDatabaseIfNotExists:EF的默认策略,数据库不存在,生成数据库:一旦model发生变 ...

随机推荐

  1. GO语言之channel

    前言: 初识go语言不到半年,我是一次偶然的机会认识了golang这门语言,看到他简洁的语法风格和强大的语言特性,瞬间有了学习他的兴趣.我是很看好go这样的语言的,一方面因为他有谷歌主推,另一方面他确 ...

  2. Index

    我主要在研究.NET/C# 实现 PC IMERP 和 Android IMERP ,目的在解决企业通信中遇到的各类自动化问题   分布式缓存框架: Microsoft Velocity:微软自家分布 ...

  3. jquery禁用文本框

    禁用文本框 //文本框禁用 $("input[type='text']").each(function () { $("#" + this.id).attr(& ...

  4. 【无私分享:ASP.NET CORE 项目实战】目录索引

    简介 首先,我们的  [无私分享:从入门到精通ASP.NET MVC]   系列已经接近尾声,希望大家在这个过程中学到了一些思路和方法,而不仅仅是源码. 因为是第一次写博客,我感觉还是比较混乱的,其中 ...

  5. 【无私分享:ASP.NET CORE 项目实战(第九章)】创建区域Areas,添加TagHelper

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 在Asp.net Core VS2015中,我们发现还有很多不太简便的地方,比如右击添加视图,转到试图页等功能图不见了,虽然我 ...

  6. 网页mp3语音展示,点击图片放大,点击图片跳转链接,调表格

    查看mp3语音 <td class="value"><embed src="${sounds.soundName}" type="a ...

  7. PHP HTTP请求

    stream_context_create 1.curl仍然是最好的HTTP库,没有之一. 可以解决任何复杂的应用场景中的HTTP 请求2. 文件流式的HTTP请求比较适合处理简单的HTTP POST ...

  8. css和@import区别用法

    css和@import都是调用外部样式表的方法. 一.用法 (1)link: <link rel="stylesheet" type="text/css" ...

  9. 网站logo正确写法,个人拙见,不喜勿喷

    网站logo既要考虑seo又需要用图片代替网站名字,所有H1标签带来的权重还是需要使用 有些人喜欢直接把<H1></H1>标签直接hidden掉,个人喜欢使用css Text- ...

  10. iOS 10对隐私权限的管理(必须要改否则会crash)

    比如访问的摄像头.麦克风等硬件,都需要提前请求应用权限.允许后才可以使用,或者现在要提前声明,虽然以往要求不严格.比如在iOS10中访问通讯录时,强制必须在Info.plist中加入NSContact ...