天天看點

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

場景描述

   前面說過一篇EntityFramework入門級的增删改查,可能剛剛接觸EF時,都是拿一張學生表,增删改查慢慢學習EF提倡的以面向對象的思想去操作資料庫(至少我在學習的時候是這樣滴)。再進一步學習會發現,實際情況中我們時常會遇到下面的情況:

 主表 電影表:

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

電影表

從表1 電影類型表:

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

電影類型表

從表2 國家表:

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

國家表

 三表之間限制關系:

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

限制關系

 相信這個場景太常見了叭,兩個一對多關系,主鍵表裡面含有兩個外鍵。我們向view展示資料的時候應該把typeId,cid轉顯示為使用者能讀懂的typeName,cname吧,這是一個極其正常的需求。

   每種情形在EF中都用四種辦法來解決,幫你踩雷,相信我,總有适合你的一種!

代碼幹貨

 從簡到繁,從兩表到三表 

 ------------------------------------------------------------------------------我是可愛的分割線-----------------------------------------------------------------------------------------

PS:後面會用到兩個C#的文法糖,還是提一提吧,免得有的同學讀不懂

1.匿名類對象

通常我們使用類的時候,一般要先定義類,并且定義字段,封裝屬性。

但是在我們某個時刻要使用一個類,相當于臨時使用一次時,C#3.0推出的匿名類對象來解決這個問題,通常與推斷類型var結合使用,因為匿名類對象沒有特定的類名。

寫法如下:

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結
ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

這樣我們就執行個體化了一個匿名類對象student,通過var推斷出匿名類對象student屬于

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

這樣的一個類型。

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()方法 我們看下這個方法的參數定義叭(*^▽^*)

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

我相信小白們,頭一次看這個參數定義的時候一定是這樣的吧!

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結
ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結
ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

不慌不慌我們細心分析一下就行。

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

③ 方法三:原生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視圖

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

之後将這個視圖添加到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();
           

④方法四:建立視圖

視圖限制關系:

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結
var list3 = entities.VMovie.ToList();
           

----------------------------------------------------------------------------我是可愛的分割線--------------------------------------------------------------------------------------------

 EF中使用視圖的踩坑小記

坑一: 

       警告 6002: 表/視圖 未定義主鍵

這個警告很煩人,每次生成的時候後,都會彈這個警告,因為EF沒有檢測到表/視圖中的主鍵,但是我們可能會說,我在SqlServer建立的視圖壓根就沒有特定的主鍵啊!

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

解決方案:

使用人家EF,你就要迎合人家的規則,在視圖建立的時候,加一列值不重複且為 not null的列就行了,EF就檢測到有主鍵了,就不會再警告你啦 一般加一列Guid或者是RowNumber

select ISNULL(NEWID(), '5757E7EF-2F19-4408-B413-8F1B33B9895F') AS id,col1,col2,col3
 from xxxx
           

這時候,你再回到edmx中從資料庫更新模型後會發現,警告6002依舊存在!!!

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

沒關系,關閉VisualStudio,重新打開,警告就消失了

好了這個坑 完美解決

坑二: 

       操作VMovie的時候使用Find()方法

前幾天再給幾個同學改代碼的時候,發現他們習慣性的使用Find()查對象,最後在VMovie上使用Find()傳個ID就報錯了。

因為Find()是根據主鍵查對象的,VMovie是個視圖,本身就沒有自己特定的主鍵,為了解決坑一,我們加了一個GUID主鍵,是以當然不能像單表查詢那樣,傳一個主鍵來解決問題了。

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

    解決方案:

   使用FirstOrDefault或者Where

坑三:

     直接對VMovie進行增删改

因為VMovie的本質是個視圖,資料庫中的一張虛拟表,我們把視圖添加到edmx中隻是為了查詢資料友善,不能直接進行增删改

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結

       解決方案:

直接對主表movie進行增删改,視圖會進行自動更新

    我相信看完這篇部落格之後,使用EF處理簡單的多表聯合就不是什麼難事了吧,當初我在學習的時候,也是遇到各種各樣的問題,去網上也搜了各種方法,但是都是就事論事,說的不全面,有的還根本行不通,但是現在各種方法都有了,坑都踩了,大膽向前沖吧 !

ASP.NET Entity Framework多表聯合很頭大?一文幫你解決它場景描述代碼幹貨 EF中使用視圖的踩坑小記坑一: 坑二: 結