Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Value Injecter : Dto to Domain Model (NHibernate)

I am using ValueInjecter to map properties from a Domain model to a DTO served up via a Service Layer. The service in question also accepts updates... so an updated DTO is passed in and this is then injected to the domain object and saved.

    // 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;
    }

Now all this above code does is updates the Property Member.Country.Code which is obviously not what I need it to do.

So from the docs, I figured I needed to create an override and got this:

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;
    }

My problem is during debugging, CountryLookup never gets called.

Possible reasons I can think of:

  • Nhibernate Proxy classes causing value injecter to not match the Country type? Tho this doesnt make sense because it works during the flattening.
  • Perhaps the unflattening isn't firing for some reason. I.e Dto is CountryCode and Domain is Country.Code

I need to use the CountryCode property on the Dto to call a countryService.LookupCode to return the correct object to use during the update injection.

like image 316
Galen Avatar asked Jan 24 '11 14:01

Galen


2 Answers

unflattening would be to do this:

entity.Country.Code <- dto.CountryCode

what you need is:

entity.Country <- dto.CountryCode

so the solution for you would be to inherit an ExactValueInjection where you would go from CountryCode to Country.

what I recommend you to do is do the same that I did in the live demo of another project of mine http://awesome.codeplex.com

where I have something like this:

    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;}
    }

and use these injections to go from entity to dto and back

    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;
            }
        }

these injections will handle not just going from int? to Country and back but also any other type which inherits Entity

like image 151
Omu Avatar answered Sep 18 '22 16:09

Omu


Using the suggestion/reference from Omu this was the specific code to the problem.

 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;
}
like image 24
Galen Avatar answered Sep 22 '22 16:09

Galen