前言

之前有学过EF一段时间那时EF才4.0似乎还不太稳定,而现在EF都已7.0版本,同时AspNet Identity都与此大有关联,看来是大势所趋于是开始学习EF,在学EF过程中也遇到一些小问题,特此录下,以备忘!

数据库和表基本创建

为了更好的循序渐进稍微概括下典型创建EF Code First过程(看之即懂,懂即略过)

第一步先定义两个类,如下:

  1. public class Student
  2. {
  3. public Student()
  4. {
  5.  
  6. }
  7. public int StudentID { get; set; }
  8. public string StudentName { get; set; }
  9.  
  10. }
  11.  
  12. public class Standard
  13. {
  14. public Standard()
  15. {
  16.  
  17. }
  18. public int StandardId { get; set; }
  19. public string StandardName { get; set; }
  20.  
  21. }

第二步:继承EF上下文DbContext

  1. public class SchoolContext : DbContext
  2. {
  3. public SchoolContext():base("name=DBConnectionString")
  4. {
  5.  
  6. }
  7.  
  8. public DbSet<Student> Students { get; set; }
  9. public DbSet<Standard> Standards { get; set; }
  10.  
  11. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  12. {
  13. base.OnModelCreating(modelBuilder);
  14. }
  15. }

学生上下文中构造函数中的name去读取如下配置文件来命名数据库名称: DBByConnectionString

  1. <add name="DBConnectionString"
  2. connectionString="Data Source=.;Initial Catalog=DBByConnectionString;Integrated Security=true"
  3. providerName="System.Data.SqlClient"/>
  4. </connectionStrings>

然后在控制台中通过EF上下文添加数据并保存,如下:

  1. using (var ctx = new SchoolContext())
  2. {
  3. Student stud = new Student() { StudentName = "New Student" };
  4.  
  5. ctx.Students.Add(stud);
  6. ctx.SaveChanges();
  7. }

最终生成数据库以及表如下图:

上述创建数据库的过程只需注意:可以手动通过添加构造函数的name来命名数据库名称或者无需添加name那么生成的数据库名称是以上下文中的命名空间+上下文类来命名数据库名称。

数据库创建以及表一劳永逸配置

下面创建方法是看过园友hystar(EF教程)而写的,确实是好方法,就搬过来了,为什么说一劳永逸呢?不明白的话,可以去看看他的文章!首先添加两个类Student(学生类)和Course(课程类)。

  1. public class Student
  2. {
  3. public int ID { get; set; }
  4.  
  5. public string Name { get; set; }
  6.  
  7. public int Age { get; set; }
  8.  
  9. public virtual Course Course { get; set; }
  10. }
  11.  
  12. public class Course
  13. {
  14. public int StudentID { get; set; }
  15.  
  16. public string Name { get; set; }
  17.  
  18. public virtual Student Student { get; set; }
  19. }

添加EFDbContext类并继承DbContext上下文,代码如下:

  1. public class EntityDbContext : DbContext
  2. {
  3. public EntityDbContext()
  4. : base("name=test2")
  5. { }
  6.  
  7. /// <summary>
  8. /// 通过反射一次性将表进行映射
  9. /// </summary>
  10. /// <param name="modelBuilder"></param>
  11. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  12. {
  13.  
  14. var typesRegister = Assembly.GetExecutingAssembly().GetTypes()
  15. .Where(type => !(string.IsNullOrEmpty(type.Namespace))).Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
  16. foreach (var type in typesRegister)
  17. {
  18. dynamic configurationInstance = Activator.CreateInstance(type);
  19. modelBuilder.Configurations.Add(configurationInstance);
  20. }
  21.  
  22. }
  23. }

由于是手动命名数据库名称,当然得读取配置文件

  1. <connectionStrings>
  2. <add name="test2"
  3. connectionString="Data Source=(localdb)\v11.0;Initial Catalog=test2;Integrated Security=true"
  4. providerName="System.Data.SqlClient"/>
  5. </connectionStrings>

上述配置要添加的数据库建立在VS2013自带的实例中!我们首先初始化数据库看看:

  1. EntityDbContext ctx = new EntityDbContext();

