Is there a generic way to join list and aim specific values to properties?

I want to find a way to reproduce the code below in a generic way. Very often in the software that I work with, we compare two list of object like this:

 d.FeatureViewModels = (from feature in d.FeatureViewModels
                        join pairedFeature in s.FeaturePairTransit on feature.Id equals pairedFeature.Feature.Id
                        select new FeatureViewModel
                        {
                            Id = feature.Id,
                            Name = feature.Name,
                            DisplayOrder = feature.DisplayOrder,
                            MembershipId = feature.MembershipId,
                            IsPaired = pairedFeature.IsPaired,
                            TranslationId = feature.TranslationId,
                            DisplayNameViewModel = feature.DisplayNameViewModel,
                            DescriptionViewModel = feature.DescriptionViewModel
                        }).ToList();

As you can see, the field that needs to be added is IsPaired and every other fields comes from feature. This is also like that for many objects elsewhere in the app. Instead of copying, pasting and adapting the code above every time, I would like to have a generic method I can reuse if it’s possible to do so. I need some help to start for that purpose.

Anyone can help?

David

Edit

Based on the answer and comments of Matias, I think that I must be more precise:

The FeaturePairTransit class is like below:

public class FeaturePairTransit
    {
        public Feature Feature { get; set; }
        public bool IsPaired { get; set; }
    }

Furthermore, the FeatureViewModel has IsPaired property in it What I want to achieve is to find a way of Mapping FeaturePairTransit.IsPaired to FeatureViewModel.IsPaired and reuse the pattern.

Here the complete AutoMapper code for that specific question:

    Mapper.CreateMap<SKUFeatureTransit, SKUFeaturePivotViewModel>()
// Will give a different level error
                    //.ForMember(d => d.FeatureViewModels.Select(x => x.IsPaired), opt => opt.MapFrom(s => s.FeaturePairTransit.Select(x => x.IsPaired)))
                    .AfterMap((s, d) => d.SKUViewModel = Mapper.Map<SKUViewModel>(s.SKU))
                    .AfterMap((s, d) =>
                    {
                        // This is mandatory because we need to instantiate every translation fields with the constructor.
                        d.FeatureViewModels = Mapper.Map<IList<FeatureViewModel>>(s.FeaturePairTransit.Select(x => x.Feature));

                        // We cannot map an individual property (IsPaired) from a different level. So we did this comparaison.
                        d.FeatureViewModels = (from feature in d.FeatureViewModels
                                               join pairedFeature in s.FeaturePairTransit on feature.Id equals pairedFeature.Feature.Id
                                               select new FeatureViewModel
                                               {
                                                   Id = feature.Id,
                                                   Name = feature.Name,
                                                   DisplayOrder = feature.DisplayOrder,
                                                   MembershipId = feature.MembershipId,
                                                   IsPaired = pairedFeature.IsPaired,
                                                   TranslationId = feature.TranslationId,
                                                   DisplayNameViewModel = feature.DisplayNameViewModel,
                                                   DescriptionViewModel = feature.DescriptionViewModel
                                               }).ToList();
                    });

Then, I see two options, maybe there is something as @Matias said so AutoMapper can take care of, and that I still try to figure out OR I can do the mapping in a generic way. Any suggestions?

Answers


AutoMapper, AutoMapper, AutoMapper...

You can turn your code into:

 d.FeatureViewModels = (from feature in d.FeatureViewModels
                        join pairedFeature in s.FeaturePairTransit on feature.Id equals pairedFeature.Feature.Id
                        select mapper.Map<Feature, FeatureViewModel>(feautre)).ToList();

@devuxer in some comment said:

Yes, but not quite that simple. You also need a CreateMap statement.

Ok, since it seems like the view model and the domain objects have the same properties.... you'll need to call...:

var mapperConfig = new MapperConfiguration(cfg => {
    cfg.CreateMap<Feature, FeatureViewModel>();
});

var mapper = mapperConfig.CreateMapper();

...prior to calling mapper.Map(...)!


I finally found what I was looking for.

This is not generic like I imagined, but it's a good step in the right direction.

// HTTPGET
            Mapper.CreateMap<SKUFeatureTransit, SKUFeaturePivotViewModel>()
                .AfterMap((s, d) => d.SKUViewModel = Mapper.Map<SKUViewModel>(s.SKU))
                .AfterMap((s, d) =>
                {
                    // This is mandatory because we need to instantiate every translation fields with the constructor.
                    d.FeatureViewModels = Mapper.Map<IList<FeatureViewModel>>(s.FeaturePairTransit.Select(x => x.Feature));

                    // We cannot map an individual property (IsPaired) from a different level. So we did this comparaison.
                    d.FeatureViewModels = d.FeatureViewModels.Join(s.FeaturePairTransit, vModel => vModel.Id, source => source.Feature.Id, (dest, source) =>
                    {
                        dest.IsPaired = source.IsPaired;
                        return dest;
                    }).ToList();
                });

Hope this can help someone else

David


Need Your Help

read data from struct into 2d array c

c arrays struct multidimensional-array

I'm trying to plot coordinates to a map using a 2d Array. The data for the coordinates has been entered by the user and held in a structure. This is a snippet of code taken out of my main program.