EntityFramework(一)

前言

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

数据库和表基本创建

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

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

    public class Student
    {
        public Student()
        {

        }
        public int StudentID { get; set; }
        public string StudentName { get; set; }

    }

    public class Standard
    {
        public Standard()
        {

        }
        public int StandardId { get; set; }
        public string StandardName { get; set; }

    }

第二步:继承EF上下文DbContext

    public class SchoolContext : DbContext
    {
        public SchoolContext("name=DBConnectionString")
        {

        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }

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

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

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

            using (var ctx = new SchoolContext())
            {
                Student stud = new Student() { StudentName = "New Student" };

                ctx.Students.Add(stud);
                ctx.SaveChanges();
            }

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

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

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

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

    public class Student
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public int Age { get; set; }

        public virtual Course Course { get; set; }
    }

    public class Course
    {
        public int StudentID { get; set; }

        public string Name { get; set; }

        public virtual Student Student { get; set; }
    }

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

public class EntityDbContext : DbContext
    {
        public EntityDbContext()
            : base("name=test2")
        { }

        /// <summary>
        /// 通过反射一次性将表进行映射
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {

            var typesRegister = 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 typesRegister)
            {
                dynamic configurationInstance = Activator.CreateInstance(type);
                modelBuilder.Configurations.Add(configurationInstance);
            }

        }
    }

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

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

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

      EntityDbContext ctx = new EntityDbContext();

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

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

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

SqlLocalDB.exe start v11.0

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

SqlLocalDB.exe info v11.0

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

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

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

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

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

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

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

     /// <summary>
    /// 当对象实体对象发生改变时重生创建数据库
    /// </summary>

    public class EntityDbContextInit : DropCreateDatabaseIfModelChanges<EntityDbContext>
    {
        protected override void Seed(EntityDbContext context)
        {
            base.Seed(context);
        }
    }

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

    static EntityDbContext()
    {

        Database.SetInitializer<EntityDbContext>(new EntityDbContextInit());
    }

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

StudentMap(学生类实体映射)

    public class StudentMap : EntityTypeConfiguration<Student>
    {
        public StudentMap()
        {
            ToTable("Student");
            HasKey(d => d.ID);

            //HasRequired(p => p.Course).WithRequiredDependent(i => i.Student);
            //HasRequired(p => p.Course).WithOptional(i => i.Student);

            HasRequired(p => p.Course).WithRequiredPrincipal(p => p.Student);
            HasOptional(p => p.Course).WithRequired(p => p.Student);

            /*             对于上述映射关系不太理解的话可以去上述给出链接文章。我只说明怎么去很好的理解这两组的意思,第一组 WithRequiredDependent 和第二组             WithRequiredPrincipal 一个是Dependent是依赖的意思说明后面紧接着的Student是依赖对象,而前面的Course是主体,而Principal
             首先的意思,说明后面紧接着的是Student是主体,而Course是依赖对象。很显然在这个关系中课程是依赖学生的。所以映射选第二组              */
        }
    }

CourseMap(课程类映射)

    public class CourseMap : EntityTypeConfiguration<Course>
    {
        public CourseMap()
        {
            ToTable("Course");
            HasKey(p => p.StudentID);
        }
    }

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

            EntityDbContext ctx = new EntityDbContext();
            var s = new Student()
            {
                Name = "1",
                Age = 12,
                Course = new Course() { Name = "12" }
            };

            ctx.Set<Student>().Add(s);
            ctx.SaveChanges();

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

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

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

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

  EntityDbContext ctx = new EntityDbContext();

  var list = ctx.Set<Student>().ToList();

  或者

  SqlParameter[] parameter = { };
  var list = ctx.Database.SqlQuery<Student>("select * from student", parameter);

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

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

var list = ctx.Set<Student>().ToList();

var jsonString = JsonConvert.SerializeObject(list);

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

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

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

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

或者

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

对象转换成功,如下:

序列化成功结果如下:

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

 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获得的数据集合对象为代理对象,需要先转换为实体对象才能进行序列化或者其他操作。

时间: 2024-10-11 16:55:18

EntityFramework(一)的相关文章

EntityFramework 4使用存储过程分页