结果运行就出现如下经典错误:

  1. 在与SQLServer建立连接时出现与网络相关的或特定与实例的错误.未找到或无法访问服务器.请验证实例名称是否正确并且SQL SERVER已配置允许远程链接provide:命名管道提供程序,error:40 -无法打开到SQL Server的连接)

那肯定是无法连接到 (localdb)\v11. ,于是当我在服务器打开添加连接中添加服务器名为 (localdb)\v11. 时也是无法响应,连接不到!最终通过SqlLocalDB命令在Command Prompt(命令行)中输入

  1. SqlLocalDB.exe start v11.

启动该实例才算完事,主要原因是安装了SQL 2012默认启动的实例该SQL 2012而VS 2013中的实例被停止运行得手动启动,如果要查看其信息来查看是否已经启动,通过以下命令即可:

  1. SqlLocalDB.exe info v11.

VS2013中默认的实例应该是(localdb)\v11.0,如果在服务器中添加连接输入(localdb)\v11.0是错误的,你可以通过上述 SqlLocalDB.exe info v11. 命令复制并添加如图的字符串即可

似乎只要第一次启动了,以后每次都会连接上,不会再出现如上问题!

上述中我们对于EF上下文不用每次都初始化数据库,在EF中初始化数据库有三种策略:

CreateDatabaseIfNotExists:该项也是默认初始化数据库的一项,要是数据库不存在就创建数据库。

DropCreateDatabaseIfModelChanges:只要数据模型发生了改变就重新创建数据库。

DropCreateDatabaseAlways:只要每次初始化上下文时就创建数据库。

鉴于此我们在EFDbContext中采用第二种策略。创建一个初始化类的策略 EFDbContextInit

  1. /// <summary>
  2. /// 当对象实体对象发生改变时重生创建数据库
  3. /// </summary>
  4.  
  5. public class EntityDbContextInit : DropCreateDatabaseIfModelChanges<EntityDbContext>
  6. {
  7. protected override void Seed(EntityDbContext context)
  8. {
  9. base.Seed(context);
  10. }
  11. }

在EFDbContext静态构造函数中进行初始化此方法:

  1. static EntityDbContext()
  2. {
  3.  
  4. Database.SetInitializer<EntityDbContext>(new EntityDbContextInit());
  5. }

自此EFDbContext构建完毕!下面就是模型映射了,我们假设学生和课程是1:1关系,则我们添加的两个实体映射如下:

StudentMap(学生类实体映射)

  1. public class StudentMap : EntityTypeConfiguration<Student>
  2. {
  3. public StudentMap()
  4. {
  5. ToTable("Student");
  6. HasKey(d => d.ID);
  7.  
  8. //HasRequired(p => p.Course).WithRequiredDependent(i => i.Student);
  9. //HasRequired(p => p.Course).WithOptional(i => i.Student);
  10.  
  11. HasRequired(p => p.Course).WithRequiredPrincipal(p => p.Student);
  12. HasOptional(p => p.Course).WithRequired(p => p.Student);
  13.  
  14. /*
    对于上述映射关系不太理解的话可以去上述给出链接文章。我只说明怎么去很好的理解这两组的意思,第一组 WithRequiredDependent 和第二组
     WithRequiredPrincipal 一个是Dependent是依赖的意思说明后面紧接着的Student是依赖对象,而前面的Course是主体,而Principal
  1. 首先的意思,说明后面紧接着的是Student是主体,而Course是依赖对象。很显然在这个关系中课程是依赖学生的。所以映射选第二组
    */
  2. }
  3. }

CourseMap(课程类映射)

  1. public class CourseMap : EntityTypeConfiguration<Course>
  2. {
  3. public CourseMap()
  4. {
  5. ToTable("Course");
  6. HasKey(p => p.StudentID);
  7. }
  8. }

接下来我们进行添加数据并保存通过如下代码:

  1. EntityDbContext ctx = new EntityDbContext();
  2. var s = new Student()
  3. {
  4. Name = "",
  5. Age = ,
  6. Course = new Course() { Name = "" }
  7. };
  8.  
  9. ctx.Set<Student>().Add(s);
  10. ctx.SaveChanges();

