Automapper not mapping nullable value correctly - automapper

Automapper is incorrectly mapping null value of nullable type to default value of not-nullable type
public class Product
{
public Guid? ExternalId { get; set; }
}
public class ProductEntity
{
public Guid? ExternalId { get; set; }
}
In case ProductEntity has null value for ExternalId, mapping to product results in Guid.Empty
Is this intended behaviour? We have no special mapping.
public class ProductProfile : Profile
{
public ProductProfile()
{
CreateMap<ProductEntity, Product>();
CreateMap<Product, ProductEntity>();
}
}
We are using Automapper 7.0.1

Related

PXDBScalar SOOrderKvExt attribute bool

I'm trying to use PXDBScalar to bring in a boolean attribute from the Sales Order user defined fields tab to the Shipment screen.
I found another stack overflow post that helped with the creation of the SOOrderKvExt DAC, and I am able to retrieve the value of the valueNumeric (decimal) field via my PXDBScalar attribute, but I cannot find a way to convert the value to a bool so it properly displays as a checkbox on the screen. I tried setting the data type for my unbound field to bool, but got a data type conversion error. I also tried leaving the field as a decimal and just changing the control type on the screen, but it always displays as checked regardless of the value. Any idea how I can convert the decimal value to a bool in the PXDBScalar attribute or another solution?
Code snippets provided below.
SOOrderKvExt
[PXCacheName("SO Order Attributes")]
[Serializable]
public class SOOrderKvExt : IBqlTable
{
public abstract class recordID : BqlGuid.Field<recordID> { }
[PXDBGuid(IsKey = true)]
public Guid? RecordID { get; set; }
public abstract class fieldName : BqlString.Field<fieldName> { }
[PXDBString(50,IsKey = true)]
[PXUIField(DisplayName ="Name")]
public string FieldName { get; set; }
public abstract class valueNumeric : BqlDecimal.Field<valueNumeric> { }
[PXDBDecimal(8)]
[PXUIField(DisplayName = "Value Numeric")]
public decimal? ValueNumeric { get; set; }
public abstract class valueDate : BqlDateTime.Field<valueDate> { }
[PXDBDate]
[PXUIField(DisplayName = "Value Date")]
public DateTime? ValueDate { get; set; }
public abstract class valueString : BqlString.Field<valueString> { }
[PXDBString(256)]
[PXUIField(DisplayName = "Value String")]
public string ValueString { get; set; }
public abstract class valueText : BqlString.Field<valueText> { }
[PXDBString]
[PXUIField(DisplayName = "Value Text")]
public string ValueText { get; set; }
}
}
PXDBScalar
#region UsrSOBlindShip
[PXDecimal(8)]
[PXUIField(DisplayName="SO Blind Ship", IsReadOnly=true)]
[PXDBScalar(typeof(Search2<SOOrderKvExt.valueNumeric,
LeftJoin<SOOrder, On<SOOrder.noteID, Equal<SOOrderKvExt.recordID>>,
LeftJoin<SOShipLine, On<SOShipLine.origOrderNbr, Equal<SOOrder.orderNbr>>>>,
Where<SOShipLine.shipmentNbr, Equal<SOShipment.shipmentNbr>>>))]
public virtual decimal? UsrSOBlindShip{ get; set; }
public abstract class usrSOBlindShip: PX.Data.BQL.BqlDecimal.Field<usrSOBlindShip> { }
#endregion
Thanks
Scott
I would add a boolean calculated field. Similar to this :
public class SOLineExt : PXCacheExtension<PX.Objects.SO.SOLine>
{
#region UsrIsZero
[PXBool]
[PXUIField(DisplayName="Is Zero")]
[PXFormula(typeof(Switch< Case<Where<SOLine.orderQty, Greater<decimal0>>, False>, True >))]
public virtual bool? UsrIsZero { get; set; }
public abstract class usrIsZero : PX.Data.BQL.BqlBool.Field<usrIsZero> { }
#endregion
}

Automapper Base type, dervied type DTO Mapping

I have the following classes:
public class Entity
{
}
public class Company : Entity
{
}
public class Person : Entity
{
}
public class SomeOther
{
public Entity A { get; set; }
}
And the following DTOs:
public class EntityDTO
{
}
public class SomeOtherDTO
{
public EntityDTO A { get; set; }
}
And the following Mappings:
CreateMap<Person, EntityDTO>();
CreateMap<Company, EntityDTO>();
Is there any way of doing CreateMap<Entity, EntityDTO>() and tell Automapper to use the relevant mapping based on the derived type?

Azure Table Storage - TableEntity map column with a different name