1 CREATE PROC usp_OrgPage_SQL 2 @pageIndex INT, 3 @pageSize INT, 4 @totalCount INT OUTPUT 5 AS 6 BEGIN 7 SET @totalCount = (SELECT COUNT(*) FROM dbo.Organization) 8 SELECT * FROM 9 ( 10 SELECT *,ROW_NUMBER() OVER(ORDER BY OrganizationID DESC)AS row F

EntityFramework 简单入个门

任何一个和数据相关的系统里,数据持久化都是一个不容忽视的问题. 一直以来,Java 平台出了很多 NB 的 ORM 框架,Hibernate.MyBatis等等..NET 平台上,ORM 框架这一块一直没有一个能吊到让几乎所有开发人员改掉以拼写 SQL 语句访问数据库的习惯. 实际上,在 .NET 平台上,也层出不穷的出现了很多类似的玩意儿,比如Nhibernate.Ibatis,还有微软的亲儿子--坑爹的 LinqToSQL.虽然这么多框架,但是真的没见过 .NET 平台的 ORM 框架能像

EntityFramework Core 1.1有哪些新特性呢?

前言 在项目中用到EntityFramework Core都是现学现用,及时发现问题及时测试,私下利用休闲时间也会去学习其他未曾遇到过或者用过的特性,本节我们来讲讲在EntityFramework Core 1.1中出现了哪些新特性供我们使用. EntityFramework Core 1.1新特性探讨 DbSet.Find 在EF 6.x中也有此方法的实现,在EF Core 1.1中也同样对此方法进行了实现,为什么要拿出来讲呢,当然也有其道理,我们一起来看看.在         public 

EntityFramework Core Raw SQL

EntityFramework Core Raw SQL 基础查询(执行SQL和存储过程) 啥也不说了,拿起键盘就是干,如下:     public class HomeController : Controller     {        private IBlogRepository _blogRepository;        public HomeController(IBlogRepository blogRepository)         {             _blo

EntityFramework 学习 一 并发

EntityFramework默认支持乐观并发 乐观并发中,实体加载后如果都没发生变化,ef保存该实体 首先,我们需要一个rowversion列为了控制student实体的并发问题,rowversion的数据类型为字节数组,rowversion像是自增id, rowversion的值在数据库当中自动添加和更新 ef将在where子句中添加rowversion列,当你进行更新操作,如果rowversion的值与where子句中的值不一致,则抛出异常 Student student1WithUser

EntityFramework Core Raw Query再叙注意事项后续

前言 话说通过EntityFramwork Core进行原始查询又出问题,且听我娓娓道来. EntityFramework Core Raw Query后续 当我们进行复杂查询时我们会通过原始查询来进行,我们定义如下ViewModel public class BlogViewModel { public int Id { get; set; } public string Name { get; set; } public string Url { get; set; } public str

entityframework.extended安装

在开始学习EF过程中,发现EF的批量更新和批量删除比较缓慢,在网上搜索到entityframework.extended 插件很好的解决了这个问题,故此想下载安装学习一下,下面是自己再安装过程中遇到的问题以及解决方法. 一.entityframework.extended 安装步骤: 出现错误提示如下: 二.解决问题方法 1.找到DNS服务器地址 再网上经过一番查找好,这篇博客给予了我启发http://blog.csdn.net/bklydxz/article/details/50967498,

EntityFramework、Dapper vs 草根框架性能

EntityFramework.Dapper vs 草根框架性能 扯淡 当前市面上 ORM 很多,有跑车型的,如 Dapper,有中规中矩型的,如 Mybatis.Net,也有重量型的,如 EntityFramework 和 NHibernate,还有一些出自草根之手的,如 Chloe.ORM.各式各样,层出不穷.试问,为何要重复造轮子?很简单,咱来自火星,目前地球上还没一款轮子适合咱这辆火星车~ 为加深对各个 ORM 框架的了解,同时也想看看咱自己的框架性能如何,也可以让对 Chloe 感兴趣

Asp.net 面向接口可扩展框架之数据处理模块及EntityFramework扩展和Dapper扩展(含干货)

面向接口数据处理模块是什么意思呢?实际上很简单,就是使用面向接口的思想和方式来做数据处理. 还提到EntityFramework和Dapper,EntityFramework和Dapper是.net环境下推崇最高的两种ORM工具. 1.EntityFramework是微软出的根正苗红的.netd的ORM工具,直接在Vs工具和Mvc框架中集成了,默认生成的项目就是使用EntityFramework的;微软也一直都在维护更新升级,最新版本最新版本都在EF7了.也迁移到了最新的.net Core平台了

EntityFramework学习

本文档主要介绍.NET开发中两项新技术,.NET平台语言中的语言集成查询技术 - LINQ,与ADO.NET中新增的数据访问层设计技术ADO.NET Entity Framework.ADO.NET的LINQ to Entity部分以LINQ为基础,为了完整性首先介绍LINQ技术. 预备知识 LINQ技术 LINQ是.NET 3.5中新增的一种技术,这个技术扩展了.NET平台上的编程语言,使其可以更加方便的进行数据查询,单纯的LINQ技术主要完成对集合对象(如System.Collection下