How to specify mapping rule for bunch of properties - c#

I have 2 classes and want to configure mapping from one to another
public class Customer
{
public long CustomerId{get;set;}
public string ShippingAddres{get;set;}
public string BillingAddress{get;set;}
public DateTime DateOfBirth {get;set;}
}
public class Item2
{
public long customer_id{get;set;}
public string shipping_addres{get;set;}
public string billing_address{get;set;}
public DateTime date_of_birth {get;set;}
}
I tried to search the answer but all answers that I find tell to map fields manually:
.ForMember(dest => dest.CustomerId, opt => opt.MapFrom(src => src.customer_id));
I don't want to map each property manually, since I have a lot of properties. I want to configure some rule:
to split property name by '_' and join strings to CamelCase
or in pseudo code:
cfg.AddConditionalObjectMapper().Where((source, destination) => s.Name.Replace("(_)([a-z])","\U1") == d.Name );
The question is not about the Regex, I need to know how to configure such rules in Auto-mapper?

I found a way to configure it, but this method is not universal:
cfg.AddMemberConfiguration().AddName< ReplaceName >( _ => _.AddReplace( "_", "" ) );
cfg.AddMemberConfiguration().AddName< CaseInsensitiveName >();

Related

c# automapper lookup value from source model

I have a model which has a generic properties property looking something like this:
public class GenericProperty
{
public string Name { get; set; }
public object Value { get; set; }
}
Next to that I have a object that has a list with GenericProperties like this:
public class GenericEntity
{
public string Name { get; set; }
public List<GenericProperty> Properties { get; set; }
}
Now im calling a API that deserialize the json to the model above. Next i want to use AutoMapper to construct an actual good looking model so i did the following:
Mapper.Initialize(x =>
{
x.CreateMap<GenericEntity, MyModel>()
.ForMember(d => d.ManagerId, o => o.MapFrom(s => s.Properties.Where(n => n.Name == "ManagerId" ).Select(v => v.Value)))
});
Problem is that this returns the property type and not the actual value:
System.Linq.Enumerable+WhereListIterator`1[MyProject.Models.GenericProperty]
How can i lookup the value of within the model?
By using Where you are selecting all the properties with the name ManagerId. You should instead use Single like in this unit test:
public class TestClass
{
[Test]
public void TestMapper()
{
Mapper.Initialize(x =>
{
x.CreateMap<GenericEntity, MyModel>()
.ForMember(d => d.ManagerId,
o => o.MapFrom(s => s.Properties.Single(n => n.Name == "ManagerId").Value));
});
var ge = new GenericEntity
{
Properties = new List<GenericProperty>
{
new GenericProperty {Name = "ManagerId", Value = "Great"}
}
};
var myModel = Mapper.Map<MyModel>(ge);
Assert.AreEqual("Great", myModel.ManagerId);
}
}
If you can not guarantee that there will be a property with the name ManagerId, you should use SingleOrDefault, and handle the null case.
IMHO, you should limit this kind of AutoMapper configurations to simple cases, since it quickly gets difficult to debug and maintain.
For more complex mappings like this one, I would recommend you to make an explicit mapping method instead, which you can call like an extension method. Another option worth considering if you want to use Automapper are Custom value resolvers.

Automapper Map UserId Property By Name to static value

I use automapper to map models between each user.
I can also do this to map a property of a specific type to a userId
cfg.CreateMap<Model, Command>()
.ForMember(dest => dest.UserId, opt => ClaimsPrincipal.Current.UserId))
But I can't find a way to make this to some kind of convention so that everytime models are mapped and there is a Property "UserId" it should be set to ClaimsPrincipal.Current.UserId.
Is this now working ?
Any advice?
Have you tried the MapTo Attribute?
public class Foo
{
[MapTo("SourceOfBar")]
public int Bar { get; set; }
}

Automapper create map from custom method

I have the following classes:
public class Entity
{
public string Name { get; set; }
}
public class SomethingDto
{
public string NameChanged { get; set; }
public void Mapping(Entity something)
{
NameChanged = something.Name;
}
}
I want to use the Mapping Method of the DTO to create the map as the following way:
conf.CreateMap<Entity, SomethingDto>().ForMember(t => t.NameChanged, opt => opt.MapFrom(t => t.Name));
There is a way in AutoMapper to create the maps with custom methods, who works with his projection?
You don't want to do it like that, because that makes the DTO aware of the entity and that would throw out the separation you'd get.
Now in this case, the line ForMember(t => t.NameChanged, opt => opt.MapFrom(t => t.Name)) will work because Name and NameChanged are both of type string. Say you'd like to do something along the lines of mapping identifier of type string with value '20180120-00123456' to two properties on the destination: a DateTime property and a ProductId property. You can do this two ways.
Simple
You would write two mapping functions in the class where you make the mapping and do it along the lines of:
ForMember(t => t.Date, opt => opt.MapFrom(t => RetrieveDate(t.Identifier)))
ForMember(t => t.ProductId, opt => opt.MapFrom(t => RetrieveProductId(t.Identifier)))
Complex
You would make a custom class OrderIdentifier (now I'm assuming the identifier is for an order) with only the Id property as string. Then you'd make two custom type converters, like the article describes.

How can i set the external data that not exist dto object to domain on automapper

I am using Dto for data transfer view to domain and use automapper for mapping.
My problem is, the property that not exist dto but i need to set before mapping to domain.
I have tried to use Linq query to get external data from db on before and after mapping methods but linq query giving error.
Sample below
FooDto
public class FooDto
{
public int MyProperty1 {get;set;}
}
FooDomain
public class Foo
{
public int MyProperty1 {get;set;}
public int MyProperty2 {get;set;}
public int Foo2ID {get;set;}
public virtual Foo2 Foo2 {get;set;}
}
Foo2Domain
public class Foo2
{
public int ID {get;set;}
public int MyProperty1 {get;set;}
}
**AutoMapper*
Mapper.Initialize(x =>
{
x.CreateMap<FooDto, Foo>().BeforeMap(
(src, dest) =>dest.MyProperty2 = dest.Foo2.MyProperty1);
}
I want to set Foo2.MyProperty1 to Foo.MyProperty2 using mapping.
This answer might need to be edited if my assumptions are wrong. The assumption I am making is that the source object has the right data. Based on your sample it looks like your source object's MyProperty2 can be set in the destination object so do map this all you would need to do is:
Mapper.Initialize(x =>
{
x.CreateMap<FooDto, Foo>()
.ForMember(dest => dest.MyProperty2, opt => opt.MapFrom(src => src.MyProperty1))
.ForMember(dest => dest.Foo2.MyProperty1, opt => opt.MapFrom(src => src.MyProperty1));
}
What this code does is it tells AutoMapper when I give you an object of Type FooDto and I am requesting an object of Type Foo. For the destination objects property 'Foo2.MyProperty1' and 'MyProperty2', use the options method MapFrom. Go to the source Object get the MyProperty1 and assign it's value to my destination objects MyProperty2 and Foo2.MyProperty1.
I think this would fix you up.
Right sorry I corrected the answer

Is there a way to easily map between objects in Ruby?

I have an ActiveRecord model in my rails app which I would like to map to some other Ruby object. These models will hit external apis and the main thing that will change between the classes is the field name and some api specifics. In the example below the Person needs to map to the other two Api specific classes.
class Person
include Virtus
attribute :first_name, String
attribute :last_name, String
attribute :gender, String
end
class PersonApi1
include Virtus
attribute :forename, String
attribute :surname, String
attribute :gender, String
end
class PersonApi2
include Virtus
attribute :firstname, String
attribute :secondname, String
attribute :gender, String
end
Is there a mapping gem available that can do this type of mapping? Has anyone else come across a similar mapping problem and how have you approached it?
If I were to roll my own I would think about some sort of hash to map out each of the fields.
The .net world has Automapper where you can say something like below. Is something similar available in Ruby?
public class CalendarEvent
{
public DateTime Date { get; set; }
public string Title { get; set; }
}
public class CalendarEventForm
{
public DateTime EventDate { get; set; }
public int EventHour { get; set; }
public int EventMinute { get; set; }
public string Title { get; set; }
}
//AutoMapper mapping
Mapper.CreateMap<CalendarEvent, CalendarEventForm>()
.ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.EventDate.Date))
.ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.EventDate.Hour))
.ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.EventDate.Minute));
From the automapper wiki https://github.com/AutoMapper/AutoMapper/wiki/Projection
I don't know of any gem that does this, so I put one together yesterday - give it a try if you want - https://github.com/house9/simple_attribute_mapper
UPDATE: version 0.0.2 now supports the following mappings
default (source and target matching attribute names)
standard source to target attribute
nested source to target attribute
composite (lambda style) source to target attribute

Categories

Resources