ASP.NET Entity Framework多表联合很头大?一文帮你解决它
场景描述
前面说过一篇EntityFramework入门级的增删改查,可能刚刚接触EF时,都是拿一张学生表,增删改查慢慢学习EF提倡的以面向对象的思想去操作数据库(至少我在学习的时候是这样滴)。再进一步学习会发现,实际情况中我们时常会遇到下面的情况:
主表 电影表:
从表1 电影类型表:
从表2 国家表:
三表之间约束关系:
相信这个场景太常见了叭,两个一对多关系,主键表里面含有两个外键。我们向view展示数据的时候应该把typeId,cid转显示为用户能读懂的typeName,cname吧,这是一个极其常规的需求。
每种情形在EF中都用四种办法来解决,帮你踩雷,相信我,总有适合你的一种!
代码干货
从简到繁,从两表到三表
------------------------------------------------------------------------------我是可爱的分割线-----------------------------------------------------------------------------------------
PS:后面会用到两个C#的语法糖,还是提一提吧,免得有的同学读不懂
1.匿名类对象
通常我们使用类的时候,一般要先定义类,并且定义字段,封装属性。
但是在我们某个时刻要使用一个类,相当于临时使用一次时,C#3.0推出的匿名类对象来解决这个问题,通常与推断类型var结合使用,因为匿名类对象没有特定的类名。
写法如下:
这样我们就实例化了一个匿名类对象student,通过var推断出匿名类对象student属于这样的一个类型。
2.自动推断成员名称
当我们有一个movie对象m和一个movieType对象mt时,我希望通过生成一个新的对象包含m,mt两个对象的属性和值,这时候我们就想到了刚说的匿名类对象,通常会这样写
代码如下:
var model =new {
mid = m.mid,
mname = m.mname,
createtime = m.createtime,
typeId = m.typeId,
typeName = mt.typeName
};
但是我们发现如果新生成的匿名类对象中的属性名和原来m,mt的属性名保持一致时(通常我们都会保持一致),我们的代码可以这样写:
var model = new { m.mid, m.mname, m.createtime, m.typeId, mt.typeName };
就比如:m.mid=5时,model里面就会自动生成mid属性并且值为5
这样写非常方便、简洁!
-------------------------------------------------------------------------------我是可爱的分割线-----------------------------------------------------------------------------------------
一、两表联合 (这里取movie和movieType联合)
① 方法一:Linq语句
MoviesEntities entities = new MoviesEntities();//最开始实例化过了 后面就不再写了
var list = (from m in entities.movie
join mt in entities.movieType on m.typeId equals mt.typeId
select new
{
m.mid,m.mname,m.createtime,m.typeId,mt.typeName
}).ToList();
这个Linq语句没啥好说的叭!
②方法二:Linq方法
var list11 = entities.movie.Join(entities.movieType, m => m.typeId, mt => mt.typeId, (m, mt) => new
{
m.mid,
m.mname,
m.createtime,
m.typeId,
mt.typeName
}).ToList();
这里主要用的是Join()方法 我们看下这个方法的参数定义叭(*^▽^*)
我相信小白们,头一次看这个参数定义的时候一定是这样的吧!
不慌不慌我们细心分析一下就行。
③ 方法三:原生sql (原汁原味)
但是此处要指定泛型T,所以我们要自己去写一个新类MovieDetail了。
var list2 = entities.Database.SqlQuery<MovieDetail>("select m.*,mt.typeName from movie as m inner join movieType as mt on m.typeId=mt.typeId").ToList();
④方法四:建立视图(简单粗暴)
我们在SqlServer中对movie表和movietype表根据外键做一个VMovie视图
之后将这个视图添加到edmx模型中,完成之后,重新生成结局方案 两表联合的数据就有了 直接用VMovie拿来用
var list3 = entities.VMovie.ToList();
利用视图,虽然简单、快捷,但是还是有坑滴
二、三表联合
①方法一:Linq语句
在两表连接后继续join即可
var list1 = (from m in entities.movie
join mt in entities.movieType on m.typeId equals mt.typeId
join c in entities.country on m.cid equals c.cid
select new
{
m.mid,
m.mname,
m.createtime,
m.typeId,
m.cid,
mt.typeName,
c.cname
}).ToList();
②方法二:Linq方法
这里可能会有点绕,为什么第一次联合后赋一个m,因为最后我们构造新的匿名类对象时,要用到m中的各个属性,同时这个第二次Join中的a是第一次Join后返回的匿名类对象。这里确实比较绕-_-||
var list2 = entities.movie.Join(entities.movieType, m => m.typeId, mt => mt.typeId, (m, mt) => new
{
mt.typeName,m
}).Join(entities.country, a => a.m.cid, c => c.cid, (a, c) => new
{
a.m.mid,
a.m.mname,
a.m.createtime,
a.m.cid,
a.m.typeId,
a.typeName,
c.cname
}).ToList();
③方法三:原生sql
var list3=entities.Database.SqlQuery<MovieDetail>(@"select m.*,mt.typeName,c.cname from (movie as m inner join movieType as mt on m.typeId=mt.typeId) inner join
country as c on m.cid = c.cid").ToList();
④方法四:建立视图
视图约束关系:
var list3 = entities.VMovie.ToList();
----------------------------------------------------------------------------我是可爱的分割线--------------------------------------------------------------------------------------------
EF中使用视图的踩坑小记
坑一:
警告 6002: 表/视图 未定义主键
这个警告很烦人,每次生成的时候后,都会弹这个警告,因为EF没有检测到表/视图中的主键,但是我们可能会说,我在SqlServer建立的视图压根就没有特定的主键啊!
解决方案:
使用人家EF,你就要迎合人家的规则,在视图创建的时候,加一列值不重复且为 not null的列就行了,EF就检测到有主键了,就不会再警告你啦 一般加一列Guid或者是RowNumber
select ISNULL(NEWID(), '5757E7EF-2F19-4408-B413-8F1B33B9895F') AS id,col1,col2,col3
from xxxx
这时候,你再回到edmx中从数据库更新模型后会发现,警告6002依旧存在!!!
没关系,关闭VisualStudio,重新打开,警告就消失了
好了这个坑 完美解决
坑二:
操作VMovie的时候使用Find()方法
前几天再给几个同学改代码的时候,发现他们习惯性的使用Find()查对象,最后在VMovie上使用Find()传个ID就报错了。
因为Find()是根据主键查对象的,VMovie是个视图,本身就没有自己特定的主键,为了解决坑一,我们加了一个GUID主键,所以当然不能像单表查询那样,传一个主键来解决问题了。
解决方案:
使用FirstOrDefault或者Where
坑三:
直接对VMovie进行增删改
因为VMovie的本质是个视图,数据库中的一张虚拟表,我们把视图添加到edmx中只是为了查询数据方便,不能直接进行增删改
解决方案:
直接对主表movie进行增删改,视图会进行自动更新
结
我相信看完这篇博客之后,使用EF处理简单的多表联合就不是什么难事了吧,当初我在学习的时候,也是遇到各种各样的问题,去网上也搜了各种方法,但是都是就事论事,说的不全面,有的还根本行不通,但是现在各种方法都有了,坑都踩了,大胆向前冲吧 !