Auto Mapper преобразува от низ в Int

Създавам просто MVC4 приложение

Имам автоматичен картограф

 Mapper.CreateMap<SourceClass, DestinationClass>()
      .ForMember(dest => dest.IntphoneNo, 
                  opt => opt.MapFrom(src => src.Stringphoneno));

IntphoneNo е от DataType int (IntphoneNo е променлива от моя клас Person) Изходният атрибут Stringphoneno е от DataType string .

Когато картографирам, получавам следната грешка.

Възникна изключение от тип „AutoMapper.AutoMapperMappingException“ в AutoMapper.dll, но не беше обработено в потребителския код

Но когато променям Dataype на IntphoneNo от int на string, програмата ми работи успешно.

За съжаление не мога да променя Datatype в моя модел

Има ли някакъв начин да промените Datatupe в картографирането .. Нещо като по-долу

.ForMember(dest => dest.IntphoneNo, 
                  opt => opt.MapFrom(src => src.Int32(Stringphoneno));

След известно проучване стигнах една крачка напред ..
Ако моят StringPhoneNo е = 123456
тогава следният код работи. Не е необходимо да го анализирам на низ

Mapper.CreateMap<SourceClass, DestinationClass>()
      .ForMember(dest => dest.IntphoneNo, 
                  opt => opt.MapFrom(src => src.Stringphoneno));

но когато моят StringPhoneNo е = 12 3456 (има интервал след 12), тогава кодът ми не работи. Има ли някакъв начин за изрязване на интервали в Stringphoneno (Stringphoneno получавам от уеб услуга) в automapper.

Нещо като по-долу..

Mapper.CreateMap<SourceClass, DestinationClass>()
      .ForMember(dest => dest.IntphoneNo, 
                  opt => opt.MapFrom(src => src.Trim(Stringphoneno))); 

person user2739679    schedule 12.09.2013    source източник
comment
Не бих препоръчал да съхранявате телефонни номера (предполагам) като int, ще загубите международните/регионалните номера с нулев префикс. Освен това някои числа могат да бъдат много дълги. (освен ако не използвате int64) С 11 числа имате някои проблеми с препълването.   -  person Jeroen van Langen    schedule 12.09.2013
comment
@JeroenvanLangen Попаднах на същия вид съвет в един момент, когато някой посочи, че не трябва да използваме типа money sql за съхраняване на пари и вместо това трябва да използваме decimal. Засмях се добре, когато посочих, че работим в долари и ако някога имахме поръчка, при която покупката всъщност беше по-голяма от вида на парите, щях да направя поръчката на ръка, ние бяхме малка винена компания. Не е много подходящо, просто история, която винаги съм харесвала.   -  person Yuriy Faktorovich    schedule 12.09.2013
comment
@Yuriy Faktorovich - Но намирането на международен телефонен номер, по-голям от 10 цифри, е много по-лесно, отколкото отбелязването на поръчка, по-голяма от max money-type :)   -  person Jeroen van Langen    schedule 12.09.2013
comment
Типът източник на данни не е в моя контрол. Получавам източник чрез уеб услуга..   -  person user2739679    schedule 12.09.2013
comment
@JeroenvanLangen Съгласен съм, просто една история, която винаги съм харесвал.   -  person Yuriy Faktorovich    schedule 12.09.2013


Отговори (4)


Mapper.CreateMap<SourceClass, DestinationClass>() 
    .ForMember(dest => dest.IntphoneNo, 
        opt => opt.MapFrom(src => int.Parse(src.Stringphoneno)));

Ето примерен работен код, използващ описаната карта

class SourceClass
{
    public string Stringphoneno { get; set; }
}

class DestinationClass
{
    public int IntphoneNo { get; set; }
}

var source = new SourceClass {Stringphoneno = "8675309"};
var destination = Mapper.Map<SourceClass, DestinationClass>(source);

