【问题标题】:Value Injecter : Dto to Domain Model (NHibernate)值注入器:Dto 到域模型 (NHibernate)
【发布时间】:2011-01-24 14:31:44
【问题描述】:

我正在使用ValueInjecter 将属性从域模型映射到通过服务层提供的 DTO。有问题的服务也接受更新...因此传入更新的 DTO,然后将其注入域对象并保存。

    // Domain
    public class Member 
    {
      public Country Country { get; set; }
    }

    public class Country 
    {
      public string Code { get; set; }
      public string Name { get; set; }
    }

    //Dto
    public class MemberDto 
    {
       public string CountryCode { get; set; }
    }

    //Transformation Method attempt 1
    public Member InjectFromDto (MemberDto dto, Member source)
    {
       source = source.InjectFrom<UnflatLoopValueInjection>(dto);
       return source;
    }

现在上面的代码所做的只是更新 Property Member.Country.Code 这显然不是我需要它做的。

所以从文档中,我想我需要创建一个覆盖并得到这个:

public class CountryLookup: UnflatLoopValueInjection<string, Country>
    {
        protected override Country SetValue(string sourcePropertyValue)
        {
            return countryService.LookupCode(sourcePropertyValue);
        }
    }


 //revised transformation call
 //Transformation Method attempt 2
    public Member InjectFromDto (MemberDto dto, Member source)
    {
       source = source.InjectFrom<UnflatLoopValueInjection>(dto)
                      .InjectFrom<CountryLookup>(dto);
       return source;
    }

我的问题是在调试过程中,CountryLookup 永远不会被调用。

我能想到的可能原因:

  • Nhibernate 代理类导致值注入器与 Country 类型不匹配?但这没有意义,因为它在展平期间起作用。
  • 也许由于某种原因,unflattening 没有触发。即 Dto 是 CountryCode 而 Domain 是 Country.Code

我需要使用 Dto 上的 CountryCode 属性来调用 countryService.LookupCode 以返回要在更新注入期间使用的正确对象。

【问题讨论】:

  • 告诉我们你想达到什么目标,第一次尝试成功,但不是你需要的,你需要什么?
  • 您的名为 CountryLookup 的注入将从字符串转换为 Country,这意味着它看起来从字符串类型的 CountryCode 获取值并将其放入 Country.Code 类型的 Country
  • @Omu 是正确的,例如,如果我的 Country 对象是 Country: { Code: USA, Name: United States} 并且我的 Dto 传入 CountryCode: "CA" 它只是设置 Country.Code 属性到 CA 并将“名称”属性保留为美国。请记住,我正在更新一个预填充的域对象...因此,我需要调用我的 countryService 来查找正确的 Country 对象。我想从 Dto 中捕获“代码”,然后使用该代码查找正确的 Country 对象。

标签: nhibernate dto automapping valueinjecter


【解决方案1】:

unflattening 就是这样做:

entity.Country.Code <- dto.CountryCode

你需要的是:

entity.Country <- dto.CountryCode

因此,您的解决方案是继承 ExactValueInjection,您将从 CountryCode 转到 Country。

我建议你做的事情是和我在另一个项目 http://awesome.codeplex.com987654321@

的现场演示中做的一样

我有这样的东西:

    public class Entity
    {
       public int Id{get;set;}
    }
    public class Member : Entity
    {
        public Country Country{get;set;}
    }
    public class MemberDto : DtoWithId
    {
        public int? Country {get;set;}
    }

并使用这些注入从实体到 dto 并返回

    public class NullIntToEntity : LoopValueInjection
        {
            protected override bool TypesMatch(Type sourceType, Type targetType)
            {
                return sourceType == typeof(int?) && targetType.IsSubclassOf(typeof(Entity));
            }

            protected override object SetValue(object sourcePropertyValue)
            {
                if (sourcePropertyValue == null) return null;
                var id = ((int?) sourcePropertyValue).Value;

                dynamic repo = IoC.Resolve(typeof(IRepo<>).MakeGenericType(TargetPropType));

                return repo.Get(id);
            }
        }
//(you also need to have a generic repository, notice IRepo<>)    
    public class EntityToNullInt : LoopValueInjection
        {
            protected override bool TypesMatch(Type sourceType, Type targetType)
            {
                return sourceType.IsSubclassOf(typeof (Entity)) && targetType == typeof (int?); 
            }

            protected override object SetValue(object o)
            {
                if (o == null) return null;
                return (o as Entity).Id;
            }
        }

这些注入不仅会处理来自 int 的处理吗?到 Country 并返回,还包括任何其他继承 Entity

的类型

【讨论】:

  • 这条评论导致了我的问题的具体答案,但没有显示确切的答案,这不好发布。这是否可以作为 +1 的帮助。
【解决方案2】:

使用 Omu 的建议/参考,这是问题的具体代码。

 public class CountryLookup : ExactValueInjection
    {
        private ICountryService countryservice;

        public CountryLookup(ICountryService countryService)
        {
           this.countryService = countryService; 
        }

        protected override bool TypesMatch(Type s, Type t)
        {
            return (s == typeof(string)) && (t == typeof (Country));

        }
        protected override Object SetValue(object v)
        {
            if (v == null) 
                return null;

            var country = countryService.LookupCode((string) v);
            return country;
        }

        public override string SourceName()
        {
            return "CountryCode";
        }

        public override string TargetName()
        {
            return "Country";
        }    
    }

public Member InjectFromDto (MemberDto dto, Member source)
{
   source = source.InjectFrom<UnflatLoopValueInjection>(dto)
                  .InjectFrom<CountryLookup>(dto);
   return source;
}

【讨论】:

  • 是的,这应该可以工作(虽然我没有看到你在哪里设置了构造函数参数 ICountryService),我只是想让你看一个更通用的方法,对所有东西都进行注入
  • 在这种情况下,构造函数参数是通过 Castle Windsor 依赖注入设置的。由于实际的查找服务调用不那么相关,因此对于解决方案来说这是一个静音点。
  • 另外,我将根据您的建议考虑为该项目提供通用解决方案,谢谢 :)
【解决方案3】:

框架是否调用了setter方法?在大多数 DI 框架中,标准是 setMethod() 中的小写“s”。只是初步考虑的建议。

【讨论】:

  • 你指的是SetValue方法吗?如果是这样,那是 ValueInjecter 框架的一部分。
  • 尼克,这是 .NET,不是 Java,.NET 标准是方法名称的帕斯卡大小写,而不是骆驼大小写。
猜你喜欢
  • 2018-08-05
  • 2013-12-03
  • 1970-01-01
  • 2011-01-04
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多