Don't map property in SubClass - c#

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.

Related

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)))
;

Automapper : how to eleminate repetitive mapping?

I have following structure for tables. The two tables have a lot of common properties over 20 im just listing a two. Also I have 10 tables similar to this. This is how the tables are in the database. There is over 10 concrete tables with similar properties and are not connected to each other in any way. I am using POCO generator to generate the classes from my database.
public class A
{
public string name {get;set;}
public string address {get;set;}
public string AId {get;set;}
}
public class B
{
public string name {get;set;}
public string address {get;set;}
public string BId {get;set;}
}
I have following viewModels:
public class BaseViewModel
{
public string Fullname {get;set;}
public string Fulladdress {get;set;}
}
public class AviewModel : BaseViewModel
{
public string AId {get;set;}
}
public class BViewModel : BaseViewModel
{
public string BId {get;set;}
}
when I create mapping i have to repeat all this for each viewModel that I have created.
config.CreateMap<A, AviewModel>()
.ForMember(dest => Fulladdress, opt => opt.MapFrom(src =>.address))
.ForMember(dest => Fullname, opt => opt.MapFrom(src =>.name)).ReverseMap();
config.CreateMap<B, BviewModel>()
.ForMember(dest => Fulladdress, opt => opt.MapFrom(src =>.address))
.ForMember(dest => Fullname, opt => opt.MapFrom(src =>.name)).ReverseMap();
Is it possible to reduce the repetitive mappings that I might potentially have to do ?
You can move the common mapping code to a helper generic method. You will constrain the TDestination type to be a class derived from BaseViewModel, thus allowing to access the destination members in ForMember method. And for source mapping you will use the MapFrom overload accepting string property name:
public static class CommonMappings
{
public static IMappingExpression<TSource, TDestination> MapToBaseViewModel<TSource, TDestination>(this IMappingExpression<TSource, TDestination> map)
where TDestination : BaseViewModel
{
return map
.ForMember(dest => dest.Fulladdress, opt => opt.MapFrom("address"))
.ForMember(dest => dest.Fullname, opt => opt.MapFrom("name"));
}
}
Then you can use it like this:
config.CreateMap<A, AViewModel>()
.MapToBaseViewModel()
// ... specific mappings
.ReverseMap();
config.CreateMap<B, BViewModel>()
.MapToBaseViewModel()
// ... specific mappings
.ReverseMap();
Update: It turns out that automatic reverse mapping in the latest at this time AutoMapper 6.1.1 works for the lambda overload of MapFrom, but not for the string overload (in AutoMapper 5 it doesn't work at all). So until it gets fixed, you can use the following MapFrom(string) replacement:
public static class AMExtensions
{
public static void From<TSource, TDestination, TMember>(this IMemberConfigurationExpression<TSource, TDestination, TMember> opt, string name)
{
var parameter = Expression.Parameter(typeof(TSource), "src");
var body = Expression.PropertyOrField(parameter, name);
var selector = Expression.Lambda(body, parameter);
opt.MapFrom((dynamic)selector);
}
}
Which means you'll need to replace MapFrom calls in the original solution with From, because we can't give the extension method the same name since it has less priority than the concrete interface method.
Probably too much effort compared to base class approach. But useful in case you can't control the design of the entity classes.
You need a base class for the source classes. You create a map between the base source class and the destination class. You include that map in the map for the derived classes. That would allow you to reuse the configuration. The docs. For simple cases you can use As instead of Include.
You set an attribute on properties on your models.
This contains the name of the property it maps from on a source object.
Then you make a generic method that accepts the target object and source object, that finds the customattribute on the property where the attribute was set, and the property on the target object (or vice versa) and then sets the value.
You can even handle nested objects by asking if its a class property or not.

MongoDB .NET: Mapping inherited generic property

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.

Override resolved property type with AutoMapper

With AutoMapper, can I override the resolved type for a property? For example, given these classes:
public class Parent
{
public Child Value { get; set; }
}
public class Child { ... }
public class DerivedChild : Child { ... }
Can I configure AutoMapper to automap the Child Value property with a DerivedChild instance? The hypothetical mapping would look something like this:
map.CreateMap<ChildEntity, DerivedChild>();
map.CreateMap<ParentEntity, Parent>()
.ForMember(p => p.Value, p => p.UseDestinationType<DerivedChild>());
(I'm projecting from LINQ entities. The closest I could find is using a custom type converter, but it looks like I'd need to override the entire mapping.)
Here is one way to do it:
map.CreateMap<ChildEntity, DerivedChild>();
map.CreateMap<ParentEntity, Parent>()
.ForMember(
x => x.Value,
opt => opt.ResolveUsing(
rr => map.Map<DerivedChild>(((ParentEntity)rr.Context.SourceValue).Value)));
ResolveUsing allows to specify custom logic for mapping the value.
The custom logic that is used here is actually calling map.Map to map to DerivedChild.
You may re-assign new object manually after mapping:
Mapper.CreateMap<ParentEntity, Parent>()
.AfterMap((src, dest) => dest.Value = new DerivedChild(){...});
or even re-map it:
.AfterMap((src, dest) => dest.Value = Mapper.Map<DerivedChild>(dest.Value));

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.

Categories