Console.WriteLine(destination.IntphoneNo); //8675309
person Yuriy Faktorovich    schedule 12.09.2013
comment
трябва да прихванете изключението, може би прехвърлянето към string--› int не е възможно. - person ZaoTaoBao; 12.09.2013
comment
stackoverflow.com/questions/136035/ до заснемете изключението!! може би низът не е число... - person ZaoTaoBao; 12.09.2013
comment
@user2739679 int.Parse и Int32.Parse са буквално едно и също нещо, int преобразува в Int32. Можете да поставите точка на прекъсване в ламбда израза, който извършва синтактичния анализ, за ​​да видите каква е стойността на Stringphoneno, за да разберете дали трябва да го форматирате, първо да го премахнете от тирета например. - person Yuriy Faktorovich; 12.09.2013
comment
не мога да поставя точка на прекъсване на реда вътре в Mapper.CreateMap. Когато се опитвам да поставя точка на прекъсване, това избира цялата област на automapper - person user2739679; 12.09.2013
comment
@user2739679 подчертайте int.Parse(src.Stringphoneno) щракнете с десния бутон върху него изберете вмъкване на точка на прекъсване. - person Yuriy Faktorovich; 12.09.2013
comment
стойността на src.stringphoneNo е 12345678... но int.Parse не работи дори ако променя Datatype на IntphoneNo на низ... - person user2739679; 12.09.2013
comment
@user2739679 ще трябва да уточните какъв е този номер, в противен случай проблемът ви е другаде. Публикувах някакъв работещ код. - person Yuriy Faktorovich; 12.09.2013
comment
@ Юрий Факторович.. StringPhoneNo получавам от уеб услугата.. Нямам контрол над StringPhoneNo.. Единственото нещо, което виждам, е DATATYPE на StringPhoneNo е низ и DATATYPE на IntPhoneNo в моя модел е низ.. - person user2739679; 13.09.2013
comment
@ Юрий Факторович.. за да бъдем точни, стойността в **StringPhoneNo ** е 12 23456 ..(след 12 има интервал)... - person user2739679; 13.09.2013
comment
@user2739679, ако това е вашият модел, тогава трябва да го промените на низ. Също така можете просто да замените това пространство преди int.Parse. - person Yuriy Faktorovich; 13.09.2013

Проблемът, с който може да се сблъскате, е, че когато не може да анализира низа, една от опциите би била да използвате ResolveUsing:

Mapper.CreateMap<SourceClass, DestinationClass>() 
.ForMember(dest => dest.intphoneno, opts => opts.ResolveUsing(src =>
                double.TryParse(src.strphoneno, out var phoneNo) ? phoneNo : default(double)));
person StuckOverflow    schedule 26.02.2017
comment
това може да е едноредов (...src => double.TryParse(src.strphoneno, out var phoneNo) ? phoneNo : default(double)) - person Dinerdo; 15.12.2018
comment
Това решение изглежда вече не работи. ResolveUsing беше премахнат и препоръчителната алтернатива в документите, MapFrom, използва изразни дървета, така че не можете да използвате out аргументи. - person Guttsy; 11.02.2021

Решението на Yuriy Faktorovich може да бъде обобщено за всички strings, които трябва да бъдат преобразувани в ints чрез дефиниране на метод за разширение за IMappingExpression и използване на някои персонализирани атрибути:

[AttributeUsage(AttributeTargets.Property)]
public class StringToIntConvertAttribute : Attribute
{
}

// tries to convert string property value to integer
private static int GetIntFromString<TSource>(TSource src, string propertyName)
{
    var propInfo = typeof(TSource).GetProperty(propertyName);
    var reference = (propInfo.GetValue(src) as string);
    if (reference == null)
        throw new MappingException($"Failed to map type {typeof(TSource).Name} because {propertyName} is not a string);

    // TryParse would be better
    var intVal = int.Parse(reference);
    return intVal;
}

public static IMappingExpression<TSource, TDestination> StringToIntMapping<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
    var srcType = typeof(TSource);
    foreach (var property in srcType.GetProperties().Where(p => p.GetCustomAttributes(typeof(StringToIntConvertAttribute), inherit: false).Length > 0))
    {
        expression.ForMember(property.Name, opt => opt.MapFrom(src => GetIntFromString(src, property.Name)));
    }

    return expression;
}

За да работи това, трябва да се извършат следните стъпки:

  1. Съпоставянето между източник и дестинация трябва да добави разширението за съпоставяне. напр.:

    var config = new MapperConfiguration(cfg =>
    {
       // other mappings
    
       cfg.CreateMap<SrcType, DestType>().StringToIntMapping();
    });
    
  2. Приложете атрибута към всички свойства на изходния низ, които трябва автоматично да бъдат преобразувани в цели числа

person Alexei - check Codidact    schedule 08.12.2016

Ето един по-прост, но по-малко мащабируем подход. Всеки път, когато извиквате Mapper.Initialize, не забравяйте да извикате .ToInt() или ще получите грешка по време на изпълнение.

public class NumberTest
{
    public static void Main(string[] args)
    {
        Console.WriteLine("".ToInt());
        // 0
        Console.WriteLine("99".ToInt());
        // 99
    }
}

public static class StringExtensions
{
    public static int ToInt(this string text)
    {
        int num = 0;
        int.TryParse(text, out num);
        return num;
    }
}

// Use like so with Automapper
.ForMember(dest => dest.WidgetID, opts => opts.MapFrom(src => src.WidgetID.ToInt()));
person Mitch Stewart    schedule 19.04.2017