Пусть этот простой домен в моей основной сборке:Nhibernate домена Ojbect/View Model Mapping (один-ко-многим)
public class Country
{
protected ICollection<Province> _provinces = null;
public virtual int Id { get; protected set; }
public virtual string Name { get; set; }
public virtual string IsoCode2 { get; set; }
public virtual string IsoCode3 { get; set; }
public virtual int IsoCodeNumeric { get; set; }
public virtual ICollection<Province> Provinces
{
get { return _provinces ?? (_provinces = new List<Province>()); }
set { _provinces = value; }
}
}
public class Province
{
public virtual int Id { get; protected set; }
public virtual Country Country { get; set; }
public virtual string Name { get; set; }
public virtual string Abbreviation { get; set; }
}
Модели вид в моем представлении слоя являются почти то же самое:
public class CountryModel
{
public int Id { get; set; }
public string Name { get; set; }
public string IsoCode2 { get; set; }
public string IsoCode3 { get; set; }
public int IsoCodeNumeric { get; set; }
public int NumberOfProvinces { get; set; }
}
public class ProvinceModel
{
public int Id { get; set; }
public int CountryId { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
Я создаю некоторые методы расширения для отображения вперед и назад между объектами домена/просмотр моделей:
public static class Extensions
{
public static Country ToEntity(this CountryModel model, Country entity = null)
{
if (entity == null)
entity = new Country();
entity.Name = model.Name;
entity.IsoCode2 = model.IsoCode2;
entity.IsoCode3 = model.IsoCode3;
entity.IsoCodeNumeric = model.IsoCodeNumeric;
entity.AddressFormat = model.AddressFormat;
entity.CanBillTo = model.CanBillTo;
entity.CanShipTo = model.CanShipTo;
entity.IsPublished = model.IsPublished;
return entity;
}
public static CountryModel ToModel(this Country entity, bool includeProvinceCount = false, CountryModel model = null)
{
if (model == null)
model = new CountryModel();
model.Id = entity.Id;
model.Name = entity.Name;
model.IsoCode2 = entity.IsoCode2;
model.IsoCode3 = entity.IsoCode3;
model.IsoCodeNumeric = entity.IsoCodeNumeric;
model.AddressFormat = entity.AddressFormat;
model.CanBillTo = entity.CanBillTo;
model.CanShipTo = entity.CanShipTo;
model.IsPublished = entity.IsPublished;
if (includeProvinceCount)
model.NumberOfProvinces = entity.Provinces.Count;
return model;
}
public static Province ToEntity(this ProvinceModel model, Province entity = null)
{
if (entity == null)
entity = new Province();
//entity.Country = LoadCountryById(model.CountryId); ???? <-- HERE
entity.Name = model.Name;
entity.Abbreviation = model.Abbreviation;
entity.CanBillTo = model.CanBillTo;
entity.CanShipTo = model.CanShipTo;
entity.IsPublished = model.IsPublished;
return entity;
}
public static ProvinceModel ToModel(this Province entity, ProvinceModel model)
{
if (model == null)
model = new ProvinceModel();
model.Id = entity.Id;
model.CountryId = entity.Country.Id;
model.Name = entity.Name;
model.Abbreviation = entity.Abbreviation;
model.CanBillTo = entity.CanBillTo;
model.CanShipTo = entity.CanShipTo;
model.IsPublished = entity.IsPublished;
return model;
}
}
С Ent что в доменном объекте провинции были бы как Страна, так и соответствующие свойства CountryId. Я мог бы назначить страну, просто установив CountryId.
С NHibernate идентификатор внешнего ключа не требуется при создании домена. Итак, как вы нанесете карту RegionModel CountryId обратно в объект Country?
Я прошел всевозможные шаги, чтобы абстрагировать вещи на интерфейсы и использовать инъекции зависимостей. Должен ли я использовать локатор сервисов из расширений отображения и искать его? Должен ли я искать страну за пределами расширения отображения и требовать ее в качестве параметра метода расширения? Каковы рекомендуемые способы передачи этого сценария?
Во-вторых, с NHibernate они рекомендуют добавлять вспомогательные функции для объектов предметной области в целях сохранения ассоциаций (не уверен, но я думаю, что EF обрабатывает это «автомагически» для меня). Например, я бы добавил метод SetCountry
на провинцию, и AddProvince
и RemoveProvince
методов по стране.
Разве это не ухудшает производительность? Вместо того, чтобы просто устанавливать страну для провинции (где находится ассоциация), весь список новых провинций страны загружается, чтобы увидеть, есть ли он в списке перед добавлением в коллекцию, а затем весь список старые провинции страны загружаются, чтобы посмотреть, нужно ли удалить провинцию из коллекции.
Благодарим Вас за отзыв Jamie. Что касается вашего предложения по первой проблеме: он вводит зависимость от NHibernate в моем слое Presentation. Я пытался избежать этого, хотя мне известно о мыслях Айенде о репозиториях и абстрагировании от NH. Единственный способ, с помощью которого я могу предотвратить это, - передать страну как параметр расширения отображения (я могу получить его из хранилища заранее). – Sam
На второй части это то, что я делал. Но тогда я был обеспокоен тем, что установление страны для провинции приведет к загрузке всех провинций для старой страны и новой страны. Хотя это не очень важно в этом сценарии, это может быть для больших коллекций на других объектах домена. Я не был уверен, есть ли способ избежать этого. – Sam
В ответ на ваш 1-й комментарий, я считаю, что контроллер MVC отвечает за управление границами транзакций и поэтому нуждается в знаниях механизма сохранения. На ваш второй комментарий он должен загружать провинции только для 1-й страны. Существует метод утилиты для проверки того, была ли загружена коллекция, и в этом случае вам просто нужно установить ссылку на другом конце, но это вводит зависимость NHibernate в модель домена, и у меня есть свои ограничения. :-) –