主要转自教程: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。