ASP.NET Entity Framework多表联合很头大?一文帮你解决它

场景描述

   前面说过一篇EntityFramework入门级的增删改查,可能刚刚接触EF时,都是拿一张学生表,增删改查慢慢学习EF提倡的以面向对象的思想去操作数据库(至少我在学习的时候是这样滴)。再进一步学习会发现,实际情况中我们时常会遇到下面的情况:

 主表 电影表:

<figcaption> 电影表 </figcaption>

从表1 电影类型表:

<figcaption> 电影类型表 </figcaption>

从表2 国家表:

<figcaption> 国家表 </figcaption>

 三表之间约束关系:

<figcaption> 约束关系 </figcaption>

 相信这个场景太常见了叭,两个一对多关系,主键表里面含有两个外键。我们向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处理简单的多表联合就不是什么难事了吧,当初我在学习的时候,也是遇到各种各样的问题,去网上也搜了各种方法,但是都是就事论事,说的不全面,有的还根本行不通,但是现在各种方法都有了,坑都踩了,大胆向前冲吧 !

 

全部评论

相关推荐

威猛的小饼干正在背八股:挂到根本不想整理
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务