2017-02-14 78 views
0

我有一个由EntityFramework持久化的域模型。在任何给定的实体/ POCO中,我希望能够填充(通过EF CodeFirst),然后阅读集合,但只允许通过单独的域服务类对这些集合进行修改。保护EntityFramework集合不被修改

作为一个例子,我可以具有类如:

public class Foo { 

    public Foo() { 
     _bars = new List<Bar>(); 
    } 

    private ICollection<Bar> _bars; 
    public virtual ICollection<Bar> Bars { get { return _bars; } protected set { _bars = value; } } 

} 

这将停止与myFoo.Bars = new List<Bar>());被覆盖的集合。但是,它仍然允许任何使用POCO的人编写代码,例如myFoo.Bars.Add(new Bar());或类似的代码。

我想让Bars集合为只读,因此不仅可以直接停止集合,还可以阻止用户直接向集合添加Bar实例。

这是因为用户被迫使用域服务类将项目添加到集合。该类还将对添加的Bar实例执行非平凡的验证和业务逻辑检查。例如:

public class AddBarToFooService() : IAddBarToFooService { 

    public AddBarToFooService(IBarChecker checker) { 
     _checker = checker; 
    } 

    private readonly IBarChecker _checker; 

    public Add(Foo foo, Bar bar) { 

     if(_checker.Check(foo, bar) { // Trivial validation check 
      foo.Bars.Add(foo); 
     } 
    } 
} 

有两个要点:

  1. 的只读限制需要能够允许域名服务操作集合
  2. 该解决方案必须符合的EntityFramework
  3. 兼容
  4. 理想情况下,POCO和域名服务应该是松散耦合的

我该如何做到这一点?

+0

因此,您的服务从不暴露上下文?用户是否调用您的代码来保存更改,或者他们能否直接调用SaveChanges? –

回答

0

有一些选项可以防止使用实体框架添加或更新数据。

从模型中卸下实体

当你调用数据库,你可以使用

Configuration.ProxyCreationEnabled = false; 

在这种情况下您禁用延迟加载和关闭某些对象跟踪。或者你可以'取消代理'的对象与

protected internal List<T> UnProxyList<T>(List<T> list) where T : class 
{ 
    var proxyCreationEnabled = this.Configuration.ProxyCreationEnabled; 
    try 
    { 
     this.Configuration.ProxyCreationEnabled = false; 
     return list.Select(i => this.Entry(i).CurrentValues.ToObject() as T).ToList(); 
    } 
    finally 
    { 
     this.Configuration.ProxyCreationEnabled = proxyCreationEnabled; 
    } 
} 

在这两种情况下的变化不再被追踪。因此用户是否修改集合并没有关系,它没有任何影响。请注意,用户需要急切的加载来填充导航属性。

回滚改变

这可以的DbContext完成。您可以创建一个内部方法,您可以调用base.SaveChanges,而用户必须使用SaveChanges的重写。您可以添加一些逻辑来回滚某些更改。

public override int SaveChanges() 
{ 
    var entries = base.ChangeTracker.Entries<Bar>().ToList(); 

    entries.ForEach(entry => entry.State = System.Data.Entity.EntityState.Unchanged); 
    return base.SaveChanges(); 
} 

延迟加载和跟踪是可用的,所以你会得到正常的实体框架行为。但是,更改不会落实。