夢想成為現(xiàn)實:在Enitity Framework中以理想方式實現(xiàn)指定字段查詢
在之前的隨筆“博客園現(xiàn)代化建設(shè)—[Entity Framework]在LINQ查詢中指定返回的字段”中,我們找到了問題的原因,卻沒有找到解決方法。
而對于理想中的解決方法,我們依然戀戀不忘,雖然很多次嘗試都失敗了,但我們相信,在代碼世界一切皆有可能。
讓我們先回顧一下理想中的LINQ查詢代碼:
{
var result = (from e in context.BlogEntries
join t in context.PostTexts
on e.ID equals t.ID
where e.ID == entryId
select new BlogEntry()
{
Title = e.Title,
Body = t.Text
})
.FirstOrDefault();
}
再回顧一下錯誤信息:
The entity or complex type 'BlogServer.Data.Provider.BlogEntry'
cannot be constructed in a LINQ to Entities query.
at System.Data.Objects.ELinq.ExpressionConverter.CheckInitializerType(Type type)
還有BlogDbContext的代碼:
{
public DbSet<BlogEntry> BlogEntries { get; set; }
}
把這三者聯(lián)系起來,把問題精簡為:如果一個類型(這里是BlogEntry)被注冊到DbSet<T>,Enity Framework就會認(rèn)為這個類型是complex type,在select new時引發(fā)異常。而建立一個具有同樣屬性的類型(前篇隨筆中的BlogEntryClone),由于沒有被注冊到DbSet<T>,則不會引發(fā)異常。
本來很單純的BlogEntry,從DbSet<T>進(jìn)入Enity Framework,就變成復(fù)雜了;而從其他地方進(jìn)入,依然單純。很明顯,DbSet<T>有問題。
可以猜測DbSet對BlogEntry動了手腳,可能是修改了BlogEntry的類型信息...
所以,要解決的問題變成:DbSet<T>與select new必須要使用不同的類型,而且要共享屬性信息。
自然而然,就會想到繼承,于是創(chuàng)建了一個繼承自BlogEntry的類DerivedBlogEntry試試,代碼如下:
{
}
然后,將之用于select new,代碼如下:
{
var result = (from e in context.BlogEntries
join t in context.PostTexts
on e.ID equals t.ID
where e.ID == entryId
select new DerivedBlogEntry()
{
Title = e.Title,
Body = t.Text
}
).FirstOrDefault();
}
結(jié)果出現(xiàn)同樣的complex type錯誤。
稍作分析,就能理解為什么還會出現(xiàn)這個錯誤。由于DbSet<T>對BlogEntry的類型進(jìn)行了改變,DerivedBlogEntry繼承自BlogEntry,自然也會受到影響。
再把我們要解決的問題進(jìn)一步提煉:DbSet<T>中的類型(BlogEntry1)與select new中的類型(BlogEntry2)要共享屬性(必然要存在關(guān)聯(lián)),而且對BlogEntry1類型的修改不能影響到BlogEntry2。
父類雖然可以與子類共享屬性,但對父類類型的修改必然會子類,這就是上面遇到的情況。
似乎我們踏破鐵鞋也找不到解決方法...
如果將父類與子類使用的位置交換一下,也就是在DbSet<T>中使用DerivedBlogEntry,在select new中使用BlogEntry...
當(dāng)這個想法閃現(xiàn)出來的,就預(yù)感到這就是解決之道,當(dāng)時真的很興奮...迫不及待地用代碼進(jìn)行驗證,代碼如下:
BlogDbContext的代碼:
{
public DbSet<DerivedBlogEntry> BlogEntries { get; set; }
}
LINQ查詢代碼:
{
var result = (from e in context.BlogEntries
join t in context.PostTexts
on e.ID equals t.ID
where e.ID == entryId
select new BlogEntry()
{
Title = e.Title,
Body = t.Text
}
).FirstOrDefault();
}
當(dāng)代碼測試通過的時候,內(nèi)心那種美妙的感覺無法用語言去表達(dá)...當(dāng)時很想慶祝一下,于是,把寫出這篇博客當(dāng)作慶祝的方式!
浙公網(wǎng)安備 33010602011771號