I am using Azure Table Storage as my data sink for my Semantic Logging Application Block. When I call a log to be written by my custom EventSource, I get columns similar to the ff.:
EventId
Payload_username
Opcode
I can obtain these columns by creating a TableEntity class that matches the column names exactly (except for EventId, for some reason):
public class ReportLogEntity : TableEntity
{
public string EventId { get; set; }
public string Payload_username { get; set; }
public string Opcode { get; set; }
}
However, I would like to store the data in these columns in differently named properties in my TableEntity:
public class ReportLogEntity : TableEntity
{
public string Id { get; set; } // maps to "EventId"
public string Username { get; set; } // maps to "Payload_username"
public string Operation { get; set; } // maps to "Opcode"
}
Is there a mapper/attribute I can make use of to allow myself to have the column name different from the TableEntity property name?
You can override ReadEntity and WriteEntity methods of interface ITableEntity to customize your own property names.
public class ReportLogEntity : TableEntity
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public string Id { get; set; } // maps to "EventId"
public string Username { get; set; } // maps to "Payload_username"
public string Operation { get; set; } // maps to "Opcode"
public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
{
this.PartitionKey = properties["PartitionKey"].StringValue;
this.RowKey = properties["RowKey"].StringValue;
this.Id = properties["EventId"].StringValue;
this.Username = properties["Payload_username"].StringValue;
this.Operation = properties["Opcode"].StringValue;
}
public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
{
var properties = new Dictionary<string, EntityProperty>();
properties.Add("PartitionKey", new EntityProperty(this.PartitionKey));
properties.Add("RowKey", new EntityProperty(this.RowKey));
properties.Add("EventId", new EntityProperty(this.Id));
properties.Add("Payload_username", new EntityProperty(this.Username));
properties.Add("Opcode", new EntityProperty(this.Operation));
return properties;
}
}

How do I create a navigation property that can navigate to more than one entity type?

I have the following in my domain classes ( simplified )
public enum JobType
{
SalesOrder = 1,
StockOrder = 2
}
public class SalesOrder : LoggedEntity
{
public string Name { get; set; } // and other fields
}
public class StockOrder : LoggedEntity
{
public string Name { get; set; } // and other fields
}
public class Job : LoggedEntity
{
public int JobType { get; set; } // jobtype enum
public virtual LoggedEntity LinkedEntity { get; set; }
}
My context is as follows;
public class Context : DbContext
{
public DbSet<Job> Jobs { get; set; }
public DbSet<StockOrder> StockOrders { get; set; }
public DbSet<SalesOrder> SalesOrders { get; set; }
}
When I run the migration i get the error described [here][1] So using an abstract entity appears not to work.
My question was, how do I create a navigation property that can navigate to more than one entity type?
If JobType = SalesOrder then I want to navigate to sales order, if JobType = StockOrder then I want to navigate to stock order.
I wanted to use a Table Per Heirarchy Strategy [see TPH here][2]
The trick is to keep EF oblivious of the LoggedEntity class. Remodel your entities according to this example:
public enum JobType
{
SalesOrder = 1,
StockOrder = 2
}
public abstract class LoggedEntity
{
public int Id { get; set; }
public string Name { get; set; } // and other fields
}
public abstract class BaseOrder : LoggedEntity // New base class for orders!!
{ }
public class SalesOrder : BaseOrder
{ }
public class StockOrder : BaseOrder
{ }
public class Job : LoggedEntity
{
public JobType JobType { get; set; } // jobtype enum
public virtual BaseOrder Order { get; set; }
}
public class Tph2Context : DbContext
{
public DbSet<Job> Jobs { get; set; }
public DbSet<BaseOrder> Orders { get; set; }
}
You will see that the migration creates two tables, Jobs and BaseOrders (name to be improved). Job now has a property Order that can either be a SalesOrder or a StockOrder.
You can query specific Order types by
contex.Orders.OfType<StockOrder>()
And you will notice that EF doesn't know LoggedEntity, because
context.Set<LoggedEntity>()
will throw an exception
The entity type LoggedEntity is not part of the model for the current context.
how do I create a navigation property that can navigate
to more than one entity type?
You cannot do so. atleast not now. navigational properties are way of describing relationship between entities. at most, they represent, some sort of sql relationship. so you cannot alter or define such a relationship on the fly. you have to define it before hand.
Now in order to do that, you have to define separate navigational property for your separate conditions i.e.
public class Job : LoggedEntity
{
public int JobTypeSales { get; set; }
public int JobTypeStock { get; set; }
public virtual SalesOrder SalesOrder { get; set; }
public virtual StockOrder StockOrder { get; set; }
}
and then link them in configuration in modelbuilder through fluent API.
HasRequired(s => s.SalesOrder)
.WithMany()
.HasForeignKey(s => s.JobTypeSales).WillCascadeOnDelete(true);
HasRequired(s => s.StockOrder)
.WithMany()
.HasForeignKey(s => s.JobTypeStock).WillCascadeOnDelete(true);
and
as for your error "Sequence Contains No Elements"
this error comes, when the Linq query that you specified, is using either .First() or .Single(), or .ToList() and query returned no data.
so to avoid it use, .FirstOrDefault() or SingleOrDefault().
obviously with proper null check.

Type does not have a default constructor automapper

I have a problem:
public class TDocumentation
{
public XmlElement Summary { get; set; }
public XmlElement LongDescription { get; set; }
public XmlAttribute[] AnyAttr { get; set; }
}
...and:
public class ProxieTDocumentation
{
public XmlElement Summary { get; set; }
......
}
Mapper.CreateMap<Proxies.TDocumentation, TDocumentation>()
...throws:
----> System.ArgumentException : Type "System.Xml.XmlElement" does not have a default constructor automapper
How I can make a mapping on another?
I resolve thie promleb:
Mapper.CreateMap<XmlElement, XmlElement>().ConvertUsing(item => item != null ? item.Clone() as XmlElement : null);

Resources