I have a situation where I need to map a single property as a combination of multiple source properties based on some conditions.
Destination :
public class Email
{
public Email() {
EmailRecipient = new List<EmailRecipient>();
}
public string Subject{get; set;}
public string Body {get; set;}
public virtual ICollection<EmailRecipient> EmailRecipient { get; set; }
}
public class EmailRecipient
{
public int EmaiId { get; set; }
public string RecipientEmailAddress { get; set; }
public int RecipientEmailTypeId { get; set; }
public virtual Email Email { get; set; }
}
Source:
public class EmailViewModel
{
public List<EmailRecipientViewModel> To { get; set; }
public List<EmailRecipientViewModel> Cc { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
public class EmailRecipientViewModel
{
public string RecipientEmailAddress { get; set; }
}
I want Mapper.Map<EmailViewModel,Email>()
Here I would like to map my Email.EmailRecipient as a combination of EmailViewModel.To and EmailViewModel.Cc.
However the condition is, Email.EmailRecipient.RecipientEmailTypeId will be 1 for To and 2 for Cc
Hope my question is clear.
One possible way to achieve this is to create a map that uses a specific method for this conversion. The map creation would be:
Mapper.CreateMap<EmailViewModel, Email>()
.ForMember(e => e.EmailRecipient, opt => opt.MapFrom(v => JoinRecipients(v)));
Where the JoinRecipients method would perform the conversion itself. A simple implementation could be something like:
private ICollection<EmailRecipient> JoinRecipients(EmailViewModel viewModel) {
List<EmailRecipient> result = new List<EmailRecipient>();
foreach (var toRecipient in viewModel.To) {
result.Add(new EmailRecipient {
RecipientEmailTypeId = 1,
RecipientEmailAddress = toRecipient.RecipientEmailAddress
});
}
foreach (var ccRecipient in viewModel.Cc) {
result.Add(new EmailRecipient {
RecipientEmailTypeId = 2,
RecipientEmailAddress = ccRecipient.RecipientEmailAddress
});
}
return result;
}
I'm a huge opponent of converters, mostly because for other people in your project, things will just happen 'like magic' after the mapping call.
An easier way of handling this would be to implement the property as a method that converts other properties on the viewmodel to the required formatting. Example:
public class EmailViewModel
{
public ICollection<EmailRecipient> EmailRecipient {
get {
return To.Union(Cc);
}
}
public List<EmailRecipientViewModel> To { get; set; }
public List<EmailRecipientViewModel> Cc { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
Now automapper automatically maps from EmailRecipient property to EmailRecipient property, and if someone is trying to figure out how it happens, they just need to look on the viewmodel.
Editing this some years later: Just as a warning, doing things this way means that every time you call EmailRecipient, you incur the o(n) task of unioning the To and Cc fields. This is fine if you're only dealing with one email, but if you're reusing the viewmodel and someone sticks it in a loop with say, every other email in the system, it might be a huge performance issue. In that case I'd go with the accepted answer so that you dodge this potential performance pitfall.
Related
I know we can set the Context items when we call Map(), and it will be available to every map operation. Is there a way to change those context items during mapping?
Suppose I have these source types:
public class OuterSource {
public string TimeZone { get; set; }
public string Name { get; set; }
public InnerSource[] InnerArray { get; set; }
}
public class InnerSource {
public DateTime Created { get; set; }
public string Message { get; set; }
}
and these destination types:
public class OuterDest {
public string Name { get; set; }
public InnerDest[] InnerArray { get; set; }
}
public class InnerDest {
public DateTime Created { get; set; }
public string Message { get; set; }
}
The only difference is that InnerSource.Created is in UTC and I want to map it to the local time zone. However the time zone is in OuterSource, not InnerSource.
Normally, I would set up my mappers like so:
CreateMap<OuterSource, OuterDest>();
CreateMap<InnerSource, InnerDest>();
But that wouldn't work because when it comes to mapping InnerSource to InnerDest it does not have access to OuterSource.TimeZone.
So I'm currently forced to set my mapping like so:
CreateMap<OuterSource, OuterDest>()
.ForMember(dest => dest.InnerArray, opt => opt.ResolveUsing(
//loop through source.InnerArray and do the datetime
//conversion manually
));
I consider that a code smell. What I would love to do is to pass the timezone to the nested mapping somehow. I would appreciate any pointers towards that direction.
So, I'm building a system for managing contacts. My contact domain model has quite a few string properties, as well as booleans. In the spirit of keeping behavior inside of the domain models, I've gone down the path of creating "update methods." I'm starting to feel like it's getting a bit burdensome. In the past, CRUD apps would just have a single update method and it would set all of the properties in one shot.
Am I on the right path? I'm concerned about having 10 - 15 update methods on my domain service and domain entities.
FYI, the example given is a bit contrived, so imagine a model with lots of string and boolean properties.
// Application Layer Stuff
public class UpdateContactCommand
{
public UpdateNamePredicate UpdateName { get; set; }
public UpdatePhonePredicate UpdatePhone { get; set; }
public int ContactId { get; set; }
}
public class UpdateNamePredicate
{
public string NewFirstName { get; set; }
public string NewLastName { get; set; }
}
public class UpdatePhonePredicate
{
public string NewPHone { get; set; }
}
public class UpdateContactResponse
{
public bool Success { get; set; }
public string Message { get; set; }
}
public interface IWcfService
{
UpdateContactResponse UpdateContact(UpdateContactCommand updateContactCommand);
}
public class WcfService : IWcfService
{
private readonly IContactService _contactService;
public WcfService(IContactService contactService)
{
_contactService = contactService;
}
public UpdateContactResponse UpdateContact(UpdateContactCommand updateContactCommand)
{
if (updateContactCommand.UpdateName != null)
{
_contactService.UpdateName(updateContactCommand.ContactId, updateContactCommand.UpdateName.NewFirstName,
updateContactCommand.UpdateName.NewLastName);
}
if (updateContactCommand.UpdatePhone != null)
{
_contactService.UpdatePhone(updateContactCommand.ContactId, updateContactCommand.UpdatePhone.NewPHone);
}
return new UpdateContactResponse();
}
}
// Domain Layer
public interface IContactService
{
// There are lots more of these
void UpdateName(int contactId, string newFirstName, string newLastName);
void UpdatePhone(int contactId, string newPhone);
}
public class ContactService : IContactService
{
private readonly IContactRepository _contactRepository;
public ContactService(IContactRepository contactRepository)
{
_contactRepository = contactRepository;
}
public void UpdateName(int contactId, string newFirstName, string newLastName)
{
var contact = _contactRepository.GetById(contactId);
contact.SetName(newFirstName, newLastName);
_contactRepository.Commit();
}
public void UpdatePhone(int contactId, string newPhone)
{
var contact = _contactRepository.GetById(contactId);
contact.SetPhone(newPhone);
_contactRepository.Commit();
}
}
public interface IContact
{
int Id { get; set; }
// There are lots more of these
void SetName(string newFirstName, string newLastName);
void SetPhone(string newPhone);
}
public class Contact : IContact
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public void SetName(string newFirstName, string newLastName)
{
FirstName = newFirstName;
LastName = newLastName;
}
public void SetPhone(string newPhone)
{
Phone = newPhone;
}
}
public interface IContactRepository
{
IContact GetById(int id);
void Commit();
}
public class ContactRepository : IContactRepository
{
public IContact GetById(int id)
{
// Not important
throw new NotImplementedException();
}
public void Commit()
{
// Not important
throw new NotImplementedException();
}
}
First of all, not all applications lend themselves well to a DDD approach. If you say your application could pretty much have been implemented in a CRUDish way before, chances are it's still CRUD now. Don't try to apply DDD on any app because it's the shiny new thing.
That being said, you don't just write "update methods" for the fun of it. They have to reflect the domain tasks your user wants to perform. Why does the user want to update a Contact ? Has the contact moved or just changed phone number ? Changed marital status and name ? Has the point of contact in a company been taken over by another employee ?
Usually, you won't have tons of update methods for a given entity. There's always a way to group changes in operations that are meaningful for the domain. Good ways to force yourself to do it are :
Think about the maximum number of form fields you can reasonably display to the user. Couldn't you split that complex UI into smaller, more meaningful screens ? From there you have to start reasoning (preferably with the help of a domain expert) about the tasks these should reflect.
Make your entity fields immutable from the outside. Thus you'll have to think harder about their true nature -- what should be in the constructor ? what should some other manipulation methods be ?
I am using these classes:
public class MasteryPages
{
internal MasteryPages() { }
[JsonProperty("pages")]
public List<MasteryPage> Pages { get; set; }
[JsonProperty("summonerId")]
public long SummonerId { get; set; }
}
[Serializable]
public class MasteryPage
{
internal MasteryPage() { }
[JsonProperty("current")]
public bool Current { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("talents")]
public List<Talent> Talents { get; set; }
}
[Serializable]
public class Talent
{
internal Talent() { }
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("rank")]
public int Rank { get; set; }
}
This is the code I'm using to deserialise the object
//MASTERIES
var jsonMasteries = requester.CreateRequest(string.Format(RootUrl, Region) + string.Format(MasteriesUrl, summonerId));
var objAllMasteryPages = JsonConvert.DeserializeObject<MasteryPages>(jsonMasteries);
The jsonMasteries object is correctly serialized and gives me this:
http://pastebin.com/3dkdDHdx (Rather large, to view easily: go to http://www.jsoneditoronline.org/ and paste it)
The second line is giving me troubles however. Normally my object should be filled with the data. It unfortunately isn't and I have no idea what's wrong.
Anyone could help me out?
Your problem is in this part of serialized JSON: "42177333": { ... }
As I understand - this is some kind of ID and it's dynamic.
Possible solutions are:
One of possible resolutions is here: C# deserialize dynamic JSON
Cut this part of dynamic JSON.
Try to modify the serialization stuff to avoid this dynamic ID.
Thanks to sleepwalker I saw what was wrong. (Dynamic Id (number), first line)
Now, the James Newtonking JSON library has a solution for dynamic id's like this.
I edited my code to this:
var jsonMasteries = requester.CreateRequest(string.Format(RootUrl, Region) + string.Format(MasteriesUrl, summonerId));
var objAllMasteriePages = JsonConvert.DeserializeObject<Dictionary<long, MasteryPages>>(jsonMasteries).Values.FirstOrDefault().Pages;
(First line stays the same, the magic is in the second line)
Now, i use a dictionary with the key being my given Id, and my custom class.
This works wonders
Consider the following:
public class VideoContainer<T>
{
public string Name { get; set; }
//public List<VideoContainer<T>> VideoContainers { get; set; }
}
public class Perspective : VideoContainer<Perspective>
{
public List<VideoContainer<SourceContainer>> VideoContainers { get; set; }
}
I want to ensure VideoContainer<Perspective>.VideoContainers can only contain VideoContainer<SourceContainer> types.
I add a new Perspective object to a List<Perspective> with three VideoContainers. The problem is that when I add a new Perspective to the list, the previously-added Perspective.VideoContainers is null.
Why is this happening?
It sounds like you need two generic types:
public class VideoContainer<T, U>
{
public string Name { get; set; }
public List<VideoContainer<U>> VideoContainers { get; set; }
}
public class Perspective : VideoContainer<Perspective, SourceContainer>
{
// No longer declare the list, just use it... it's now:
// public List<VideoContainer<SourceContainer>> VideoContainers { get; set; }
}
I think I may be using generic interfaces inappropriately (but not sure so please tell me). I have a small inheritance hierarchy for horse racing. There are 3 primary interfaces : IMeeting + IRace + IRunner which I have reduced for the example. The meeting contains races which contains runners. I have used generics to make runtime decisions on the concrete types but it looks ugly, the WriteData method param has to declare the type for IMeeting which has to declare the type for IRace etc e.g.
static void WriteData(IMeeting<IRace<IRunner, string>> meeting)
Here is the little example:
class Program
{
static void Main(string[] args)
{
IMeeting<IRace<IRunner, string>> meeting = new Meeting<IRace<IRunner, string>>();
IRace<IRunner, string> slrace = new SL_Race<IRunner, string>();
IRunner slrunner = new SL_Runner();
slrace.Runners.Add(slrunner);
meeting.Races.Add(slrace);
WriteData(meeting);
}
static void WriteData(IMeeting<IRace<IRunner, string>> meeting)
{
// Write to db or whatever
}
}
public interface IMeeting<T_Race>
{
string Course { get; set; }
string CourseId { get; set; }
List<T_Race> Races { get; set; }
}
public class Meeting<T_Race> : IMeeting<T_Race>
{
public string Course { get; set; }
public string CourseId { get; set; }
public List<T_Race> Races { get; set; }
public Meeting()
{
Races = new List<T_Race>();
}
}
public interface IRace<T_Runner, T_Going>
{
T_Going Going { get; set; }
List<T_Runner> Runners { get; set; }
}
public interface ISL_Race<T_Runner, T_Going> : IRace<T_Runner, T_Going>
{
// Extended behaviour
string Time { get; set; }
string RaceId { get; set; }
string Info { get; set; }
uint MaxOR { get; set; }
}
public class SL_Race<T_Runner, T_Going> : ISL_Race<T_Runner, T_Going>
{
// IRace
public T_Going Going { get; set; }
public List<T_Runner> Runners { get; set; }
// ISL_RACE
public string Time { get; set; }
public string RaceId { get; set; }
public string Info { get; set; }
public uint MaxOR { get; set; }
public SL_Race()
{
Runners = new List<T_Runner>();
}
}
public interface IRunner
{
string Name { get; set; }
}
public class SL_Runner : IRunner
{
public string Name { get; set; }
}
In my real world app there are a few different types of concrete runner and races. I am trying to create a relevant meeting at runtime. In my mind IMeeting must have a declaration for IRaces but the concrete race type can't be known until runtime and same for the runners. My real world app also has more generic parameters and I end up with ugly looking method signatures that have to be aware of the types up the hierarchy e.g.
public List<IMeeting<IRP_Race<IRP_Runner, Going>>> ExtractMeetingList(String dayResultPage)
So am I using generics inappropriately? I could remove all generics by moving the generic properties down to concrete classes and specify them as non generic e.g. I could move IRace.Runners to the SL_Race class, but it seems to me it should be in IRace as a race interface should have runners.
Thanks for any input.
**edit - having thought about it I should probably remove the generics and just create a subclass that has the required types that will be known at compile time e.g.
public interface IMeeting
{
string Course { get; set; }
string CourseId { get; set; }
}
// This is the new subclass with the list of concrete races "ISL_RACE"
public class ISL_Meeting : IMeeting
{
List<ISL_Race> Races { get; set; }
}
public class SL_Meeting : ISL_Meeting
{
public string Course { get; set; }
public string CourseId { get; set; }
List<ISL_Race> Races {get; set;}
public SL_Meeting()
{
Races = new List<ISL_Race>();
}
}