I'm trying to read a flat file and do some processes. To do that I've defined a mapper. That mapper will assign the values for each property. In the document, the date will be represented with yyMMdd format and it can have "" or 000000 as a null value. That mean, if the date is 6 zeros or 6 blank spaces, the output should be null. I tried to do this by defining a NullFormater. But didn't work.
This is what I've tried:
============================
public class Test : DocumentRecordBase
{
public string StorageOrganisation { get; set; }
public Guid? StorageOrganisationId { get; set; }
public string StorageDescription { get; set; }
public DateTime? PaymentDueDate { get; set; }
public decimal? DiscountRate { get; set; }
public int? MaximumDaysDiscount { get; set; }
public DateTime? DateStorageChargeCommences { get; set; }
public decimal? StorageChargePerBalePerDay { get; set; }
public decimal? PenaltyInterestRate { get; set; }
public DateTime? LotAvailableDate { get; set; }
public decimal? PostSaleRechargeRebate { get; set; }
public Test() : base()
{
}
public override T GetDocumentRecord<T>()
{
if (typeof(T) == typeof(Test))
{
return this as T;
}
return null;
}
public static IFixedLengthTypeMapper<Test> GetMapper()
{
var mapper = FixedLengthTypeMapper.Define<Test>();
mapper.Property(r => r.RecordType, 2);
mapper.Property(r => r.RecordSubType, 1);
mapper.Property(r => r.PaymentDueDate, 6)
.ColumnName("PaymentDueDate")
.InputFormat("yyMMdd")
.NullFormatter(NullFormatter.ForValue("000000")); // if the read value is "000000" or " " then should pass as null
mapper.CustomMapping(new RecordNumberColumn("RecordNumber")
{
IncludeSchema = true,
IncludeSkippedRecords = true
}, 0).WithReader(r => r.RecordNumber);
return mapper;
}
public static bool GetMapperPredicate(string x)
{
return x.StartsWith("11A");
}
}
According to the definition of NullFormatter, (found here), you can only assign 1 fixed value. "If it is a fixed value, you can use the NullFormatter.ForValue method."
NullFormatter = NullFormatter.ForValue("NULL")
If you use "000000", then it should convert 000000 to null otherwise, spaces will be considered actual values. Any number of 0s != 6 will result in non-null value as well.
Also, please define what you mean by "But didn't work". Please provide details and errors for elaboration
Related
This question already has answers here:
Automatic conversion of numbers to bools - migrating from Newtonsoft to System.Text.Json
(1 answer)
System.Text.Json: Deserialize JSON with automatic casting
(7 answers)
Closed 12 months ago.
Given the following json document, what would be the best way to convert it to a valid object using a Converter? The trick comes in that the source json has the value property as string where it should be serialized as a float?
{
"metric": "metric",
"operator": "GREATER_THAN",
"value": "1",
"status": "OK",
"errorThreshold": "1"
}
The resulting c# object:
public class Condition
{
[JsonPropertyName("errorThreshold")]
public string ErrorThreshold { get; set; }
[JsonPropertyName("metric")]
public string Metric { get; set; }
[JsonPropertyName("operator")]
public string Operator { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("value")]
public double? Value { get; set; }
}
I'm toying here with a converter that makes use of reflection to do this, but this seems like using a shotgun to kill a earthworm.
Are there any more commonly established/recommended ways in doing this?
well one way is
public class Condition
{
[JsonPropertyName("errorThreshold")]
public string ErrorThreshold { get; set; }
[JsonPropertyName("metric")]
public string Metric { get; set; }
[JsonPropertyName("operator")]
public string Operator { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("value")]
public string Value { get; set{
Double.TryParse(value, out ValNumeric);
}; }
public double ValNumeric = 0;
}
I would never use Text.Json for something except "Hello World", but you can do it this way, you do not need any extra properties
var conditionParsed = JsonDocument.Parse(json);
var condition =conditionParsed.Deserialize<Condition>();
if (double.TryParse( conditionParsed.RootElement.GetProperty("value").GetString(),out double value))
condition.Value=value;
and change value property attribute
[System.Text.Json.Serialization.JsonIgnore]
public double? Value { get; set; }
or you can like this too
[JsonPropertyName("value")]
public string _value { get; set; }
[System.Text.Json.Serialization.JsonIgnore]
public double? Value
{
get { return double.TryParse(_value, out double val)? val:null; }
set { _value = value != null ? value.ToString(): null; }
}
but in this case you will need an extra public propery
I need to map a nullable int to a nullable int via autompper
This my class Incident:
public class Incident : Evenement
{
public Incident()
: base(-1, Global.EvenementType.Incidents, DateTime.MinValue)
{
}
public Incident(int id, DateTime date, string libelle, int formulaireId, string societe, string userName)
: base(id, (int)Global.EvenementType.Incidents, date, libelle, "", "", societe)
{
ContratId = formulaireId;
Contrat = null;
UserName = userName;
}
public Incident(int id, DateTime date, string libelle, string societe, string userName)
: base(id, (int)Global.EvenementType.Incidents, date, libelle, "", "", societe)
{
ContratId = null;
Contrat = null;
UserName = userName;
}
[DataMember]
public int? ContratId { get; set; }
[DataMember]
public Contrat Contrat { get; set; }
[DataMember]
public string UserName { get; set; }
[DataMember]
public bool IsGeneral
and this is my class INCIDENT
public partial class INCIDENT : EVENEMENT
{
public Nullable<int> FORMULAIRE_ID { get; set; }
public virtual FORMULAIRE FORMULAIRE { get; set; }
public string USERNAME { get; set; }
}
When I'm doing a mapping and i have a null in contratId dans incident, it's automotically converted to 0 in FORMULAIRE_ID in class INCIDENT
This my bindings
Mapper.CreateMap<Incident, INCIDENT>()
.ForMember(degivreuse => degivreuse.FORMULAIRE_ID, expression => expression.MapFrom(degivreuse => degivreuse.ContratId))
.ForMember(degivreuse => degivreuse.FORMULAIRE, expression => expression.Ignore());
And in the PJ the problem:
Do you have any idea why i don't obtain a null value please?
Regards
I'm not seeing any issues with the way Automapper handles int?. Here's a quick sample that works fine:
public class Src1
{
public string Name { get; set; }
public int? Age { get; set; }
}
public class Dest1
{
public string Name { get; set; }
public Nullable<int> Age { get; set; }
}
Mapper.CreateMap<Src1, Dest1>();
Mapper.AssertConfigurationIsValid();
var s = new Src1 {Name = "aaa", Age = null};
var d = Mapper.Map<Src1, Dest1>(s);
In the sample above, d.Age is null. Can you provide some sample code that reproduces the issue you're seeing?
Today I've stumbled upon the same problem with AutoMapper 10.1.1.
I tried to map my custom class to MarginSettings class in DinkToPdf library.
The MarginSettings class had 2 constructors:
public class MarginSettings
{
public Unit Unit { get; set; }
public double? Top { get; set; }
public double? Bottom { get; set; }
public double? Left { get; set; }
public double? Right { get; set; }
public MarginSettings()
{
Unit = Unit.Millimeters;
}
public MarginSettings(double top, double right, double bottom, double left) : this()
{
Top = top;
Bottom = bottom;
Left = left;
Right = right;
}
// the rest of class..
}
It looks like for some reason AutoMapper is calling a constructor with parameters in MarginSettings class when it tries to map my custom class to it. This way, the default double value (0) is set to double? properties in this constructor.
Here is the code demonstrating this problem:
class SourceClass
{
public double? Top { get; set; }
public double? Bottom { get; set; }
public double? Left { get; set; }
public double? Right { get; set; }
}
class ClassWithoutCtor
{
public double? Top { get; set; }
public double? Bottom { get; set; }
public double? Left { get; set; }
public double? Right { get; set; }
}
// The class similar to one in DinkToPdf library
class ClassWithCtor
{
public string Message1 { get; set; }
public string Message2 { get; set; }
public double? Top { get; set; }
public double? Bottom { get; set; }
public double? Left { get; set; }
public double? Right { get; set; }
public ClassWithCtor() => this.Message1 = "in default ctor";
public ClassWithCtor(double top, double right, double bottom, double left)
: this()
{
this.Top = new double?(top);
this.Bottom = new double?(bottom);
this.Left = new double?(left);
this.Right = new double?(right);
Message2 = "in ctor with parameters";
}
}
class AutoMapperTest
{
public void TryMapZeros()
{
var source = new SourceClass
{
Top = 5,
Bottom = 5
};
var mapConfiguration = new MapperConfiguration(
cfg =>
{
cfg.CreateMap<SourceClass, ClassWithoutCtor>();
cfg.CreateMap<SourceClass, ClassWithCtor>();
}
);
var mapper = mapConfiguration.CreateMapper();
var margin1 = mapper.Map<SourceClass, ClassWithoutCtor>(source);
var margin2 = mapper.Map<SourceClass, ClassWithCtor>(source);
}
}
The mapped objects look this way after the code execution:
margin1
{PdfGeneratorTest.ClassWithoutCtor}
Bottom: 5
Left: null
Right: null
Top: 5
margin2
{PdfGeneratorTest.ClassWithCtor}
Bottom: 5
Left: 0
Message1: "in default ctor"
Message2: "in ctor with parameters"
Right: 0
Top: 5
I'm creating a method that will analyze an instance of a class that I have created, checking each of the properties on that class for string types and then checking if those string properties are null or empty.
Code:
public class RootClass
{
public string RootString1 { get; set; }
public string RootString2 { get; set; }
public int RootInt1 { get; set; }
public Level1ChildClass1 RootLevel1ChildClass11 { get; set; }
public Level1ChildClass1 RootLevel1ChildClass12 { get; set; }
public Level1ChildClass2 RootLevel1ChildClass21 { get; set; }
}
public class Level1ChildClass1
{
public string Level1String1 { get; set; }
public string Level1String2 { get; set; }
public int Level1Int1 { get; set; }
}
public class Level1ChildClass2
{
public string Level1String1 { get; set; }
public string Level1String2 { get; set; }
public int Level1Int1 { get; set; }
public Level2ChildClass1 Level1Level2ChildClass11 { get; set; }
public Level2ChildClass1 Level1Level2ChildClass12 { get; set; }
public Level2ChildClass2 Level1Level2ChildClass22 { get; set; }
}
public class Level2ChildClass1
{
public string Level2String1 { get; set; }
public string Level2String2 { get; set; }
public int Level2Int1 { get; set; }
}
public class Level2ChildClass2
{
public string Level2String1 { get; set; }
public string Level2String2 { get; set; }
public int Level2Int1 { get; set; }
}
Not all the properties on the class are strings, some of them are instances of other classes, which have their own properties, which also need to be analyzed the same way. Basically, the method will return true if any of the properties are strings with a value on the RootClass or anywhere on sub-levels of the class (for example, if RootLevel1ChildClass11 has a string property with a value).
Here's what I have so far:
public static bool ObjectHasStringData<T>(this T obj)
{
var properties = typeof(T).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType == typeof(string))
{
try
{
if (!String.IsNullOrEmpty(property.GetValue(obj, null) as string))
return true;
}
catch (NullReferenceException) { } // we want to ignore NullReferenceExceptions
}
else if (!propertyType.IsValueType)
{
try
{
if (ObjectHasStringData(property.GetValue(obj, null)))
return true;
}
catch (NullReferenceException) { } // we want to ignore NullReferenceExceptions
}
}
return false;
}
this works great on the first layer (so any string within the RootClass), but once I start using it recursively on the if (ObjectHasStringData(property.GetValue(obj, null))) line, the return value of property.GetValue() is object, so when calling the method recursively, T is object.
I can get the Type of the current object, but how do I convert the object returned from property.GetValue() to the actual type of the property?
I'd suggest not making that a generic method, just have it accept any object, and use GetType to get the type (unless it's null). The generics doesn't really seem to add anything of value here.
So, remove the type parameter, use obj.GetType(), and don't recurse if the object is null!
Also, (propertyType)obj) won't work, and if it would it would have no use. Casting is only for type safety and determining (at compile time) how to interact with an object. To System.Reflection it doesn't make any difference.
public static bool ObjectHasStringData( this object obj )
{
if( obj == null )
return false;
var properties = obj.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var property in properties)
...
}
I have the following model:
public class FactCache
{
public int ID { get; set; }
public DateTime MonthDate { get; set; }
public string AttributeKey { get; set; }
public decimal RawValue { get; set; }
public decimal ManDayValue { get; set; }
public decimal FTEValue { get; set; }
public int? InputResourceID { get; set; }
public int? PhaseID { get; set; }
public virtual InputResources InputResource { get; set; }
public virtual DimPhase Phase { get; set; }
}
As you can see above, InputResourceID and PhaseID are nullable optional fields.
I want to write a query to find the first entry for a given date and AttributeKey where both PhaseID and InputResourceID are null.
I have tried the following code:
FactCache fact = db.FactCache.FirstOrDefault(
a => a.InputResourceID == null
&& a.PhaseID == null
&& a.MonthDate == monthDate
&& a.AttributeKey == key);
However, it returns a null object. What is the correct way to write the above query?
I have checked the database and there are indeed entries with null PhaseID and InputResourceID.
Not sure, but perhaps...
FactCache fact = db.FactCache.FirstOrDefault(
a => false == a.InputResourceID.HasValue
&& false == a.PhaseID.HasValue
&& a.MonthDate == monthDate
&& a.AttributeKey == key);
Just a note, I you are lucky enough to be running EF version 5 or above try the solution proposed here: Call is failing with null parameter
I have a class:
public class TaskDiplayModel
{
public int taskId { get; set; }
[DisplayName("Task Description")]
public string description { get; set; }
[DisplayName("Priority")]
public string priority { get; set; }
[DisplayName("State")]
public string state { get; set; }
[DisplayName("Due By")]
public DateTime deadline { get; set; }
[DisplayName("Created By")]
public PersonObject created_by { get; set; }
[DisplayName("Assigned To")]
public PersonObject assigned_to { get; set; }
[DisplayName("Category")]
public string category { get; set; }
[DisplayName("Sub Category")]
public string subCategory { get; set; }
[DisplayName("Created")]
public DateTime createdDate { get; set; }
[DisplayName("Updated")]
public DateTime lastUpdatedDate { get; set; }
[DisplayName("Updated By")]
public PersonObject lastUpdatedBy { get; set; }
}
I then have another class which inherits from this class:
public class TaskModifyModel : TaskDiplayModel
{
public int priorityId { get; set; }
public int stateId { get; set; }
public int categoryId { get; set; }
public int subCategoryId { get; set; }
public SelectList states { get; private set; }
public SelectList priorities { get; private set; }
public SelectList categories { get; private set; }
public SelectList subCategories { get; private set; }
public TaskModifyModel()
{
SetupReferenceData(0);
}
public TaskModifyModel(int taskId)
{
var taskService = new TaskService();
var task = taskService.GetTask(taskId);
}
}
In my application, I create a TaskModifyModel object. However, string fields from the base class are null. I'd expect them to have been created and be String.Empty. But I get exception when I try to access them. Am I missing something?
These are MVC3 Models, by the way.... And code from the classes have been omitted as I think it's irrelevant to the question.
in .NET, the default value for a string is null, not String.Empty, so unless you specifically set the values of the properties to String.Empty, they will remain null.
Assuming you want your string properties to default to an empty string instead of null, you would normally do this either by setting them in the constructor:
public void TaskDiplayModel()
{
description = String.Empty;
priority = String.Empty;
state = String.Empty;
}
Or by using a field-backed property instead of an auto property, and setting the backing field:
private string _description = String.Empty;
[DisplayName("Task Description")]
public string description
{
get { return _description; }
set { _description = value; }
}
Personally I usually use the first option, doing it in the constructor, because it is less to code.
Just to add to rally25rs' excellent answer (+1 from me anyway), given the following abridged version:
public class TaskDiplayModel
{
private string _priority = string.Empty;
public int TaskId { get; set; }
public string Description { get; set; }
public string Priority
{
get { return _priority; }
set { _priority = value; }
}
public TaskDisplayMode()
{
Description = string.Empty;
}
}
public class TaskModifyModel : TaskDisplayMode
{
public int PriorityId { get; set; }
public TaskModifyModel()
:base()
{
PriorityId = 3;
}
}
Then the order upon construction of TaskModifyModel is as follows:
Set _priority to string.Empty, TaskId to 0, PriorityId to 0, and Description to null (if no value is stated, everything gets set to null if a reference, 0 if a number, and structs get set to having their fields full of 0 and null).
If the constructor body of TaskDiplayModel is executed, setting Description to string.Empty.
The constructor body of TaskModifyModel is executed, setting PriorityId to 3.
And so on if the nested inheritance is more complicated. As a rule, you can expect some of this to be optimised, so don't worry about whether it would be faster or slower to take a different approach as to how you set a value - it won't, except in debug runs. It does though explain the rule of avoiding calling virtual methods within constructors - most of the time we don't need to care about the ordering above and just treat the constructor as a single unit after which we have a fully constructed object, but if you start playing with virtual calls then the above ordering becomes very important because at one point PriorityId is 0, and at another its 3.