假設我使用下面的實體框架的實體:投影領域模型的孩子數到視圖模型沒有額外查詢
public class Country : DomainObject<int>
{
private ICollection<StateOrProvince> _statesOrProvinces;
public string Name { get; set; }
public string Abbreviation { get; set; }
public virtual ICollection<StateOrProvince> StatesOrProvinces
{
get { return _statesOrProvinces ?? (_statesOrProvinces = new List<StateOrProvince>()); }
protected set { _statesOrProvinces = value; }
}
}
public class StateOrProvince : DomainObject<int>
{
public int CountryId { get; set; }
public virtual Country Country { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
我要投射到我的表現層以下視圖模型:
public class CountryListModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
[Display(Name = "States/Provinces")]
public int StatesOrProvincesCount { get; set; }
}
正如你所看到的,我有我的模型StateOrProvincesCount屬性,它應該代表我的國家耳鼻喉列表中StatesOrProvinces的總次數性。
爲了保持我的MVC控制器代碼精簡,我爲我的域實體創建了靜態映射擴展方法。在一個映射到CountryListModel看起來是這樣的:
public static CountryListModel MapToListModel(this Country country)
{
return new CountryListModel
{
Id = country.Id,
Name = country.Name,
Abbreviation = country.Abbreviation,
StatesOrProvincesCount = country.StatesOrProvinces.Count
};
}
然後我試圖使用它,如下所示:
var models = _countries.OrderBy(x => x.Name).Select(x => x.MapToListModel()).ToList();
然而,這引發異常LINQ到實體不承認方法'CountryListModel MapToListModel(Country)'方法,並且此方法不能轉換爲商店表達式。我的假設是,這是IQueryable
無法將代碼轉換爲SQL的問題。
於是我嘗試:
var models = _countries.AsEnumerable().OrderBy(x => x.Name).Select(x => x.MapToListModel()).ToList();
這並不會引發錯誤,給我我想要的結果。但是,查看SQL Express Profiler時,我可以看到這導致(N + 1)查詢被髮送到數據庫。首先它詢問獲得國家名單,然後查詢選擇每個國家的所有州/省。
如果直接在.Select
方法中拋出的映射擴展和項目只有一個查詢,並將其直接在SQL執行Count
而不是返回州/省,然後計算這些的:
var models = _countries.OrderBy(x => x.Name).Select(x => new CountryListModel
{
Id = x.Id,
Name = x.Name,
Abbreviation = x.Abbreviation,
StatesOrProvincesCount = x.StatesOrProvinces.Count
}).ToList();
這太棒了,但這只是一個快速的原型。從長遠來看,我希望將事情分成不同層次(例如 - 核心,數據,商業,演示)。
從我在這個過程中學到的知識來看,爲了有效地查詢,我所預測的視圖模型必須被數據層所瞭解。在這種情況下,視圖模型是否屬於核心/公共項目以及域實體?我應該創建額外的DTO對象並映射到這些對象上嗎?你如何在你的項目中處理這個問題?
'MapToListModel()'在SQL Server中不存在,所以它不知道你想要什麼。您是否嘗試過:'_countries.OrderBy(x => x.Name).ToList()。Select(x => x.MapToListModel())。ToList();'你也在問一些關於編程的概念問題,更適合http://programmers.stackexchange.com關於核心/數據/業務/演示。 –
您可以使用https://automapper.codeplex.com/(AutoMapper)在Domain對象和ViewModels之間進行映射......它只是一個要添加到項目中的配置圖層 –
Erik,可以工作,但會導致* * N + 1 **查詢就像我的另一個例子。謝里夫,我知道AutoMapper,但沒有看到它是如何解決聚合** N + 1 **查詢問題。 Linq to SQL不知道有關AutoMapper的更多信息,而不瞭解擴展方法。 – Sam