異常跟蹤之CLR 類型到 EDM 類型的映射不明確


異常信息:

"指定的架構無效。錯誤:
CLR 類型到 EDM 類型的映射不明確,因為多個 CLR 類型與 EDM 類型“Person”匹配。
以前找到的是 CLR 類型“A.Person”,
新找到的則是 CLR 類型“B.Person”。

這類異常信息在代碼里面出現過幾次,每次的解決方案都讓人匪夷所思。不知道為什么出現,也不知道為什么被解決了。

查閱了一些國外的資料,鏈接

Don't use classes with the same name - EF uses only class names to identify the type mapped in EDMX (namespaces are ignored) - it is a convention to allow mapping classes from different namespaces to single model. The solution for your problem is to name your classes in BLL differently.

但實際情況是,這類異常不總是出現,而是在一個偶然的情況下出現。所謂偶然的情況,卻是一種很普通又簡單的調用。

using (var con = new MyContainer())
{
    string sql = "select top 1 name from cat";
    var p = con.Database.SqlQuery<contract.Dog>(sql).FirstOrDefault();
    Console.WriteLine(p.Name);
}

查詢cat數據,將第一個的name數據查詢並存儲在contract.Dog對象中。這類調用非常普通。

 

整理一下思路:

1. 出現"CLR 類型到 EDM 類型的映射不明確"異常,肯定是存在和ef模型中數據結構一樣的類

2. 與ef數據結構同名的類一直存在,但並非一直報錯。

 

做以下測試:

測試一

在ef數據模型所在項目中(以下用entity表示),建立模型Person

同時,在entity項目中另外新建一個類,也命名為Person(當然名稱空間不一樣),屬性一樣(類型和名稱)。

調試時,會發現報錯,報錯內容同上。

測試二

在測試一的基礎上,去掉entity中手動創建的Person類,在解決方案下新建另一個項目contract,在contract中新建類,命名Person,屬性同上。

調用代碼:

using (var con = new MyContainer())
{
    string sql = "select top 1 * from person";
    var p = con.Database.SqlQuery<contract.Person>(sql).FirstOrDefault();
    Console.WriteLine(p.Name);
}

單獨運行這段時,不會報錯。加上下面這段:

using (var con = new MyContainer())
{
    string sql = "select top 1 * from person";
    var p = con.Database.SqlQuery<efentity.Person>(sql).FirstOrDefault();
    Console.WriteLine(p.Name);
}

執行完上面代碼后,緊接着執行下面的代碼。出現異常,異常同上。

加斷點,跟蹤con的數據明細。

在執行完第一段查詢以前,con.base._internalContext.ObjectContext.MetadataWorkSpace._itemOCSpace.Value(以下簡稱MetaOCSpace)為空;

執行完第一段查詢后,MetaOCSpace的數量出現32條,具體如下:

出現了Person的類型映射數據,此時Person類型映射到了contract.Person。

 

省略其他測試過程,有如下結論:

1. 當entity中出現同數據模型的類時,同類名同字段,無論什么時候用ef操作數據,都會報錯。

2. 當entity所在的assembly沒有同名類,但其他assembly(例contract)有同名類時。先有查詢結果放入entity的任意類對象,后有查詢結果放入contract的任意類對象時,就會報錯。操作的先后順序調換,結果一樣。

這是因為DbContext的MetadataWorkSpace一旦生成會緩存起來。也就是說,在同一個應用程序域里面,一旦用dbcontext操作過數據庫,它會自動讀取類所在assembly里面的所有類,並嘗試匹配數據庫模型,然后將匹配結果保存起來(保存到上面的MetaOCSpace中)。當下次操作數據庫時,返回數據對應類類所在其它assembly里面的類與當前已匹配數據庫模型發生沖突時,便會報錯。

3. 當client引用entity + client引用contract時,有結論2的隱患。而當entity引用contract,然后client引用entity時,同樣存在問題。

這種情況一般出現在ef的枚舉類型定義為引用外部類型(contract中定義的類型),這時就會出現entity引用contract,然后client引用entity的場景。配合以下代碼:

using (var con = new MyContainer())
{
    var p = con.Person.Where(pp => pp.Status == contract.We.One).FirstOrDefault();
    Console.WriteLine(p.Name);
}

這時,也會出現報錯。

 

解決思路:

1. 不要與entity中的模型同名,同字段。或者換過來entity中的模型加特殊標記

2. ef操作數據庫時,返回數據的數據類型必須用entity項目中定義的類型。

 

以上內容,部分細節未仔細推敲,如有其他想法請留言。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM