Automapper Map UserId Property By Name to static value - c#

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

Related

.NET Core 3 automapper not mapping different name variables? Worked in .NET framework

Below is the Automapping profile. An error is thrown on the destination Id being of the wrong input format.
The destination Id property is not even being mapped to.
public class AspGetUserLoginReturnModelToSRSDLUserLoginModel : Profile
{
public AspGetUserLoginReturnModelToSRSDLUserLoginModel()
{
CreateMap<asp_GetUserLoginReturnModel, SRSDLUserLoginModel>()
.ForMember(dest => dest.UserPassword, opt => opt.MapFrom(src => src.PasswordHash))
.ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.Id)
;
}
}
Now the destination class SRSDLUserLoginModel is derived from a base class that has a public accessor named Id which is type of nullable long.
The source Id property used above is of type string.
As the code shown above the source Id is mapped to the destination UserId property.
But Automapper is mapping the source Id to the destination's based classes Id property.
WHY IS THIS HAPPENING?
The code is straight forward and there is nothing new trying to be accomplished.
It Automapper like most everything other packages that I have work with?
In the full/classic .NET framework, the packages worked fine, but in .NET Core those packages just suck?
// source class
public partial class asp_GetUserLoginReturnModel
{
public string Id { get; set; }
}
// destination classes
public class SRSDLUserLoginModel: SRSDLModel, ISRSDLUserLoginModel
{
public string UserId { get; set; }
public string UserPassword { get; set; }
// [...]
}
public class SRSDLModel : ISRSDLModel
{
public long? Id { get; set; }
// [...]
}
AutoMapper will map properties with the same name by default so you don't have to write them all the time. In this case it tries to set the SRSDLModel.Id property with the value from the asp_GetUserLoginReturnModel.Id property. As you already noticed, that doesn't work because of the mismatch between long? and string.
To fix this, use the .Ignore() method in your mapping to specify that this specific property should no be set during mapping. The configuration might look like this:
.ForMember(dest => dest.Id, i => i.Ignore());

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

Entity Framework Self Referencing Using Non-Primary Key Column

I have an employee table that self references to determine organization structure. I'm having some trouble trying to set this up using Code-First (POCO) fluently.
An employee record has both a "Position" field and a "ReportsTo" field and neither of the columns are the primary key (employee.id).
An employee with a "ReportsTo" value of "08294" , is an employee of a direct report of an employee with "Position" value of "08294".
Can anyone offer up some info on how to set this up using EF code first, fluently...is it possible?
I tried the code below and am getting error:
Employee_Employees_Source_Employee_Employees_Target: : The types of
all properties in the Dependent Role of a referential constraint must
be the same as the corresponding property types in the Principal Role.
The type of property 'ReportsTo' on entity 'Employee' does not match
the type of property 'Id' on entity 'Employee' in the referential
constraint 'Employee_Employees'.
Employee.cs
public class Employee
{
public int Id { get; set; } //pk
public string Position { get; set; } // i.e. 06895
public string ReportsTo{ get; set; } // i.e. 08294
public virtual Employee Supervisor { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
DbContext
modelBuilder.Entity<Employee>()
.HasMany(e => e.Employees)
.WithOptional(e => e.Supervisor)
.HasForeignKey(e => e.ReportsTo);
I think more than anything, I would like to keep the POCO free of EF "stuff" and be able to do something like:
employee.IsSupervisor(); // based on child employee count.
The issue is in the relationship configuration. If you want to configure your one to many relation without using a FK, you could do this:
modelBuilder.Entity<Employee>()
.HasMany(e => e.Employees)
.WithOptional(e => e.Supervisor);
Now if you want to use a FK property, then add this property to your model class:
public class Employee
{
//...
public int SupervisorId { get; set; }
}
And map your relationship this way:
modelBuilder.Entity<Employee>()
.HasMany(e => e.Employees)
.WithOptional(e => e.Supervisor)
.HasForeignKey(e => e.SupervisorId);
To resolve your issue related with ReportTo and Position properties,I think you should handle that logic in your code. If you want to know if an Employee is a supervisor based on the count of Employees property, you could use a NotMapped property:
public class Employee
{
[NotMapped]
public bool IsSupervisor
{
get
{
return Employess.Count>0
}
}
}
You can do the same using Fluent Api:
modelBuilder.Entity<Employee>().Ignore(e => e.IsSupervisor);
PS: Remember initialize Employees in your class'constructor.
The error you get is because it is trying to map a PK of int type to a FK of string type. User int for all of your key fields.
Then, you need to declare your OnModelBuilding like this:
modelBuilder.Entity<Employee>()
.HasOptional(e => e.Supervisor)
.WithMany()
.HasForeignKey(s => s.ReportsTo);
To get something like IsSupervisor() you can take advantage of partial classes. Create another class file which is a public partial class Employee (and modify your original one to be partial), then in your new file you will add a property that does whatever you want, and decorate it with [NotMapped] attribute. Yours will probably look something like public bool IsSupervisor {get { return (Employees == null) ? false : true; } set {} } The new partial class is where you can do whatever you want for the POCO without changing the EF class (make sure you use [NotMapped] though).

How to use automapper with complex types

Within my domain model for my view I have the following object that is serving as backing fields for my properties
public class ModelProperty<T>// where t:struct
{
public T Value { get; set; }
public string Description { get; set; }
public string LabelName { get; set; }
}
The object in turn is presented as:
public partial class Incident : BaseEntityModel
{
private ModelProperty<string> typeCode = new ModelProperty<string>{Description="1-C", LabelName = "Type Code"};
private ModelProperty<string> typeText = new ModelProperty<string>{Description="1-C", LabelName = "Type Text"};
public ModelProperty<string> TypeCode { get {return typeCode;}}
public ModelProperty<string> TypeText { get {return typeText;}}
}
The business object (my source) is not as complex.
public partial class Incident : ObjectBase
{
public string TypeCode { get; set; }
public string TypeText { get; set; }
}
is it possible to map the values from the source to the target. Using Automapper I have the following mapping setup
//note SrcObj is not an object but a namespace alias since the domain and business objects are of the same name
Mapper.CreateMap<SrcObj.Incident, Incident>()
.ForMember(ui => ui.TypeText.Value,
opt => opt.MapFrom(src => src.TypeText));
But I am getting the exception Expression must resolve to top-level member and not any child object's properties. Use a custom resolver on the child type or the AfterMap option instead.
I'm new to automapper but in looking at the documentation is the object I am working with too complex (based on the idea that there are really three types here and not two)?
If it is possible to handle this type of mapping how is this done?
Update
Based upon the suggestion from Jimmy I have updated my code as follows:
Mapper.CreateMap<SrcObj.Incident, Incident>();
Mapper.CreateMap<string, ModelProperty<string>>()
.ConvertUsing(src => new ModelProperty<string> { Value = src });
Mapper.AssertConfigurationIsValid();
SrcObj.Incident viewModelDto = md.GenerateMockIncident(); //populate the business object with mock data
uibase = Mapper.Map<SrcObj.Incident, Incident>(viewModelDto);
The code executes and I do not get any exceptions however the value that is being set and returned in the business object is still not getting assigned to the backing property Value it is still null.
What am I missing?
-cheers
An easier way is to create a type converter:
Mapper.CreateMap<string, ModelProperty<string>>()
.ConvertUsing(src => new ModelProperty<string> { Value = src });
Then you'll have this for every time AutoMapper sees string -> ModelProperty. You won't have to do member-specific configuration at all.
Try this.. you need to give a ModelProperty object mapping to the destination TypeText
Mapper.CreateMap<Funky.Incident, Incident>()
.ForMember(ui => ui.TypeText,
opt => opt.MapFrom(src =>
new ModelProperty<string>
{
Value = src.TypeText
}));
Do the same for the TypeCode property mapping so that all fields are mapped.
You need to account for each member mapping, only if their names are different OR if their type names are different. in this case, AutoMapper will have a hard time converting string to a Model object till you give hints.
Try mapping TypeCode as well.. And i don't know the properties of ObjectBase etc. So you need to do check if any manual mapping is needed there as well.

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