場景描述
前面說過一篇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處理簡單的多表聯合就不是什麼難事了吧,當初我在學習的時候,也是遇到各種各樣的問題,去網上也搜了各種方法,但是都是就事論事,說的不全面,有的還根本行不通,但是現在各種方法都有了,坑都踩了,大膽向前沖吧 !