改變你的第二個功能是:
public IEnumerable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo.ToList()
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
AutoMapper只是罰款的LINQ到SQL,但它不能爲遞延查詢的一部分來執行。在您的Linq查詢的末尾添加ToList()
會導致它立即評估結果,而不是嘗試將AutoMapper段作爲查詢的一部分進行翻譯。
澄清
延遲執行(不「懶加載」)的概念沒有任何意義,一旦你已經改變了結果類型的東西,這不是一個數據實體。考慮這兩個類:
public class DB_RoleInfo
{
public int ID { get; set; }
public string Name { get; set; }
}
public class DO_RoleInfo
{
public Role Role { get; set; } // Enumeration type
}
現在考慮下面的映射:
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>
.ForMember(dest => dest.Role, opt => opt.MapFrom(src =>
(Role)Enum.Parse(typeof(Role), src.Name)));
這種映射是完全沒問題的(除非我犯了一個錯誤),但讓我們說你寫的SelectAll
方法在你的原職而不是我的修訂之一:
public IQueryable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
竟是那樣的這個工作,但一個自稱「可查詢」,就在於。如果我嘗試寫下它,會發生什麼情況:
public IEnumerable<DO_RoleInfo> SelectSome()
{
return from ri in SelectAll()
where (ri.Role == Role.Administrator) ||
(ri.Role == Role.Executive)
select ri;
}
想一想這件事真的很難。 Linq如何能夠可能能夠成功地將您的where
成爲一個實際的數據庫查詢?
Linq對DO_RoleInfo
類一無所知。它不知道如何做映射落後 - 在某些情況下,這可能甚至不可能。當然,你可以看看這個代碼,然後去「哦,這很簡單,只需在Name
列」「中搜索'管理員'或'執行',但只有你是唯一知道這一點的人。就Linq to SQL而言,查詢是純粹的廢話。
想象一下,有人給你這些指令:
Go to the supermarket and bring back the ingredients for making Morton Thompson Turkey.
除非你之前已經做到了,而且大部分人都沒有,你到指令響應是最有可能將是:
你可以去市場,你可以通過名字來取得具體成分,但你不能評價我已經給你而你那邊的條件。我必須「取消」標準第一個。我必須告訴你,這裏是我們需要這個食譜的成分 - 現在去拿他們。
總之,這是不是LINQ的之間的一些簡單不相容到SQL和AutoMapper。這兩個圖書館都不是唯一的。不要緊實際操作中做映射到非實體類型 - 你可以很容易地做手工的映射,你仍然得到同樣的錯誤,因爲你現在給LINQ to SQL的一組不能再理解的指令,處理不具有任何特定實體類型的內在映射的神祕類。
這個問題到O/R映射的概念,並推遲執行查詢的基礎。甲投影是單向操作。一旦你的項目,你再也不能回到查詢引擎,並說哦對了,這裏爲大家介紹一些多個條件。太晚了。你能做的最好的就是把它已經給你的東西和你自己評估額外的條件。
最後但並非最不重要的,我會給你一個解決方法。如果您希望能夠從你的映射做唯一就是過濾行,你可以這樣寫:
public IEnumerable<DO_RoleInfo> SelectRoles(Func<DB_RoleInfo, bool> selector)
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return _ctx.DB_RoleInfo
.Where(selector)
.Select(dbr => Mapper.Map<DB_RoleInfo, DO_RoleInfo>(dbr));
}
這是處理映射爲您和接受過濾器的實用方法在原實體,而不是的映射的實體。如果您有許多不同類型的過濾器,但始終需要執行相同的映射,則此功能可能會很有用。個人而言,我認爲只要正確寫出查詢,首先確定需要從數據庫中檢索,然後進行任何預測/映射,然後最後如果需要做進一步過濾(你不應該),然後物化結果與ToList()
或ToArray()
並寫入更多的條件對本地列表。
不要試圖使用AutoMapper或任何其他工具來將Linq公開的實體隱藏到SQL中。領域模型是您的公共接口。您編寫的查詢是您的私有執行的一個方面。理解差異並保持良好的關注點很重要。
只是除了您的更新我的筆記回答:第二個版本的工作原理是因爲Linq到SQL已經*知道*你已經做了一個不可逆轉的預測; 「SelectByKey」實際上只是將Linq用於對象。如果您檢查正在生成的實際查詢,我認爲您會發現它仍然從數據庫中選擇所有實體,這相當於使用「ToList()」,然後過濾結果列表。 – Aaronaught 2010-02-06 15:33:57
這不是說AutoMapper支持LINQ。這是LINQ to SQL不支持AutoMapper。 LINQ to SQL查詢提供程序查看錶達式樹以確定如何生成SQL查詢。當它到達Mapper.Map部分時,它不知道如何生成SQL。 – 2010-02-07 18:11:15