>在我的核心程序集中假设这个简单的域:
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;
}
}
使用实体框架,省域对象将同时具有国家/地区和相应的 CountryId 属性。我可以通过简单地设置国家/地区 ID 来分配国家/地区。
使用 NHibernate,创建域时不需要外键的 id。那么,如何将省模型国家 ID 映射回国家/地区对象呢?
我已经经历了各种步骤来将事物抽象到接口中并使用依赖注入。我是否应该使用映射扩展模块中的服务定位器并查找它?我是否应该在映射扩展之外查找国家/地区并要求将其作为扩展方法的参数?处理此方案的推荐方法是什么?
其次,使用 NHibernate,他们建议向域对象添加帮助程序函数以保持关联(不是积极的,但我认为 EF 为我"自动"处理这个问题)。例如,我会在"省"上添加一个SetCountry
方法,在"国家"上添加AddProvince
和RemoveProvince
方法。
这不会损害性能吗?不是简单地为省份(管理关联的地方)设置国家/地区,而是加载新国家/地区省份的整个列表以查看它是否已在添加到集合中,然后加载旧国家/地区省份的整个列表以查看是否需要从集合中删除该省。
[在EF中]我可以通过简单地设置国家/地区ID来分配国家/地区。
这不是真的,在我看来,这是实体框架的一个主要缺陷。同时拥有国家/地区和国家/地区 ID 属性是一种黑客攻击,它允许您设置国家/地区,而无需通过设置 CountryId 从数据库中检索它。在 Web 应用程序中,这有效,因为记录是使用设置的 CountryId 外键保存的,因此下次加载它时,将填充国家/地区。NHibernate 对此模式的解决方案是创建动态代理的ISession.Load
方法。
在您的示例中,您将执行以下操作
province.Country = session.Load<Country>(provinceModel.CountryId);
至于你的第二个问题,一般来说,我只使用方法来封装对集合的访问。这确保了集合本身不会被二传手取代,并允许我保持关系的双方。我会将其建模为:
public class Country
{
private ICollection<Province> _provinces;
public Country()
{
_provinces = new HashSet<Province>();
}
public virtual IEnumerable<Province> Provinces
{
get { return _provinces; }
}
public virtual void AddProvince(Province province)
{
province.Country = this;
_provinces.Add(province);
}
public virtual void RemoveProvince(Province province)
{
province.Country = null;
_provinces.Remove(province);
}
}
如您所指出的,这确实需要加载集合。您必须记住,NHibernate(和Hibernate)最初是为有状态应用程序设计的,许多使用模式在无状态Web应用程序中并不是绝对必要的。但是,在偏离其中一些模式之前,我会分析性能。例如,您可能希望在提交对象之前对其进行验证,这要求内存中的表示形式保持一致。