Bac*_*cks 9 c# entity-framework
我使用EntityFramewotk和代码第一种方法.所以,我这样描述我的模型:
class Person
{
public long Id { get;set; }
public string Name { get;set; }
public ICollection<Person> Parents { get;set; }
}
Run Code Online (Sandbox Code Playgroud)
但是,我的域逻辑不允许修改Parents集合(添加,删除),它必须是readonly(仅举例).EntityFramework要求所有集合都有ICollection<T>
接口,并且它具有Add
方法(实现结果)和Remove
方法等.我可以通过显式实现接口来创建自己的集合:
public class ParentsCollection : ICollection<Person>
{
private readonly HashSet<Person> _collection = new HashSet<Person>();
void ICollection<Person>.Add(Person item)
{
_collection.Add(item);
}
bool ICollection<Person>.Remove(Person item)
{
return _collection.Remove(item);
}
//...and others
}
Run Code Online (Sandbox Code Playgroud)
这隐藏Add
和Remove
方法,但根本不保护.因为我总是可以转换为ICollection并调用禁止的方法.
所以,我的问题是:
Ehs*_*edi 14
在 EF Core 中,您可以通过使用支持字段来封装集合并实现真正的域建模。所以,你可以定义你的集合作为一个私人领域和揭露它作为一个公共只读属性,像下面的_parents和家长。
class Person
{
public long Id { get;set; }
public string Name { get;set; }
private List<Person> _parents = new List<Person>();
public IReadOnlyCollection<Person> Parents => _parents.AsReadOnly();
public void AddParent(Parent parent){
_parents.Add(parent);
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,Parents 是一个只读集合,不允许消费者对其进行修改。
请注意, _parents 被 ef core 的约定发现为支持字段。
您可以将私有集合属性公开给EF,允许映射和查询,同时仍然保持域对象的成员和关系正确封装.这有点乱,但它有效:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Order> Orders
{
get { return _orders.AsEnumerable(); }
}
private List<Order> _orders { get; set; }
public Customer()
{
_orders = new List<Order>();
}
public static Expression<Func<Customer, ICollection<Order>>> OrderMapping
{
get { return c => c._orders; }
}
}
Run Code Online (Sandbox Code Playgroud)
映射然后使用:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Customer>().HasMany(Customer.OrderMapping);
}
Run Code Online (Sandbox Code Playgroud)
这里进一步描述了这种方法:http: //ardalis.com/exposing-private-collection-properties-to-entity-framework
简短的回答:不。奇怪的是,您可以这样做(嗯,NHibernate 可以设置私有类字段,这意味着您可以使用将字段封装为只读集合的公共属性来公开它......好吧,您可以在 EF 中解决这种情况也是:实体框架通过包含对象实现多对多。顺便说一句,我不会建议您使用这种方法,因为如果它是私有财产,您如何添加新的父级?)
无论如何,我认为域对象应该是读写的,因为归根结底,域对象描述了域内的实体,您应该能够访问和修改它。
另一种解决方案是设计一个接口来公开Parents
as IReadOnlyList<Person>
,以及一个IPerson
包含除 之外的所有Person
成员的接口Parents
,并返回Person
为IPerson
:
public interface IHasParents
{
IReadOnlyList<Person> Parents { get; }
}
public interface IPerson : IHasParents
{
long Id { get; set; }
string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
并IPerson
隐式实现,Person
除非显式Parents
实现。当您需要返回某个地方时,您可以返回而不是:Person
IPerson
Person
public IPerson CreatePerson(string name, IEnumerable<Persons> parents)
{
Person person = new Person { Name = name, Parents = parents };
// Persistence stuff
return person;
}
Run Code Online (Sandbox Code Playgroud)
您可以争辩说您可能能够向下转型IPerson
为Person
,但此时我会告诉您,您需要遵循自己的编码约定:如果您定义了您永远不会返回,Person
但IPerson
我会在整个代码中这样做base,如果您需要可写的属性Parents
,则返回Person
(并且稍后可以避免强制转换!)。
归档时间: |
|
查看次数: |
4135 次 |
最近记录: |