zoukankan      html  css  js  c++  java
  • Entity Framework学习记录

     主要转自教程:https://www.cnblogs.com/wyy1234/p/9650759.html (作者:捞月亮的猴子)

    EF框架三种方式:

    EF框架有三种基本的方式:DB First,Model First,Code First

    DB First:

    首先,要有数据库(可以无表,后面创建再导)

    接着,创建 实体数据库模型 

    这种方式,即使数据库有数据,也不怕丢失。

    Code First:

    直接代码创建

    似乎需要引用 system.data.entity,Entity Framwork,Entity Framwork.sqlserver(未验证)

    Model First:

    新建模型,添加实体(表),以模型去更新数据库

    查询语句:

    (来源:https://www.cnblogs.com/wyy1234/p/9628399.html)

    1,L2E查询:

    L2E查询时可以使用linq query语法,或者lambda表达式,默认返回的类型是IQueryable,(linq查询默认返回的是IEnumerable)

    //查询名字为ls的用户集合
    //query语法
    var users = from u in context.UserInfo
                where u.UserName == "ls"
                select u;
    //method语法
    var users2 = context.UserInfo.Where<UserInfo>(user => user.UserName == "ls");

    2,原生SQL查询:

    (1)DbSet.SqlQuery()

    返回的结果是DbSqlQuery类型,该类型实现了IEnumberable接口,所以结果集也可以用linq操作

    //查询名字为ls,密码是123321的用户集
    //使用占位符,执行的时候自动生成sql参数,不用担心sql注入
    var user1 = context.UserInfo.SqlQuery("select * from userinfo where username=@p0 and userpass=@p1", "ls", "123");
      
    //自己设sql参数
    SqlParameter [] pars= {
    new SqlParameter("@name", SqlDbType.NVarChar, 20) { Value = "ls" },
    new SqlParameter("@pass", SqlDbType.NVarChar, 20) { Value="123"}
    };
    var user2 = context.Database.SqlQuery<UserInfo>( "select * from userinfo where username=@name and userpass=@pass", pars);
     
    //查询用户人数
    int count = context.Database.SqlQuery<int>("select count(*) from userinfo").SingleOrDefault();

    (2)Database.SqlQuery()

    context.Database对应着底层数据库,Database.SqlQuery用于查询,可以返回任意类型。

    using (var ctx = new SchoolDBEntities())
    {
        //获取ID为1的student的名字
        string studentName = ctx.Database.SqlQuery<string>("Select studentname from Student where studentid=@id", new SqlParameter("@id", 1))
                                .FirstOrDefault();
    }

    (3)Database.ExecuteSqlCommand()

    Database.ExecuteSqlCommand()用于通过Sql进行CUD操作,返回int类型(受影响的行数)

    using (var ctx = new SchoolDBEntities())
    {
      //修改
        int noOfRowUpdated = ctx.Database.ExecuteSqlCommand("Update student  set studentname ='changed student by command' where studentid=@id", new SqlParameter("@id", 1));
     //添加
        int noOfRowInserted = ctx.Database.ExecuteSqlCommand("insert into student(studentname) values('New Student')");
     //删除
        int noOfRowDeleted = ctx.Database.ExecuteSqlCommand("delete from student where studentid=@id",new SqlParameter("@id", 1)); 
    }

    EF中实体关系:

    (来源:https://www.cnblogs.com/wyy1234/p/9627676.html)

    EF与数据库一样支持三种关系类型:①一对一 ,②一对多,③多对多。

    1,一对一关系:

    如上图,Student和StudentAddress具有一对一的关系(零或一)。一个学生只能有一个或零个地址。实体框架将Student实体导航属性添加到StudentAddress实体中,将StudentAddress实体导航属性添加到Student实体中。同时,StudentAddress类中将StudentId作为PrimaryKey和ForeignKey属性,这样Student和StudentAddress就成为一对一的关系。

    StudentId属性在StudentAddress类中是同时是PrimaryKey和ForeignKey。我们可以在context的OnModelCreating方法中使用Fluent API进行配置。

    2,一对多关系:

    Standard与Teacher实体具一对多的关系。这表示多个教师评同一个级别(成绩级别A,B,C,D),而每个教师只能评一个级别,如给学生1评A级的同时不能再评一个B级。

    public partial class Standard
    {
        public Standard()
        {
            this.Teachers = new HashSet<Teacher>();
        }
        
        public int StandardId { get; set; }
        public string StandardName { get; set; }
        public string Description { get; set; }
        //集合导航属性
        public virtual ICollection<Teacher> Teachers { get; set; }
    }
    
    public partial class Teacher
    {
        public Teacher()
        {
            this.Courses = new HashSet<Course>();
        }
        public int TeacherId { get; set; }
        public string TeacherName { get; set; }
        public Nullable<int> TeacherType { get; set; }
        //外键
        public Nullable<int> StandardId { get; set; }
        //实体导航属性
        public virtual Standard Standard { get; set; }
    }

    Standard实体具有集合导航属性 Teachers (请注意它是复数),这表明一个Standard可以有一个教师集合(老师1和老师2都可以给A级的评分)。而Teacher实体具有Standard实体导航属性,表明每个Teacher只能评一个Standard,同时Teacher中包含StandardId外键。这样Standard与Teacher就成为了一对多的关系。

    3,多对多:

    Student和Course具有多到多关系。这表示一个学生可以参加许多课程,而一个课程也可以向许多学生讲授。
    数据库包括StudentCourse中间表,表中只包含Student和Course的主键。
    如上图所示,Student实体包含集合导航属性 Courses,Course实体包含集合导航属性 Students以表示它们之间的多对多关系。这两个表都没有外键关系,它们通过StudentCourse中间表进行关联。

    注:实体框架在中间表仅有两个表的主键(只有StudentId和CourseId)时才自动维护多对多关系。当我们给Student添加一个Course或给Course添加一个Student,执行SaveChange()时,EF会在中间表自动会插入对应的StudentId和CourseId。如果中间表包含其他列,那么EDM也会为中间表创建实体,EF不再自动维护中间表,那么我们就需要手动管理多对多实体的CRUD操作。

    EF中的高并发:

    EF6中database-first开发方案的高并发解决方案:(https://www.cnblogs.com/wyy1234/p/9639040.html)

    EF默认支持乐观并发:我们从数据库加载了一条数据,这是有人修改了这条数据,而我们手中用的还是旧数据,这就出现了脏读,这个时候我们修改了这条数据然后执行SaveChange()会发生什么呢?EF在保存数据时会首先查看数据库中的数据有没有改变过,数据没有改变就执行保存;数据改变了会抛出异常,我们再次提交前必须解决冲突(提到解决冲突是不是想到了git提交中的冲突?EF中解决高并发的方法和git提交的方法采用的思想是一样的,往下看就知道了)。

    1.添加RowVersion列

      在EF中database-first开发模式中,为了解决高并发问题我们可以为数据表填加一个timestamp类型的的列,列名为rowversion,rowversion是一个二进制的数据,在每次的添加/修改操作后rowversion的值都会变大

    以Student实体为例,给Student表添加一个Rowversion列,类型为timestamp,如下所示:

    2.生成/升级EMD

    如果没有EDM通过数据库生成新的实体数据模型,如果有EDM则右击设计器->Update Model From Database ->Refresh Student table,这时我们就可以在设计器中看到RowVersion属性了,RowVersion属性的Concurrency Mode设置为Fixed,如下图

    做完这两步,EF API在执行Update时,会把RowVersion添加到where子句中(就像这样:update tb set cloName=xxx where Id=@id and RowVersion=@rowversion),如果where子句中的RowVersion值和数据库中的不一样就抛出DbUpdateConcurrencyException。

  • 相关阅读:
    数据库ALL和ANY的区别
    数据库-关系代数-投影
    数据库关系代数表达式学习
    数据模型的三要素
    题解 P2812 【校园网络【[USACO]Network of Schools加强版】】
    题解 P2746 【[USACO5.3]校园网Network of Schools】
    题解 P2257 【YY的GCD】
    题解 P6476 【[NOI Online #2 提高组]涂色游戏】
    题解 P2522 【[HAOI2011]Problem b】
    题解 P4782 【【模板】2-SAT 问题】
  • 原文地址:https://www.cnblogs.com/clis/p/12348028.html
Copyright © 2011-2022 走看看