数据添加和保存都已通过,接下来进行查询数据,查询数据有两种方式:

(1)直接通过EF中Set()方法获得数据集合

(2)通过EF中SqlQuery()方法通过sql语句查询

如要获得上述学生数据列表集合,可以通过如下操作:

  1. EntityDbContext ctx = new EntityDbContext();
  2.  
  3. var list = ctx.Set<Student>().ToList();
  4.  
  5. 或者
  6.  
  7. SqlParameter[] parameter = { };
  8. var list = ctx.Database.SqlQuery<Student>("select * from student", parameter);

于是我监视下返回的list集合中的数据类型,如图

oh,shit!和我们实际的实体类型不符,通过EF产生的却是 DynamicProxies ,于是到Sytem.Data.Entity类下去看看是个什么类型,居然没找到,估计看这单词意思就是运行时产生的动态代理对象。那么,你觉得是不是没什么影响了???那影响可大了,请看下面操作:

  1. var list = ctx.Set<Student>().ToList();
  2.  
  3. var jsonString = JsonConvert.SerializeObject(list);

我尝试将其序列化看看结果,一运行,oh,no!错误如下:

这意思是检测到在Course里面有Student属性,而Student类里又有Course这就相当于自己引用自己,导致了循环引用就成了死循环。(这就是因为 DynamicProxies 导致的结果)所以当前要将其代理对象转换为我们的实体对象即可。

则通过Select()方法投影将其代码进行改造后如下:

  1. var list = ctx.Set<Student>().Include(p => p.Course).ToList().Select(entity => new Student() { ID = entity.ID, Name = entity.Name, Age = entity.Age }).ToList();
  2.  
  3. 或者
  4.  
  5. var list = ctx.Set<Student>().Include("Course").ToList().Select(entity => new Student() { ID = entity.ID, Name = entity.Name, Age = entity.Age }).ToList();

对象转换成功,如下:

序列化成功结果如下:

【注意】你用EF获得数据集合后得 ToList() 因为此时集合对象为代理对象,否则进行转换将报错,代码如下:

  1. var list = ctx.Set<Student>().Include(p => p.Course).Select(entity => new Student() { ID = entity.ID, Name = entity.Name, Age = entity.Age }).ToList();

报错如下:

上述转换也叫DTO(Data Transfer Objects)数据转换为对象,像这种情况在EF中很常见。下面给出老外的用两张图在两个常见的场景中来展现关于DTO的概念:

 Getting Information: DAL=>BLL=>GUI

Insert Information: GUI=>BLL=>DAL

总结

(1)当安装了sql时则默认启动的是此实例,那么VS中的实例则会停止启动,需要通过SqlLocalDB命令进行启动。

(2)通过EF获得的数据集合对象为代理对象,需要先转换为实体对象才能进行序列化或者其他操作。

补充

在此感谢园友中华小鹰,经其提示用上述一劳永逸配置无法配置复杂类型!

  1. modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly());

通过上述代码既能配置实体类型也能配置复杂类型,用此方法更加精简!当然若你将复杂类型作为另一个类的导航属性时上述代码也是可以满足所需的!

