I have a service which wraps enum-values in a SafeEnum type, to enable addition of new enum values without breaking the contract.
Here's an example:
public class Customer
{
public int Id { get; set; }
public SafeEnum<CustomerType> Type { get; set; }
}
public class CustomerModel
{
public int Id { get; set; }
public CustomerModelType Type { get; set; }
}
When mapping from Customer to CustomerModel using AutoMapper, is there a way to automatically map from SafeEnum<T> to T', where T is the wrapped type and T' is the matching type in the model?
I know this can be fixed by configuring for each relevant enum-type, but I am looking for a more elegant solution.
I have stumbled with the same problem recently. From what i've gather there is no official support from Automapper for this kind of scenario (there's no mention of generic wrappers or anything similar on the documentation and i couldn't find any web resource with how to do it), but it can be accomplished with a little bit of work.
First you need to create a class that implements the IObjectMapper interface. This interface has two methods IsMatch(ResolutionContext context) and Map(ResolutionContext context, IMappingEngineRunner mapper)
When mapping two objects, the IsMatch method is used internally by Automapper to determine if a given instance of IObjectMapper can be used to map from the source type to the destination type. On the ResolutionContext object you have the SourceType, DestinationType, SourceValue, DestinationValue, an instance of MappingEngine among other things that can help you determine if you can map the two types with your current mapper.
The Map method is responsible for the actual mapping between the two types.
So, on the IsMatch method you should check if the source or destination type are instances of your wrapper class. And then, on the Map method, when mapping from the wrapped value, you could unwrap the value with reflection, and use the mapping engine provided on the ResolutionContext to map the unwrapped value to it's destination type, and then returning it.
Similarly, when mapping from any type to a wrapped type, you could get the type argument of the closed generic wrapper, use the mapping engine provided on the resolution context to map from the source type, to the type enclosed by your generic wrapper, and wrap the result on an instance of the wrapper class of the appropiate type.
Finally, you need to include this mapper when configuring your MappingEngine on the application startup (This doesn't work with with the static method of the Mapper class, since you can't change the default mappers on it), like this:
var configuration = new ConfigurationStore(new TypeMapFactory(), new IObjectMapper[] { new WrapperMapper()}.Union(MapperRegistry.Mappers));
var engine = new MappingEngine(configuration);
The MapperRegistry.Mappers static property is a collection of all the default Automapper mappers. If you don't include these, you'll lose all the default functionality.
Finally, here's a working fiddle:
https://dotnetfiddle.net/vWmRiY
It'll probably need some work to adapt it to your particular use case, but the general idea is there. This could be used to wrap primitive types, complex types, or anything that is supported by automapper.
Related
Scenario
Assume we have a class Target with the following two constructors (one objec, or two objects and an Enum).
public Target(paramOne) { ... }
public Target(paramOne, paramTwo, paramTwoConfigEnum) { ... }
We then have a ClassA which needs to perform a mapping operation from some object to an instance of Target. One version of this would be the following, which relies on existign mapping rules (for automapper), and dependency injection using AutoFac for providing the parameters to perform the mapping. This uses the last of the two constructors above (3 params):
// Behind the scenes this performs a call like: new Target(p1, p2, myEnum)
// with p1, p2 and
var result = _mapper.Map<List<Target>>(someOtherObject);
Next, we have two other classes ClassB, and ClassC. Both of these need to perform similar mapping operations, but here the resulting objects are classes that contain instances of Target; in other words, there is an behind-the-scenes, implicit mapping from someOtherObject into Target here too:
// Behind the scenes this performs calls conceptually similar to the following
// (NB: The second line here will call new Target() with 3 params, as above):
// var x = new ClassContainingTarget(..)
// x.instOfTarget = _mapper.Map<List<Target>>(someOtherObject);
var result = _mapper.Map<ClassContainingTarget>(anotherSourceObject);
The first challenge
For ClassB, the call operation requires values for all three parameters to Target, and values are provided for these via DI.
For ClassC however, paramTwo and paramTwoConfigEnum are not only not needed; they can't be provided via DI in this context. In other words, I what I would like to happen is for the other constructor in Target to be called in this case.
Attempted solution
I realized I can specify which constructor to use when setting up the rules for AutoFac, and override these in specific cases, so I've experimented with the following general setup in my ContainerBuilder:
// This specifies that the constructor that takes a single param of type ParamOne
// should be used by default:
builder.RegisterType<Target>().AsSelf().UsingConstructor(typeof(ParamOne));
With this setup, all the Map() calls above will result in the second (single-param) constructor of Target being used, including in the case of ClassC, where that is exactly what I want.
For the mapping in ClassA then, I can override this logic by replacing the Map() operation shown above with the following:
// Direct manipulation of the rules for mapping to Target, since I'm
// mapping directly to Target. As mentioned below, this does not appear
// to be possible when mapping to classes that contain Target (i.e.
// when Target is mapped implicitly).
result = _mapper.Map<List<Target>>(
someOtherObject,
options =>
options.ConstructServicesUsing(t => new Target(_p1, _p2, myEnum)));
This actualy works in part: Mapping in ClassA causes the 3-param constructor to be called, while that in ClassC causes the 1-param constructor to be called.
Remaining problem
Now the problem remains with ClassB however: I can't see any way to configure it such that it will call the 3-param constructor for Target, since that instantiation and mapping is defined at a lower level, so to speak.
So my question then: Is there any way for me to specify (either from ClassB, or somewhere else) that when Target is instantiated from ClassB, it should use some specific constructor?
Or alternatively, is there some better strategy to get around this problem?
If you want to resolve Target parameters from DI, you'll have to have them registered in container as well (you probably have this, just double-checking):
builder.RegisterType<ParamOne>().AsSelf().UsingConstructor(() => new ParamOne());
builder.RegisterType<ParamTwo>().AsSelf().UsingConstructor(() => new ParamTwo());
builder.RegisterType<ParamTwoEnum>().AsSelf().UsingConstructor(() => ParamTwoEnum.Default);
Then you can use ConstructUsingServiceLocator() as Lucian suggested and a type converter to which you can inject parameters via DI. Mapping configuration:
CreateMap<ClassA, Target>();
CreateMap<ClassB, Target>()
.ConvertUsing<ClassBToTargetTypeConverter>();
CreateMap<ClassC, Target>()
.ConstructUsingServiceLocator();
The ClassBToTargetTypeConverter:
public class ClassBToTargetTypeConverter : ITypeConverter<ClassB, Target>
{
private readonly ParamOne _paramOne;
private readonly ParamTwo _paramTwo;
private readonly ParamTwoEnum _paramTwoConfigParamTwoEnum;
public ClassBToTargetTypeConverter(ParamOne paramOne, ParamTwo paramTwo, ParamTwoEnum paramTwoConfigParamTwoEnum)
{
_paramOne = paramOne;
_paramTwo = paramTwo;
_paramTwoConfigParamTwoEnum = paramTwoConfigParamTwoEnum;
}
public Target Convert(ClassB source, Target destination, ResolutionContext context)
{
return new Target(_paramOne, _paramTwo, _paramTwoConfigParamTwoEnum);
}
}
Summary:
ClassA to Target is mapped normally using source object properties
ClassB to Target is mapped using type converter which in turn construct Target using constructor with three parameters which are resolved from container
ClassC to Target is mapped directly using DI, where Target is registered as to be constructed using constructor with only one parameter
Side note: using Autofac you have the freedom to switch between using the type converter for ClassC or for ClassB and use DI for the other. But! If you were to use default .NET Core DI engine, you'll have to use the type converter for ClassC to Target mapping as DI is designed to be greedy and chooses the constructor with the most parameters it can fill. What that means is if you let .NET Core DI to construct Target by itself having all three parameters registered in service collection, then it would choose constructor with three parameters over constructor with only one parameter, because it's greedy.
I eventually ended up using a different approach to solve this problem. This explains more or less what I did:
Making the second parameter default to null allows this constructor to be used in all cases. Note that I'm leaving out the third parameter altogether; instead, I'll be relying on Automapper to populate it's property instead (that is precisely what I was not able to do originally, and why I was trying to use specific constructors; the next section of code shows how I managed to set that up in th end).
public Target(ParamOne, ParamTwo = null) { ... }
public MyEnumType ConfigEnum {get; set;}
Now when setting upt the mapping from e.g. ClassB to Target, I specify that it should pick up the value for ConfigEnumProp from a value passed in via context (an item with they key "MyConfigEnum"):
// Map to ConfigEnum in Target NOT from the source, but from a value
// passed in via context by the caller:
CreateMap<ClassB, SectionsDTO>()
.ForMember(dest => dest.ConfigEnum,
opt => opt.MapFrom((src, dest, destMember, context) =>
context.Items["MyConfigEnum"]))
This allows me to pass the required enum value as one value when mapping from ClassA...
var result = _mapper.Map<List<Target>>(instanceOfClassA,
options => options.Items["MyConfigEnum"] = valueWhenMappingFromA);
...and as a different value when mapping from ClassB:
var result = _mapper.Map<List<Target>>(instanceOfClassB,
options => options.Items["MyConfigEnum"] = someOtherValue);
Finally, in cases where ParamTwo and ConfigEnum are not required, they can simply be left out - the constructor will work fine and the property will retain its default value (as Enums do) and otherwise be ignored.
I am in the process of setting up nhibernate using fluent nhibernate for a relatively simple setup. Automapping is able to do everything currently fine except for one property on my objects.
I have properties of type MongoDB.Bson.ObjectId. This is simple immutable struct that basically represents a binary ID that can be easily represented in string format as well. These properties cause NHibernate to throw an error saying:
An association from the table PostView refers to an unmapped class:
MongoDB.Bson.ObjectId
This is quite expected of course because I don't expect nhibernate to understand what ObjectId is.
Where I am stuck is that what I want is to be able to tell Nhibernate to map this object type to a string representation in the database. I would like to be able to do this while still using automapping so I don't have to explicitly map all of those objects - what I'd like is to be able to just say "Whenever you find this objecttype use this mapping". I've found mention of NHibernate.UserTypes.IUserType which seems to look like it does what I want but I've found nothing that usefully tells me how to use it.
So to summarise the question:
How can I automatically map a custom data type to a known type for storing in the database (and of course the reverse).
I would prefer not to change my objects to storing the string representation of the object if possible.
You have to write a convention for this type.
Something like this:
public class CustomTypeConvention : IUserTypeConvention
{
public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
criteria.Expect(x => x.Property.PropertyType == typeof(MyType));
}
public void Apply(IPropertyInstance target)
{
target.CustomType(typeof(string));
}
}
And add this convention to mappings:
mapping.Conventions.Add(new CustomTypeConvention());
I expose a complex type through OData. The class is like this:
public class RemoteFile
{
[Key]
public int Id { get; set; }
[Required]
public string Resource { get; set; }
public virtual ICollection<RemoteFile> RelatedFiles { get; set; }
}
And I expose it through OData:
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.ComplexType<RemoteFile>();
Here is what I got when I start the project:
An exception of type 'System.ArgumentException' occurred in System.Web.Http.OData.dll but was not handled in user code
Additional information: The complex type 'RemoteFile' has a reference to itself through the property 'RelatedFiles'. A recursive loop of complex types is not allowed.
If there is a handler for this exception, the program may be safely continued.
Any suggestion is welcomed.
It sounds like it makes more sense for RemoteFile to be an entity type, not a complex type. Entity types can have properties that point to the originating type, which is how you've set up RemoteFile. Your definition of the type also has a key property, which is used for entity types, not complex types. (Think of complex types as a convenient way to group a bunch of scalar properties. Entity types are the first-class types of your system where each instance can be uniquely identified.)
So instead of this:
modelBuilder.ComplexType<RemoteFile>();
Try this:
modelBuilder.EntitySet<RemoteFile>(“RemoteFiles”);
That line will create both the entity type RemoteFile and the entity set RemoteFiles. An entity set is the container for all the instances of an entity type.
So why is recursion allowed for entity types but not complex types? When you ask for an entity, by default the server won't fetch the data of referenced entities. You can explicitly ask for the data of a referenced entity by using $expand in the query, but you can't expand infinitely. On the other hand, complex values will always be included when you ask for their parent. So if you have a circular complex value, you'll create a stack overflow when you try to serialize it.
Do you need to explicitly ignore the navigation property by any chance?
modelBuilder.ComplexType<RemoteFile>().Ignore(x => x.RemoteFile);
Hope that helps :)
I had the same problem. I had a model with more than 100 entities, and I tried to add only two, for make tests.
The solution: ADD ALL ENTITIES to ODataConventionModelBuilder, something like this:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Entity1>("Entity1");
builder.EntitySet<Entity2>("Entity2");
builder.EntitySet<Entity3>("Entity3");
//... and thus for ALL YOUR ENTITIES.
// If you don't want to expose any entity like EntitySet, simply add to builder like EntityType:
builder.EntityType<Entity4>("Entity4");
Even if you do not add entities, the builder scans all types like Complex Types, and relationships fail. Therefore it is necessary to specify that all scanned types are Entities.
If you don't want to expose all like EntitySet, you can add to builder like EntityType, and your client reference will use this class but not will give you access to a EntitySet (CRUD Operations). This Entities only can be used indirectly through relationships of exposed entities.
The error message "The complex type 'RemoteFile' has a reference to itself through the property 'RelatedFiles'. A recursive loop of complex types is not allowed." is due to a limitation of the Web API OData library, specifically the inner workings of the ODataConventionModelBuilder class. This is a blocking issue for many people, tracked here on GitHub.
I have the following class:
public class Foo
{
public int Id { get; set; }
...
public Boo Boo1 { get; set; }
public Boo Boo2 { get; set; }
}
I want to exclude Boo1 and Boo2 properties but I don't want to decorate those properties with PetaPoco.Ignore attribute. I want to have pure POCO objects. Can I execute Ignore command in code or do I have to create query/stored procedure and manually map all fields?
Any help would be greatly appreciated!
Looks like PetaPoco can't be told in any other way that fields/properties should be ignored than by using attributes. You can either Ignore a few members, or if you're not mapping the majority of a class then you can specify explicit column mapping for the class and decorate the ones you DO want mapped. I understand your hesitance to add ORM-specific cruft to a "pure" POCO, but unfortunately that information has to be somewhere, and as PetaPoco doesn't use mapping files (or much of a configuration at all, really), the class is where it goes.
The only thing you could do is create a DTO/DAO that will be what is mapped, then create implicit or explicit operators to convert between the domain class and its DTO. The DTO, then, can simply not have the fields you don't want to include. That keeps both classes POCO (depending on your feelings regarding operator methods), and it just adds a relatively simple step of casting the query result to your domain class.
In my branch here:
https://github.com/schotime/PetaPoco
You can fluently describe your models like I have described here: http://schotime.net/blog/index.php/2011/05/16/fluent-petapoco-external-mappings/ and also use the convention based mapping like here: http://schotime.net/blog/index.php/2012/02/13/petapoco-convention-based-fluent-mapping/
This is a great place for an anonymous type.
In your method for saving foo
public void InsertFoo(Foo f)
{
var db = new Database("connection");
var petaPocoFooObj = new {f.Id}
db.Insert("FooTable", "FooId", petaPocoFooObj);
}
It's just a little more work, although it could be a PITA if your classes are deeply nested.
I've written a class with a single static method that copies property values from one object to another. It doesn't care what type each object is, only that they have identical properties. It does what I need, so I'm not engineering it further, but what improvements would you make?
Here's the code:
public class ShallowCopy
{
public static void Copy<From, To>(From from, To to)
where To : class
where From : class
{
Type toType = to.GetType();
foreach (var propertyInfo in from.GetType().GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance))
{
toType.GetProperty(propertyInfo.Name).SetValue(to, propertyInfo.GetValue(from, null), null);
}
}
}
I'm using it as follows:
EmployeeDTO dto = GetEmployeeDTO();
Employee employee = new Employee();
ShallowCopy.Copy(dto, employee);
Are your DTOs serializable? I would expect so, in which case:
MemberInfo[] sm = FormatterServices.GetSerializableMembers(typeof(From));
object[] data = FormatterServices.GetObjectData(from, sm);
FormatterServices.PopulateObjectMembers(to, sm, data);
But note that I don't really agree with this general approach. I would prefer a strong contract for copying on your DTOs that each DTO implements.
Change your type parameter names to comply with naming conventions, e.g. TFrom and TTo, or TSource and TDest (or TDestination).
Do most of your work in a generic type instead of in just a generic method. That allows you to cache the properties, as well as allowing type inference. Type inference is important on the "TFrom" parameter, as it will allow anonymous types to be used.
You could potentially make it blindingly fast by dynamically generating code to do the property copying and keeping it in a delegate which is valid for the "from" type. Or potentially generate it for every from/to pair, which would mean the actual copying wouldn't need to use reflection at all! (Preparing the code would be a one-time hit per pair of types, but hopefully you wouldn't have too many pairs.)
A new method that created a new instance of To and called the Copy() method before returning might be useful.
Like this:
public static To Create<From, To>(From from)
where To : class, new()
where From : class
{
var to = new To();
Copy(from, to);
return to;
}
Decide what you want to do if passed objects of types that share some properties but not all. Check for the existence of the property in the From object in the To object before trying to set it's value. Do the "right thing" when you come to a property that doesn't exist. If all of the public properties need to be identical, then you will need to check if you've set all of them on the To object and handle the case where you haven't appropriately.
I'd also suggest that you may want to use attributes to decorate the properties that need to be copied and ignore others. This would allow you to go back and forth between the two different objects more easily and continue to maintain some public properties that are derived rather than stored on your business object.