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

补充

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

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

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

时间: 2024-10-10 05:39:49

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

经典解密数据库和表的创建

    创建数据库和表是学习大数据必备的知识,那么数据库和表如何创建呢?使用Impala和Hive创建数据库和表又有什么区别呢? 数据库和表通过HiveQL或ImpalaSQL的DDL语句进行创建和管理,和标准SQL DDL非常相似.但是它们又有各自不同的语法,这个差异会在后面具体提出来,如果没有提到就是两者相通的. 一.创建数据库 Hive和Impala数据库就是简单的命名空间,用来统一管理一部分表和视图.数据库在HDFS上的体现就是一个建立在表上的目录. (1)创建新的数据库: 这是和所有关

实验二 数据库和表的创建与管理

实验二 数据库和表的创建与管理  创建用于企业管理的员工管理数据库,数据库名为YGGL中,YGGL数据库中包括三个表:Employees(员工信息表).Departments(部门信息表).Salary(员工薪水情况表).各表的结构如下表: 表1   Employees表结构 列名 数据类型 长度 是否允许为空 说明 EmployeeID char 6 not null 员工编号,主键 Name char 10 not null 姓名 Education char 4 not null 学历 B

数据库和表的创建(SQLiteOpenHelper)

1.Android为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类就可以非常简单地对数据库进行创建和升级.SQLiteOpenHelper是一个抽象类,如果想使用它的话,就要创建一个自己的帮助类(这里我们以自己创建的MySqliteHelper类去继承)去继承它.SQLiteOpenHelper中有两个抽象方法,分别是onCreate()和onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后在这两个方法中实现创建.升级数据库的

数据库与表的创建及增删改查

TSQL语句: [“.sql”结尾的文件是:保存用户对数据库和表操作的过程代码.注意:随时 ctrl+s 保存一下 字段名就是列名!] 一.数据库 1.创建数据库: create database [数据库名称],选中该行语句,点击“执行”或者选中按 F5,消息返回“命令已成功完成”,新数据库就创建完成啦! 如果你在“对象资源管理器”中找不到新建的数据库,那就右击“数据库”,点击“刷新”,就可以看到了 2.删除数据库: drop database [要删除的数据库],选中该行语句,点击“执行”,

记录一次数据库某表未创建索引造成的问题

现象描述: 昨天鹰网监控告知廊坊某台物理机CPU使用率接近100%,查看得知每颗逻辑CPU的使用率都接近了100%,但该数据库机器是测试机器,按理说不会造成此问题.截图如下: 处理步骤: 1. 查看消耗大量CPU资源和I/O等待的PID 通过TOP命令即可查看 2. 通过PID查看正在执行的SQL SELECT sql_text FROM v$sqltext a WHERE (a.hash_value, a.address) IN (SELECT DECODE(sql_hash_value, 0

SQL server 数据库的表的创建与使用T-SQL语句操控数据表

表的创建与T-SQL语句的使用 一,表的创建与基本概念 表是包含数据库中所有数据的数据库对象,表定义是一个集合.数据在表中组织方式与在电子表格中相似,都是按行和列的格式组织的.每一行代表一条唯一的记录,每一列代表记录中的一个字段. **SQLserver 中的表包含下列主要组件 ** #列: 每一列代表由表的建模的对象的某个属性,列如,一个产品表有id 列,颜色列和重量列 #行: 每一行代表由表建模的对象的一个单独的实例 数据类型 表的创建 使用T-SQL语句操控数据表 1.查询王明的成绩?结果

20150504 SQL 数据库于表的创建与删除

一.创建数据库语句 create database 数据库名 on primary -- 默认就属于primary文件组,可省略(/*--数据文件的具体描述--*/ name=名字'HQ0128_data', -- 主数据文件的逻辑名称 filename='D:\数据库名.mdf', -- 主数据文件的物理名称 size=5mb, --主数据文件的初始大小 maxsize=100mb, -- 主数据文件增长的最大值 filegrowth=15%--主数据文件的增长率)log on(/*--日志文

SQLSERVER数据库、表的创建及SQL语句命令

SQLSERVER数据库,安装.备份.还原等问题: 一.存在已安装了sql server 2000,或2005等数据库,再次安装2008,会出现的问题 1.卸载原来的sql server 2000.2005,然后再安装sqlserver 2008,否则经常sql server服务启动不了 2.sql server服务启动失败,解决方法: 进入sql serverconfigure manager,点开 Sql server 网络配置(非sql native client 配置),点sqlzhh(

数据库及表的创建

一·.数据库的创建 表:存放数据库及关系的主要形式,是最主要的数据库对象 视图:视图是一个或多个基本表中生成的引用表. 约束:用于保障数据的一致性与完整性,具有代表的约束是主键和外键,主键约束当前表记录的主键字段唯一性,外键约束当前表和其他表的关系 存储过程:存储过程是一组为了完成特定功能的SQL语句几何,它存储于数据库中存储过程具有名称,它能够接受参数,输出参数,返回单个或多个值,存储过程独立于表存在 触发器:触发器基于一个表的操作创建,编写若干条T-SQL语句,当操作发生时,这些T-SQL语