EntityFramework之数据库以及表基本创建(一)的更多相关文章

  1. 【SQL必知必会笔记(1)】数据库基础、SQL、MySQL8.0.16下数据库、表的创建及数据插入

    文章目录 1.数据库基础 1.1 数据库(database) 1.2 表(table) 1.3 列和数据类型 1.4 行 1.5 主键 2.什么是SQL 3.创建后续练习所需数据库.表(MySQL8. ...

  2. SQL Server数据库(表的创建)

    表的创建 1.创建列(字段):列名+类型 2.设置主键列:能够唯一表示一条数据 3.设置唯一键:设计--索引/键--添加--唯一键(选择列)--确定 唯一键的内容不能重复 4.外键关系:一张表(从表) ...

  3. SQL语句(一)SQL和数据库数据表的创建

    SQL的组成 (1) 数据定义语言DDL(Data Definition Language) 用于数据库和数据表的创建.修改和删除等操作 CREATE (create) 创建数据库.数据表 ALTER ...

  4. MySQL数据库(8)----表的创建、删除、索引和更改

    MySQL允许使用 CREATE TABLE 语句和 DROP TABLE 语句来创建.删除表,使用 ALTER TABLE 语句更改其结构.CREATE INDEX 语句和 DROP INDEX 语 ...

  5. 【第四章】MySQL数据库的基本操作:数据库、表的创建插入查看

    MySQL数据库基本操作 创建表 create table 查看表结构 desc table, show create table 表完整性约束 修改表 alter table 复制表 create ...

  6. mysql - 数据库、表 的创建

    -- 创建数据库 CREATE DATABASE IF NOT EXISTS ibs_environ DEFAULT CHARACTER SET utf8; -- 切换数据库 USE ibs_envi ...

  7. olacle数据库员工表的创建,及插入数据,添加约束,删除列,查询数据的sql语句

    ---删除原有的员工表drop TABLE employee;---创建员工表CREATE TABLE employee       (       empno NUMBER(4) NOT NULL, ...

  8. sqliteExpert软件使用(创建数据库和表)

    sqliteExpert是sqlite数据库的可视化操作软件,通过该软件可以进行可视化的创建数据库以及表,免去了复杂的建表语句.首先在下面地址下载该软件http://www.ddooo.com/sof ...

  9. Android(java)学习笔记192:SQLite数据库(表)的创建 以及 SQLite数据库的升级

    一.数据库的创建 1.文件的创建      //引用,如果文件不存在是不会创建的   File  file = new File("haha.txt"):     //输出流写数据 ...

随机推荐

  1. Linux查看系统状态命令

    Linux查看系统状态命令       iostat iostat 命令详细地显示了存储子系统方面的情况.你通常用iostat来监控存储子系统总体上运行状况如何,并且在用户注意到服务器运行缓慢之前提早 ...

  2. 使用js_md5加密密码

    为什么在传输过程中要用md5对密码进行加密? 众所周知,我们在表单中的输入框输入了密码后,如果采用ajax的post或者get方式提交数据,在浏览器的newwork中就可以看到我们向后台传输的内容,其 ...

  3. 前端工具之-- Sublime

    开始学习前端知识,做一些笔记来记录下- 之前学习都是使用的dw 现在前端开发工具既轻便功能也够强大. 下面记录下常用的前端工具: Sublime3:需要安装第三方包,一般 Atom:继承度非常好 VS ...

  4. linux shell中不显示路径了,显示为-bash-4.1#的两种解决办法

    出现这个问题的原因是因为没有配置.bash_profile的问题,或者是我们不小心清空或删除了.bash_profile文件. 办法一:修改 ~/.bash_profile文件 步骤如下: vim ~ ...

  5. IDEA插件

    Key Promoter 快捷键提示插件,帮助你快速记住快捷键.当你用鼠标完成某功能时,它会指示有相应的快捷键来完成刚才的功能,同时指导你为经常重复的操作建立快捷键. SerialVersionUID ...

  6. SQL执行效率1

    第一种方法:使用insert into 插入,代码如下: ? 1 2 3 4 5 6 7 $params = array('value'=>'50′); set_time_limit(0); e ...

  7. H5文件操作api--持续完善中

    Drop Here <input type="file" onchange="upload(this)" /></p> <div ...

  8. java之数据结构之链表及包装类、包

    链表是java中的一种常见的基础数据结构,是一种线性表,但是不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针.与线性对应的一种算法是递归算法:递归算法是一种直接或间接的调用自身算法的过 ...

  9. C#_基础,初始化器

    对象初始化器 在没有对象初始化器之前,我们创建一个对象大概需要经过这么两个步骤,首先new一个对象,然后给每个字段赋值.而有了对象初始化器之后,原本需要几行代码才能完成的任务变成一行代码就可以完成,简 ...

  10. node(async原理)

    node中的async是用来实现同步操作的,提供包括map.Series等方法,本文不做赘述. 由于项目需要在浏览器端用了async.js,因此仔细看了下它的代码.原来,一直以为node是在服务端调用 ...