I want to transform two properties of base classes using ConvertUsing, but it is not being called
Base classes
public abstract class BaseDadoMestreViewModel
{
public DateTime UltimaAtualizacao { get; set; }
public bool Excluido { get; set; }
public bool Ativo { get; set; }
}
public abstract class BaseDadoMestre<TEntity> : EntityCrud<TEntity>
where TEntity : class
{
public DateTime UltimaAtualizacao { get; set; }
public string MarcadoEliminacao { get; set; }
public bool Desabilitado { get; set; }
}
Classes
public class CalendarioViewModel: BaseDadoMestreViewModel
{
public DateTime Data { get; set; }
}
public class CalendarioDTO: BaseDadoMestre<CalendarioDTO>
{
public DateTime Data { get; set; }
}
ITypeConverter
public class BaseConverter<TEntity> :
ITypeConverter<BaseDadoMestre<TEntity>, BaseDadoMestreViewModel>,
ITypeConverter<BaseDadoMestreViewModel, BaseDadoMestre<TEntity>>
where TEntity : BaseDadoMestre<TEntity>
{
public BaseDadoMestreViewModel Convert(BaseDadoMestre<TEntity> source, BaseDadoMestreViewModel destination, ResolutionContext context)
{
destination.Excluido = (source.MarcadoEliminacao== "X");
destination.Ativo = !source.Desabilitado;
return destination;
}
public BaseDadoMestre<TEntity> Convert(BaseDadoMestreViewModel source, BaseDadoMestre<TEntity> destination, ResolutionContext context)
{
destination.MarcadoEliminacao = (source.Excluido ? null : "X");
destination.Desabilitado = !source.Ativo;
return destination;
}
}
And finally my map:
CreateMap(typeof(BaseDadoMestre<>), typeof(BaseDadoMestreViewModel)).ConvertUsing(typeof(BaseConverter<>));
CreateMap(typeof(BaseDadoMestreViewModel), typeof(BaseDadoMestre<>)).ConvertUsing(typeof(BaseConverter<>));
CreateMap<CalendarioDTO, CalendarioViewModel>()
When I run the mapping command ConvertUsing is not called.
mapper.Map<CalendarioViewModel>(new CalendarioDTO() { MarcadoEliminacao = "X", Desabilitado = true });
As from Automapper docs you need to either specify the inheritance when creating the mapping for base classes either from derived.
Check this one:
http://docs.automapper.org/en/stable/Mapping-inheritance.html
Related
I have the following structure of EF entities classes:
public abstract class CalendarItem
{
public Guid CalendarItemId { get; set; }
public Guid? ParentCalendarItemId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual CalendarItem ParentCalendarItem { get; set; }
public virtual ICollection<CalendarItem> ChildCalendarItems { get; set; }
}
public class CalendarSlot : CalendarItem
{
public bool IsAvailable { get; set; }
}
public class CalendarSession : CalendarEvent
{
public DateTimeOffset StartDateTime { get; set; }
public DateTimeOffset EndDateTime { get; set; }
}
Mapping is configured as follows:
public class CalendarItemMap
{
public static void Map(ModelBuilder modelBuilder)
{
modelBuilder.Entity<CalendarItem>().ToTable("CalendarItem");
modelBuilder.Entity<CalendarItem>().HasKey(t => t.CalendarItemId);
modelBuilder.Entity<CalendarItem>().HasOne(ci => ci.ParentCalendarItem)
.WithMany(cs => cs.ChildCalendarItems).HasForeignKey(cs => cs.ParentCalendarItemId);
}
}
With DbSets as:
public DbSet<CalendarItem> CalendarItems { get; set; }
public DbSet<CalendarSession> CalendarSessions { get; set; }
public DbSet<CalendarSlot> CalendarSlots { get; set; }
My question is how to properly organize self-reference (tree) structure of the base class with inheritance provided. All types of entities, namely CalendarSlot and CalendarSession should have references to themselves, CalendarItem cannot be created as an instance.
In the database the tree structure is implemented in the CalendarItem table. CalendarSlot/CalendarSession tables have 1-1 relationship with CalendarItem.
The problem is that in my code I have a place with generic method which converts models to contracts for the API:
internal static TContract ToCalendarItem<TContract, TModel>(TModel calendarItemModel)
where TContract : Contract.CalendarItem, new()
where TModel : Model.CalendarItem
{
return new()
{
CalendarItemId = calendarItemModel.CalendarItemId,
Name = calendarItemModel.Name,
Description = calendarItemModel.Description,
ParentCalendarItem = calendarItemModel.ParentCalendarItem != null ? ToCalendarItem<TContract, TModel>(calendarItemModel.ParentCalendarItem) : null
};
}
and in the line
ParentCalendarItem = calendarItemModel.ParentCalendarItem != null ? ToCalendarItem<TContract, TModel>(calendarItemModel.ParentCalendarItem) : null
I have an error "Argument 1: Cannot convert from 'Model.CalendarItem' to TModel".
How can I tell the system that calendarItemModel.ParentCalendarItem should always be TModel (a class derived from Model.CalendarItem)?
What I am doing wrong here?
Thank you in advance.
I have the following class;
public class PricingRuleNumberRange
{
public decimal? FromValue { get; private set; }
public decimal? ToValue { get; private set; }
protected PricingRuleNumberRange() {}
public PricingRuleNumberRange(decimal? fromValue, decimal? toValue)
{
FromValue = fromValue;
ToValue = toValue;
}
...
}
And a model which uses said class;
public class PricingRule
{
public PricingRuleNumberRange LVR { get; private set; }
protected PricingRule() { }
public PricingRule(...)
{
...
}
public void UpdateDetails(PricingRuleNumberRange lvr)
{
LVR = lvr;
}
}
I can add a new PricingRuleNumberRange property to PricingRule and call Add-Migration, it will detect and scaffold the change without issue. However, I now need to add another PricingRuleNumberRange property that is only an int, not a decimal. I thought that converting the PricingRuleNumberRange to a generic class would be acceptable but Add-Migration now drops the LVR property/columns.
This is the new code;
public class PricingRuleNumberRange<T> where T : struct, IComparable<T>
{
public T? FromValue { get; private set; }
public T? ToValue { get; private set; }
protected PricingRuleNumberRange() {}
public PricingRuleNumberRange(T? fromValue, T? toValue)
{
FromValue = fromValue;
ToValue = toValue;
}
...
}
public class PricingRule
{
public PricingRuleNumberRange<decimal> LVR { get; private set; }
public PricingRuleNumberRange<int> NewCol { get; private set; }
protected PricingRule() { }
public PricingRule(...)
{
...
}
public void UpdateDetails(PricingRuleNumberRange<decimal> lvr)
{
LVR = lvr;
}
}
Since I am specifying int/decimal in the property declaration, I thought it would pick it up still, but obviously not. I suspect I might need to do something in the DbContext.OnModelCreating() method or maybe add some attributes to some properties to get it to work?
I'm looking for the best approach of working with different types identically.
I have a web service that goes to specific resource, makes some research and returns an object WebResult, that contains all information about completed operations.
And now I'd like to build a set of different metrics, that will describe all received results. These metrics should provide
different types of data
easy way to collect it
possibility to deserialize it.
Example 1
First I've created separate classes for different metrics
public abstract class AbstractStatistic
{
public string Url { get; set; }
public string ExceptionMessage { get; set; }
public abstract void FillAllMetrics(WebResult result);
}
public class Resource1Statistic : AbstractStatistic
{
public string Title { get; set; }
public string[] Table1_Header { get; set; }
public int Table1_RowCount { get; set; }
public string[] Table2_Header { get; set; }
public int Table2_RowCount { get; set; }
public override void FillAllMetrics(WebResult result)
{
this.Url = result.url;
this.Title = result.data["title"];
this.Table1_Header = result.data["table1.header"].ToObject<string[]>();
//...
}
}
It works, but I'd like to make it in more standard way. One of the reason is that in this approach I have to create separate web form for each metrics.
Example 2
Second working example is universal but redundant: create an abstraction of any datatype
public abstract class AbstractStatistic
{
public string Url { get; set; }
public string Exception { get; set; }
public Dictionary<string, Metric> Metrics { get ;set;}
public abstract void FillAllMetrics(WebResult webResult);
}
public class Metric // Specific class for data
{
public string StringValue { get; set; }
public int? IntegerValue { get; set; }
public string[] ArrayValue { get; set; }
public DateTime? DateTimeValue { get; set; }
}
public class Resource1Statistic : AbstractStatistic
{
public override void FillAllMetrics(WebResult result)
{
this.Metrics.Add("title",
new Metric() { StringValue = result.data["title"].ToString() });
this.Metrics.Add("Table1 Header",
new Metric() { ArrayValue = result.data["table1.header"].ToObject<string[]>() });
//...
}
It works, but I'm sure there is more elegant solution. I don't like to take all these null values in json.
Examples 3
Generic solution (regarding to Adwaenyth)
public abstract class AbstractStatistic
{
public string Url { get; set; }
public string Exception { get; set; }
public List<AbstractMetric> Metrics { get ;set;}
public abstract void FillAllMetrics(WebResult webResult);
}
public abstract class AbstractMetric{}
public class Metric<T> : AbstractMetric
{
public string Name { get; set; }
public T Value { get; set; }
public string Type { get; private set; }
public Metric()
{
this.Type = typeof(T).ToString();
}
}
public class Resource1Statistic : AbstractStatistic
{
public override void FillAllMetrics(WebResult result)
{
this.Metrics.Add(new Metric<string>()
{ Name = "title",
Value = result.data["title"].ToString() });
this.Metrics.Add(new Metric<string[]>()
{ Name = "Table1 Header",
Value = result.data["table1.header"].ToObject<string[]>() });
//...
}
This solution looks nice, but I have to write custom deserializer.
What do you think, is there some good pattern that fits to my task? Or what's the best approach?
I have these interfaces:
public interface IParameter
{
string Name { get; }
object UntypedValue { get; set; }
}
public interface IValidationPolicy<T>
{
bool Validate(T toValidate);
T Default();
}
A parameter base class
[Serializable]
public abstract class ParameterBase : IParameter
{
public abstract string Name { get; protected set; }
public abstract object UntypedValue { get; set; }
}
A parameter concrete class (I have more but them are quite similar):
public class Parameter<T, V> : ParameterBase where V : IValidationPolicy<T>
{
[XmlAttribute("Name")]
public override string Name { get; protected set; }
[XmlIgnore]
protected V validation_policy_;
[XmlElement("AnyValidation", Type = typeof(AnyValidation<>))]
[XmlElement("MultiOptionsValidation", Type = typeof(MultiOptionsValidation<>))]
[XmlElement("RangeValidation", Type = typeof(RangeValidation<>))]
[XmlElement("TextValidation", Type = typeof(TextValidation))]
public V Validation
{
get
{
return validation_policy_;
}
}
[XmlIgnore]
protected T value_;
[XmlElement("Value")]
public T Value
{
get
{
return value_;
}
set
{
if (validation_policy_.Validate(value))
{
value_ = value;
}
}
}
[XmlIgnore]
public object UntypedValue
{
get
{
return Value;
}
set
{
throw new NotImplementedException();
}
}
}
And an XMLParameter class:
public class XMLParameter : INotifyPropertyChanged
{
public string Description { get; set; }
public int PasswordLevel { get; set; }
public bool Enabled { get; set; }
public ParameterBase Parameter { get; set; }
}
How can I serialize and deserialize a list of XMLParameters?
In particular I have problem on serializing the IParameter objects.
Since the interface is not serializable as first attempt I created a base abstract class ParameterBase and derive the Parameter from it.
But when I try to serialize it in a test method:
var validation = new RangeValidation<int>() { MinValue = 1, MaxValue = 6 };
var parameter = new Parameter<int, RangeValidation<int>>();
parameter.Initialize("NumberOfTrays", validation);
parameter.Value = 6;
XElement par = validation.ToXElement<Parameter<int, RangeValidation<int>>>();
I got an exception: Error at reflection of type 'ConfigurableLibray.Parameter'2[System.Int32,ConfigurableLibray.RangeValidation'1[System.Int32]]'
The inner exception says that ConfigurableLibray.Parameter'2[T,V] is not supported
What am I doing wrong?
Thanks in advance for any suggestion!
I solved implementing manually the serialization and deserialization of the classes using reflection.
I have a business model which consists of a parent/child relationship (Identifier/IdentifierValue) and also some snapshot classes which look the same (IdentifierSnapshot/IdentifierValueSnapshot).
I am trying to create an extension method which will work on an enumeration of either Identifier or IdentifierSnapshot, but I just can't work out what to put in the extension method where I have inserted the XXX placeholder.
//Interfaces
public interface IIdentifier<TIdentifierValue>
where TIdentifierValue : IIdentifierValue
{
string Code { get; }
IEnumerable<TIdentifierValue> GetValues();
}
public interface IIdentifierValue
{
string Code { get; }
string Value { get; }
}
//Main classes
public class Identifier : IIdentifier<IdentifierValue>
{
public string Code { get; set; }
public IEnumerable<IdentifierValue> GetValues();
}
public class IdentifierValue : IIdentifierValue
{
public string Code { get; set; }
public string Value { get; set; }
}
//Snapshots
public class IdentifierSnapshot : IIdentifier<IdentifierValueSnapshot>
{
public string Code { get; set; }
public IEnumerable<IdentifierValueSnapshot> GetValues();
}
public class IdentifierValueSnapshot : IIdentifierValue
{
public string Code { get; set; }
public string Value { get; set; }
}
public static IdentifierExtensions
{
public static IEnumerable<XXX> ByCode<XXX>(this IEnumerable<XXX> instance, string code)
{
return instance.Where(x => string.Compare(code, x.Code, true) == 0);
}
}
I think this would do it:
public static IEnumerable<T> ByCode<T,Z>(this IEnumerable<T> instance, string code)
where T:IIdentifier<Z>
where Z:IIdentifierValue