NHibernate:如何在实体上注入依赖关系

NHibernate:如何在实体上注入依赖关系,nhibernate,structuremap,Nhibernate,Structuremap,NHibernate 3.2/Fluent NHibernate 1.3/StructureMap 2.6.3- 尝试将DDD作为一种体系结构策略,我通常不依赖于域实体。然而,我现在正在尝试向我的域实体添加更多的行为,这样它们就不会那么贫乏了。一切都很顺利,直到我找到了尼伯内特。我有两个问题: NH需要一个无参数构造函数,我不希望有 不应该使用的ctor 当NH试图实例化我的实体时,它需要解析我的 但是我没有给NH任何它可以做的事情 那个 我一直在网上阅读,但我发现的大多数(如果不是全部的话)例

NHibernate 3.2/Fluent NHibernate 1.3/StructureMap 2.6.3-

尝试将DDD作为一种体系结构策略,我通常不依赖于域实体。然而,我现在正在尝试向我的域实体添加更多的行为,这样它们就不会那么贫乏了。一切都很顺利,直到我找到了尼伯内特。我有两个问题:

  • NH需要一个无参数构造函数,我不希望有 不应该使用的ctor
  • 当NH试图实例化我的实体时,它需要解析我的 但是我没有给NH任何它可以做的事情 那个

  • 我一直在网上阅读,但我发现的大多数(如果不是全部的话)例子都过时了(或者只是旧的)。即使NH阵营可能不赞成我所做的,我也在寻找NH的方法来做到这一点

    如果您需要实体中的其他依赖项,请不要使用构造函数注入。而是在实体方法中创建一个附加参数

    现在,您将问自己如何获得依赖关系。为此,您可以使用CommandHandler和命令。命令处理程序在其构造函数中获取依赖项并调用实体的方法。在UI中,创建命令消息并将其发送给负责调用正确命令处理程序的命令处理器

    我希望你能理解我的解释

    域:

    public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
    
        public void SendNotification(string message, INotifier notifier)
        {
            notifier.SendMessage(string.Format("Message for customer '{0}' ({1}): {2}", Name, Id, message));
        }
    }
    
    INotifier
    基础结构组件通过方法而不是构造函数传递

    基础设施:

    public interface INotifier
    {
        void SendMessage(string message);
    }
    
    class EmailNotifier : INotifier
    {
        public void SendMessage(string message)
        {
            // SmtpClient...
        }
    }
    
    class SMSNotifier : INotifier
    {
        public void SendMessage(string message)
        {
            // SMS ...
        }
    }
    
    命令和命令处理程序:

    public class NotificationCommandHandler : ICommandHandler<NotificationCommand>
    {
        private readonly INotifier _notifier;
    
        public NotificationCommandHandler(INotifier notifier)
        {
            _notifier = notifier;
        }
    
        public void Execute(NotificationCommand commandMessage)
        {
            commandMessage.Employee.SendNotification(commandMessage.Message, _notifier);
        }
    }
    
    public class NotificationCommand
    {
        public string Message { get; set; }
        public Employee Employee { get; set; }
    }
    

    如果您有关于命令处理器的问题,请查看该项目或提出单独的问题。

    对不起,我之前的回答没有针对具体问题。我做了更多的研究,看起来我有更多的东西要学习什么时候不使用贫血领域模型。关于你的问题,我发现你的话题很重要。它基于java,而不是c#,但原理是一样的。希望这有帮助。

    解决方案最终实现了NHibernate的IInterceptor。当您从EmptyInterceptor继承并只重写Instantiate()和SetSession()方法时,它实际上是一个非常简单的实现。这是我使用StructureMap的拦截器:

    public class DependencyInjectionEntityInterceptor : EmptyInterceptor
    {
        IContainer _container;
        ISession _session;
    
        public DependencyInjectionEntityInterceptor(IContainer container)
        {
            _container = container;            
        }
    
        public override void SetSession(ISession session)
        {
           _session = session;            
        }
    
        public override object Instantiate(string clazz, EntityMode entityMode, object id)
        {
            if (entityMode == EntityMode.Poco)
            {
                var type = Assembly.GetAssembly(typeof (SomeClass)).GetTypes().FirstOrDefault(x => x.FullName == clazz);
                var hasParameters = type.GetConstructors().Any(x => x.GetParameters().Any());
                if (type != null && hasParameters)
                {
                    var instance = _container.GetInstance(type);
    
                    var md = _session.SessionFactory.GetClassMetadata(clazz);
                    md.SetIdentifier(instance, id, entityMode);
                    return instance;
                }
            }
            return base.Instantiate(clazz, entityMode, id);
        }
    }
    
    然后,你所要做的就是告诉NHibernate使用你的拦截器:

    public FluentConfiguration GetFluentConfiguration(IContainer container)
    {
        return Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008
                      .ConnectionString(c => c.FromConnectionStringWithKey("Database"))
                          .ShowSql())
            .Mappings(m => 
                m.AutoMappings.Add(AutoMap.AssemblyOf<SomeClass>()))
            .ExposeConfiguration(x => 
                x.SetInterceptor(new DependencyInjectionEntityInterceptor(container)));                
    }
    
    public FluentConfiguration GetFluentConfiguration(IContainer容器)
    {
    流畅地返回。Configure()
    .数据库(MsSqlConfiguration.MsSql2008
    .ConnectionString(c=>c.FromConnectionStringWithKey(“数据库”))
    .ShowSql())
    .Mappings(m=>
    m、 AutoMappings.Add(AutoMap.AssemblyOf()))
    .ExposeConfiguration(x=>
    x、 SetInterceptor(新的DependencyInjectionEntityInterceptor(容器));
    }
    

    当我对此进行研究时,有人建议将SessionFactory传递到拦截器类的ctor中。老实说,从会话管理的角度来看,这种方法会更好。

    我一直认为,通过提供您自己的
    iProxyFactory
    实现,这是可能的,但我从未真正尝试过。您向实体中注入了什么样的依赖关系?正如我所说,我现在只是在试验。这违背了我的“天性”。到目前为止,我已经注入了一个时间提供者、一个notificationService和一个存储库。在这一点上,我不太喜欢它。但是这个练习让我找到了一个更好的设计(一个实际上没有依赖实体的设计)如果您能发布您的替代解决方案,那就太好了;)现在我可以想象没有依赖关系的实体。我决定创建一个名为“聊天室”的典型“服务”类,该类处理保存对话、创建新对话和通知参与者等行为。这将从我的“对话”实体中删除所有依赖项。我的对话仍然有行为,但不需要依赖关系。我认为这种设计更有意义。
    public FluentConfiguration GetFluentConfiguration(IContainer container)
    {
        return Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008
                      .ConnectionString(c => c.FromConnectionStringWithKey("Database"))
                          .ShowSql())
            .Mappings(m => 
                m.AutoMappings.Add(AutoMap.AssemblyOf<SomeClass>()))
            .ExposeConfiguration(x => 
                x.SetInterceptor(new DependencyInjectionEntityInterceptor(container)));                
    }