I’ve got a webservice which uses EF to query SQL Server for data. The POCO’s for the three tables we’re interested in are listed below:
public class Plant { public int Id { get; set; } public PlantType PlantType { get; set; } public LifeCycle LifeCycle { get; set; } // other properties } public class PlantType { public int Id { get; set; } public string Name { get; set; } } public class LifeCycle { public int Id { get; set; } public string Name { get; set; } }
The issue is that when a new plant is added (or updated for that matter) using the AddPlant (or UpdatePlant) method we need to ensure EF references the LifeCycle and PlantType within its context. i.e. if we try to simply call something like
context.Plants.Add(newPlant);
then (and even though the LifeCycle and PlantType have an existing Id in the database) EF appears to create new PlantTypes and LifeCycles. Thus giving us multiple instances of the same LifeCycle or PlantType name. For the update method I’ve been using AutoMapper to map all the properties, which works well except for the navigational properties. The problem with EF occurs.
I tried several ways to solve this but kept hitting snags. For example we need to get the instance of the PlantType and LifeCycle from the EF context and assign these to the navigational properties to solve the issue of EF adding new PlantTypes etc. I wanted to achieve this in a nice way with AutoMapper. By default the way to create mappings in AutoMapper is with the static Mapper class which suggests the mappings should not change based upon the current data, so what we really need is to create mappings for a specific webservice method call.
To create an instance of the mapper and use it we can do the following (error checking etc. remove)
using (PlantsContext context = new PlantsContext()) { var configuration = new ConfigurationStore( new TypeMapFactory(), MapperRegistry.AllMappers()); var mapper = new MappingEngine(configuration); configuration.CreateMap<Plant, Plant>() .ForMember(p => p.Type, c => c.MapFrom(pl => context.PlantTypes.FirstOrDefault(pt => pt.Id == pl.Type.Id))) .ForMember(p => p.LifeCycle, c => c.MapFrom(pl => context.LifeCycles.FirstOrDefault(lc => lc.Id == pl.LifeCycle.Id))); //... use the mapper.Map to map our data and then context.SaveChanges() }
So it can be seen that we can now interact with the instance of the context to find the PlantType and LifeCycle to map and we do not end up trying to create mappings on the static class.