MongoDB .NET: Mapping inherited generic property - c#

I have a generic class Parameter with a generic property Value:
abstract class Parameter<T> {
public T Value { get; set; }
}
StringParameter class inherits the Parameter class:
class StringParameter : Parameter<string> {
//...
}
Is it possible to properly map the StringParameter class so that it contains the generic Value property?
When trying to map the StringParameter class with the code below (and various other approaches) the best I could do is get an exception with the message: "The memberInfo argument must be for class StringParameter, but was for class Parameter`1."
BsonClassMap.RegisterClassMap<StringParameter>(cm => {
cm.AutoMap();
cm.MapMember(typeof(StringParameter).GetRuntimeProperty("Value"));
});

Mapping the Parameter class with the specified type parameter for every subclass that inherits it and then automapping each subclass seems to have done the trick.
BsonClassMap.RegisterClassMap<Parameter<string>>(cm => {
cm.AutoMap();
cm.MapProperty("Value");
});
BsonClassMap.RegisterClassMap<Parameter<DateTime>>(cm => {
cm.AutoMap();
cm.MapProperty("Value");
});
BsonClassMap.RegisterClassMap<Parameter<int>>(cm => {
cm.AutoMap();
cm.MapProperty("Value");
});
BsonClassMap.RegisterClassMap<Parameter<decimal>>(cm => {
cm.AutoMap();
cm.MapProperty("Value");
});
BsonClassMap.RegisterClassMap<StringParameter>();
BsonClassMap.RegisterClassMap<DateParameter>();
BsonClassMap.RegisterClassMap<IntegerParameter>();
BsonClassMap.RegisterClassMap<DecimalParameter>();
Note that this maps all the Parameter classes into a single collection with appropriate discriminators.

Related

Automapper: validation exception ignoring destination property

I have troubles trying to ignore a destination property
Source class:
public class ClassDto
{
public int Id { get; set; }
}
Destination class:
public class ClassModel
{
public int Id { get; set; }
public IList<string> ListString { get; set; }
}
Example:
public class Program
{
static void Main(string[] args)
{
var dto = new ClassDto { Id = 1 };
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ClassDto, ClassModel>().
ForMember(i => i.ListString, opt => opt.DoNotUseDestinationValue());
});
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
var model = mapper.Map<ClassDto, ClassModel>(dto);
}
}
Unfortunately config.AssertConfigurationIsValid(); rises an exception:
$exception {"\nUnmapped members were found. Review the types and members below.\nAdd a custom mapping expression, ignore, add a custom
resolver, or modify the source/destination type\nFor no matching
constructor, add a no-arg ctor, add optional arguments, or map all of
the constructor
parameters\n===================================================\r\nClassDto
-> ClassModel (Destination member list)\r\nAutoMapperFoo.ClassDto -> AutoMapperFoo.ClassModel (Destination member list)\r\n\r\nUnmapped
properties:\r\nListString\r\n"} AutoMapper.AutoMapperConfigurationException
I can't undesrtand why, I explicit to ignore ListString by DoNotUseDestinationValue
Thanks in advance
By default, AutoMapper tries to map all the properties from the source
type to the destination type when both source and destination type
property names are the same. If you want some of the properties not to map
with the destination type property then you need to use the AutoMapper
Ignore Property in C#. Learn more AutoMapper Ignore Property in C#
Automapper gives the property Ignore which tells the mapper to not
take the value of a property from the source class. Ignore not only
ignore the mapping for the property, but also ignore the mapping of
all inner properties. It means that if the property is not a primitive
type, but another class, that if you are using Ignore, this class
properties won't be mapped. So, A.B.C would be A.Null.
So try using this:
.ForMember(x => x.ListString, opt => opt.Ignore())

How to map an ICollection<T> to Class derived from List<T>

I am setting up a mapping between my models and my view models and I'm trying to map from an ICollection to class that derives from List
I have tried to make a mapping between my ListItemClassVM and ICollection but get an error 'Argument types do not match'
Option one mapping works with this:
public class ParentVM
{
public List<ListItemClass> ListItemClasses { get; set; }
}
Option two mapping not working:
public class ParentVM
{
public ListItemClassVM ListItemClasses { get; set; }
}
public ListItemClassVM : List<ListItemClass>
{
}
Mapping Setup:
public ModelClass_ParentVM_Profile()
{
CreateMap<ModelClass, ParentVM>()
.ForMember(d => d.ListItemClasses, o => o.MapFrom(i => i.ModelCollection))
;
CreateMap<ParentVM, ModelClass>()
;
}
trying to setup the mapping so option two will map.
I think that there are more way to reach the solution, but you can't escape from a manual transposition from ICollection< ListItemClass > to ListItemClassVM.
The simplier way maybe is to add to your ListItemClassVM a constructor that accepts an ICollection< ListItemClass > and initialize itself with the elements in ICollection, then you could do something like:
CreateMap<ModelClass, ParentVM>()
.ForMember(d => d.ListItemClasses, o => o.MapFrom(i =>new ListItemClassVM (i.ModelCollection)))
;

How to configure a mapping of collection types with AutoMapper?

For example, I've implemented two classes like these:
public class A
{
public List<C> Items { get; set; }
}
public class B
{
public IImmutableList<C> Items { get; set; }
}
public class C
{
}
When I try to map A to B and vice versa, I get an exception because List<string> cannot be converted to IImmutable<string>.
Probably I could provide a mapping for A<->B, but since it'll be a very common pattern in my solution, I'd like to avoid to manually mapping each class that may fall into the same case.
Is there anyway I can generalize the whole mapping using generic type definitions from a collection type to another collection type?
This is what I want to avoid
mapperConfig.CreateMap<A, B>()
.ForMember(a => a.Items, opts => opts.Ignore())
.AfterMap
(
(source, target) =>
{
target.Items = source.Items.ToImmutableList();
}
);

C# MongoDB set different Id representation for derived classes

it's possible to change representation of inherited Id field from BsonType.ObjectId to BsonType.String?
public class BaseClass
{
public string Id { get; set; }
}
public class MyClass : BaseClass
{
}
I tried this approach, but it doesn't work.
BsonClassMap.RegisterClassMap<BaseClass>(cm =>
{
cm.AutoMap();
var id = cm.GetMemberMap(c => c.Id);
cm.SetIdMember(id);
cm.IdMemberMap.SetRepresentation(BsonType.ObjectId);
});
BsonClassMap.RegisterClassMap<MyClass>(cm =>
{
cm.AutoMap();
var idMember = cm.IdMemberMap; // idMember is null
idMember.SetRepresentation(BsonType.String);
});
Thanks a lot.
No, this is not possible. Derived classes cannot change the representation of fields in their base classes. Derived classes do of course have full control over how they want their fields to be serialized.

Don't map property in SubClass

Is it possible to tell Fluent NHibernate not to map a property in a SubClassMap which is defined in it's parent's ClassMap? So:
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
this.Map(x => x.Id);
this.HasManyToMany(x => x.Somethings)
.Table("ParentSomethings")
.ParentKeyColumn("ParentId")
.ChildKeyColumn("SomethingId");
this.DiscriminateSubClassesOn("Foo");
}
}
public class ChildMap : SubclassMap<Child> // with Child : Parent
{
this.DiscriminatorValue("Child");
this.DontMap(x => x.Somethings); // fictional method
}
If you need to do this, your map are wrong, you need to create a ClassMap to Parent, and don't map this property "something", and create two differents mappings for children, one that contains "something" property and one that does not contain.

Categories