行为注入实体或更好的方式?

时间:2017-02-13 18:00:20

标签: c# entity-framework nhibernate entity inversion-of-control

假设我有一个通过ORM部分填充的User类,但是有一些与此实体逻辑相关的数据是从其他地方提供的。

public class User {
  public int Id { get; set; }

  public int ServiceId { get; set; }

  public string FirstName => null; //this comes from somewhere else

  public ICollection<Role> Roles { get; set; }
  //etc...
}

以前,在类似的情况下,我一直允许IOC容器将单个接口注入到域模型中来处理这个问题。

public class User {
  public readonly IUserBehavior _userBehavior;

  public User() {}
  public User(IUserBehavior userBehavior) {
    _userBehavior = userBehavior;
  }

  public int Id { get; set; }

  public int ServiceId { get; set; }

  public string FirstName => _behavior?.getFirstName(this);

  public ICollection<Role> Roles { get; set; }
  //etc...
}

然而,我最近尝试从nHibernate切换到Entity Framework,这看起来使这变得不可能(至少,使用构造函数注入)。

我现在的选择似乎是移动服务调用(实现细节)以直接获取缺少的数据到实体中或使用看似相反的双重调度模式...该类型的某些数据属性必须以特殊的方式被召唤。如果这是一个改变状态的动作,我可以看到双重调度更有意义。或者,我想我可以回到nHibernate。

我想我所问的是我的任何选项实际上是“好”,还是有其他选择我应该考虑?

2 个答案:

答案 0 :(得分:0)

使用装饰器提供必要的功能:https://en.wikipedia.org/wiki/Decorator_pattern

因此,从您的业务层(或您需要访问User类的任何地方),您可以调用首先调用EF的装饰器类,然后使用您的自定义流程来提供FirstName等。

答案 1 :(得分:0)

正如多人hereherehere所解释的那样,使用构造函数注入将依赖项注入实体并不是一个好主意。

相反,你使用方法注入要好得多。例如:

public class User {
  public int Id { get; set; }
  public int ServiceId { get; set; }
  public ICollection<Role> Roles { get; set; }

  public string GetFirstName(IUserBehavior behavior) => behavior.GetFirstName(this);

  //etc...
}

这里,实体上的每个方法都定义了自己的依赖关系集,这些依赖关系是使用方法注入注入的。这使得实体上的方法非常可测试,并且无法使用容器来构建实体。

相反,使用服务将获得注入其构造函数的必需依赖项,并将这些依赖项传递给它调用的方法。

但是,在这种情况下,GetFirstName()方法的行为非常简单,通过让服务调用behavior.GetFirstName(User)本身可能更好。