I have a CreateMap:
CreateMap<ExtractInsertRequestViewModel, Extract>()
.ConstructUsing(source => new Extract(source.MemberId,
source.IsChargeBack,
source.Type,
source.Description,
source.Value,
source.VerifyBalanceBeforeRedeem))
Then I execute the transfomation (vm is my viewmodel):
var extract = Mapper.Map<Extract>(vm);
But inside my Extract ctor, I have 2 functions that may change the values (SetStatus and SetValue):
public Extract(int memberId, bool isChargeBack, ExtractType type, string description, int value, bool verifyBalanceBeforeRedeem)
{
MemberId = memberId;
IsChargeBack = isChargeBack;
Type = type;
Description = description;
SetStatus(Status.A);
IsAble = true;
VerifyBalanceBeforeRedeem = verifyBalanceBeforeRedeem;
SetValue(value);
}
public void SetValue(int newValue)
{
if (Type == ExtractType.DEBIT && newValue > 0 || Type == ExtractType.CREDIT && newValue < 0)
newValue = newValue * -1;
Value = newValue;
}
The issue is, after the value was changed by any of this functions, the Extract object result is created with the original values.
For ex: I passed a Debit operation with a positive value. The SetValue method should convert to negative, but in the final object, the value still positive.
Seems to me that the ConstructUsing runs after the constructor. The constructor set the correct values but ConstructUsing overwrite the values with the original ones.
Any thoughts of what's going on here ??
Thanks in advance!
Related
My code is .Net 4.0 and I am trying to understand some legacy code I now work with. I can't change it at the moment and i'm sure this code has worked before my time. It needs to make an enum from strings, but the type is not recognized as an enum.
EDIT
I now realize the enum property is actually nullable. So it is a NetType? How can I convert that into an enum if it has a value?
When I debug and see the type that is being checked on the enum, this is what I see:
FullName = System.Nullable1[[AppName.Model.NetType, AppName.Model,
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]
Name = Nullable1
This is the enum:
public enum NetType
{
ChoiceOne = 1,
ChoiceTwo = 2
}
Main code, simplified for clarity:
var property = typeof(MainClass).GetProperty("NetType");
var value = GetValue(property.PropertyType, "ChoiceOne");
private object GetValue(Type type, string valueString)
{
if (type.IsEnum)// Why false?
return Enum.Parse(type, valueString);
if (type == typeof (Int32))
return Int32.Parse(valueString);
return valueString;
}
Another option is to use Nullable.GetUnderlyingType() to check to see if it's a nullable enum first. If it is, use the underlying enum; if it's not, do your checks as you normally did.
private object GetValue(Type type, string valueString)
{
// If Nullable.GetUnderlyingType() returns null, it's not nullable
// and you can default to type.
var enumCandidiate = Nullable.GetUnderlyingType(type) ?? type;
if (enumCandidiate.IsEnum)
return Enum.Parse(enumCandidiate, valueString);
if (type == typeof (Int32))
return Int32.Parse(valueString);
return valueString;
}
Here was my test script (using RoslynPad, hence the Dump() calls).
var val = GetValue(typeof(NetType), "ChoiceOne");
val.Dump();
val = GetValue(typeof(NetType?), "ChoiceOne");
val.Dump();
Try this:
var type = property.PropertyType;
object value;
if (type.IsEnum)
{
value = GetValue(type, "ChoiceOne");
}
else if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>) &&
type.GetGenericArguments()[0].IsEnum)
{
value = GetValue(type.GetGenericArguments()[0], "ChoiceOne");
}
It should work for both NetType and NetType?.
I have a ViewModel which contains properties that can optionally be filled from the user of my web application (e.g. first name, last name, e-mail, date of birth etc). These properties include several types like string, bool int, decimal, double, DateTime. All these types can be both nullable and non-nullable in the ViewModel.
If at least 1 of these properties has been filled in, then I have to create a database record. Do you have any idea for a way to check if any of these optional values has been filled?
You can implement this code, pass your viewmodel, then count how much fields are not null, if the return value>0, then you can implement your Db work.
public int MethodToCheckNotNull(ViewModel obj)
{
int i = 0;
PropertyInfo[] properties = typeof(obj).GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.GetValue(obj) != null)
{
i++;
}
}
return i;
}
By convention, primitive data types are required. You can make the properties nullable which are primitive like int, double, DateTime vs. Then:
PropertyInfo[] infos = yourObjectInstance.GetType().GetProperties();
int count = 0;
for(int i = 0; i < infos.Length; i++)
{
if(infos[i].PropertyType == typeof(string))
{
string stringValue = infos[i].GetValue(yourObjectInstance).ToString().Trim();
if(!string.IsNullOrEmpty(body))
{
count++;
}
continue;
}
if(infos[i].GetValue(yourObjectInstance) != null)
{
count++;
}
}
if(count == 0)
{
// Handle error
}
// Create record
I have simple NHibernate interceptor and override method OnSave().
Now what I am trying to do here is to get SQL length for string properties.
Is that possible.
I can see that property IType[] types contains SqlType where Length is available, but just cannot find how to read it. Example from debug:
This is example of the code which I have, and where I am trying to get Sql length of property.
public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
{
for (int i = 0; i < propertyNames.Length; i++)
{
//If type is string
if (types[i].GetType() == typeof(NHibernate.Type.StringType))
{
//Get SQL length of string property
}
}
return false;
}
Any help how I can get this?
Let's just try to cast the IType into intended one:
//If type is string
var stringType = types[i] as NHibernate.Type.StringType;
//if (types[i].GetType() == typeof(NHibernate.Type.StringType))
if(stringType != null)
{
//Get SQL length of string property
var length = stringType.SqlType.Length;
}
Some background to understand the code. I have an MVC application, all my models implement IModel. IModel just enforces to have an int Id property.
The following method "updates" an instances of a model with the data available in a viewmodel. For each property of the viewmodel it checks if a corresponding property exists in the model, if it does It updates the value in the model with those of the viewmodel, if the values are different.
At the last point it goes wrong. The statement : OldValue != NewValue always returns true, even if f.e. both are integers, 1. Why ?
public static Boolean UpdateIfChanged<M, VM>(this M Model, VM ViewModel) where M : IModel
{
Boolean HasUpdates = false;
Type Mtype = typeof(M);
PropertyInfo[] MProperties = Mtype.GetProperties(BindingFlags.Public | BindingFlags.Instance);
Type VMtype = typeof(VM);
PropertyInfo[] VMProperties = VMtype.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var VMProperty in VMProperties)
{
if (!VMProperty.PropertyType.GetInterfaces().Any(x => x.Name == typeof(IModel).Name)
&& MProperties.Any(x => x.Name == VMProperty.Name)
&& Mtype.GetProperty(VMProperty.Name).PropertyType == VMProperty.PropertyType )
{
var OldValue = Mtype.GetProperty(VMProperty.Name).GetValue(Model);
var NewValue = VMtype.GetProperty(VMProperty.Name).GetValue(ViewModel);
if (NewValue != null)
{
if (OldValue == null)
{
Mtype.GetProperty(VMProperty.Name).SetValue(Model, NewValue);
HasUpdates = true;
}
else
{
if (OldValue != NewValue)
{
Mtype.GetProperty(VMProperty.Name).SetValue(Model, NewValue);
HasUpdates = true;
}
}
}
}
}
return HasUpdates;
}
The problem here is that OldValue and NewValue are objects at compile time, not int, and therefore the ==/!= operators call the ones defined by the object class, because all operators are static. The object operators check for referential equality, not logical equality, and thus only check if the two arguments are exactly the same object (the same pointer in C++)
To get around this, you have several options
As Tigran mentioned, type cast the values coming out, so you end up using the operator defined in int instead of object
Call object.Equals(OldValue, NewValue), which checks for null and then calls the virtual Object.Equals(object o), which thus will call the function defined in the actual class/struct of the calling object (in this case int)
your GetValue(..) call returns boxed integer object, so reference type.
Hence your code:
//OldValue and NewValue are Object types and NOT integers !
if (OldValue != NewValue)
compares references and not values.
You didn't notice that as you are using var keyword, which "hides" concrete type.
To correctly overcome this issue, may do like:
....
var OldValue = (int)Mtype.GetProperty(VMProperty.Name).GetValue(Model); //cast to int
var NewValue = (int)VMtype.GetProperty(VMProperty.Name).GetValue(ViewModel);//cast to int
....
Try this if (OldValue.ToString() != NewValue.ToString()). Or if OldValue/NewValue are int-s: if ((int)OldValue != (int)NewValue)
A better syntax would be:
if (!Equals(OldValue, NewValue))
I want to pass a property into a method and search for records that match the given value. The following code does not throw an error, but also does not return any data - ever. I don't know if the problem is setting the column / property like this, or if something else is wrong... the code looks like:
public virtual IList<ReceivingInspection> GetRecordsBySupplier(string property, string value) {
if (property.Length < 1 || value.Length < 1) return null;
var result = from ri in _receiveInspectRepository.Table
where ri.property == value
select ri;
return result.ToList();
}
You should iterate over the items in _receiveInspectRepository.Table and use Reflection to get the value of the property
Something like this:
Type t = ri.GetType();
PropertyInfo prop = t.GetProperty(property);
if(prop.GetValue(ri) == value)
{
dostuff();
}