Automapper:将int转换为string

4

我目前正在我的C# MVC项目中使用AutoMapper,但在将一个整数转换为字符串时遇到了问题。

我有两个类:

public class Job
{
    public string Prefix { get; set; }
    public int JobNumber { get; set; }
    public int Year { get; set }
    public int JobPriority { get; set; }

    public virtual EntityPriority EntityPriority { get; set; }
}

public class JobViewModel
{
    public string JobNumberFull { get; set; }
{

使用Automapper,我想将Job类中的三个属性连接起来形成一个字符串,然后将其映射到JobViewModel类中的JobNumberFull属性。
前缀-JobNumber-年份
为了开始,我保持简单,没有将字段连接成一个字符串,我只是试图将JobNumber(int)映射到JobNumberFull(string),如下所示:
Mapper.CreateMap<int, string>().ConvertUsing(Convert.ToString);
Mapper.CreateMap<Job, JobViewModel>()
    .ForMember(d => d.JobPriorityId, opt => opt.MapFrom(s => s.EntityPriority.EntityPriorityID))
    .ForMember(d => d.JobPriorityLevel, opt => opt.MapFrom(s => s.EntityPriority.PriorityLevel))
    .ForMember(d => d.JobNumberFull, opt => opt.MapFrom(s => s.JobNumberYear));
Mapper.AssertConfigurationIsValid();

var jobsList = db.Jobs.Where(j => j.OperationID == operationId).Project().To<JobViewModel>().ToList();

当我运行此代码时,出现以下错误。
Type 'System.String' does not have a default constructor

我知道这与IT技术有关

Convert.ToString

但我不确定该怎么做!当从字符串转换为整数时,我可以使用Convert.ToInt32,效果很好。我需要创建自定义类型转换器吗?

我该如何获得字符串前缀-工作号码-年份?

非常感谢所有帮助。


更新

在Jeremy和AutoMapper网站的帮助下,我已经成功解决了这个问题,以下是我的解决方案,请随意评论,如果您认为有更优雅的解决方案:

public class Job 
{
    public string Prefix { get; set; }
    public int JobNumber { get; set; }
    public int Year { get; set; }
    public int JobPriority { get; set; }

    public virtual EntityPriority EntityPriority { get; set; }
}

public class JobViewModel 
{
    public int JobNumber { get; set; }
    public int Year { get; set; }
    public string JobNumberFull { get; set; }
}

public enum EntityPriority 
{
  Normal = 0,
  High
}

public interface IValueResolver
{
   ResolutionResult Resolve(ResolutionResult source);
}

public class JobNumberConverter : ValueResolver<Job, string>
{
    protected override string ResolveCore(Job source)
    {
        return string.Format("{0}-{1}-{2}", source.Prefix, source.JobNumber, source.Year);
    }
}

public ActionResult Index()
{
    Mapper.CreateMap<Job, JobViewModel>()
        .ForMember(jvm => jvm.JobNumberFull, opt => opt.ResolveUsing<JobNumberConverter>());
    Mapper.AssertConfigurationIsValid();

    List<Job> jobs = new List<Job>();

    Job j = new Job()
    {
        JobNumber = 1,
        Prefix = "prefix",
        Year = 2013,
        EntityPriority = EntityPriority.High,
        JobPriority = 2
    };

    Job j2 = new Job()
    {
        JobNumber = 2,
        Prefix = "prefix",
        Year = 2013,
        EntityPriority = EntityPriority.High,
        JobPriority = 2
    };

    Job j3 = new Job()
    {
        JobNumber = 3,
        Prefix = "prefix",
        Year = 2013,
        EntityPriority = EntityPriority.High,
        JobPriority = 2
    };

    jobs.Add(j);
    jobs.Add(j2);
    jobs.Add(j3);

    var jobViewModels = jobs.Select(job => Mapper.Map<JobViewModel>(job));

    return View();

}

1
如果您不尝试过于简化并只为Job到JobViewModel指定一个转换函数,那么这将变得更加简单。请阅读关于XY问题的内容,并避免在下一个问题中出现它。 :) - Jeremy
还有一件事需要注意 - 投影实际上创建了一个LINQ查询,以供EF使用。对于Resolvers或ConvertUsing,它们不在LINQ查询中使用,只有MapFrom会使用。一个快速的解决方法是简单地使用ToString()。在您的JobNumberFull中,使用MapFrom - 但使用字符串连接而不是string.Format(EF不知道string.Format)。这将为您创建一个自定义的SQL查询! - Jimmy Bogard
2个回答

8
我认为您可以使用ResolveUsing方法来解决这个问题。
Mapper.CreateMap<Job, JobViewModel>()
    .ForMember(d => d.JobNumberFull,
    exp =>
    exp.ResolveUsing(j => string.Format("{0}-{1}-{2}", j.Prefix, j.JobNumber, j.Year)));

我已经接受了这个答案,因为它提供了一个优雅的内联用法来实现我想要达到的目的。我在原始问题中保留了更新,因为这展示了如何编写可重用的值转换器。 - oceanexplorer
感谢大家帮助我取得了成果。 - oceanexplorer
我需要的东西。清晰简单。谢谢。 - MRFerocius

0
你需要为从Job到JobViewModel的转换指定一个自定义转换函数。
Mapper.CreateMap<Job, JobViewModel>().ConvertUsing(
  job => new JobViewModel {
    JobNumberFull = string.Format("{0}-{1}-{2}",
                      job.Prefix, job.JobNumber, Job.Year)
  });

把工作(Job)转换为工作视图模型(JobViewModel),可以使用Map函数。

var jobViewModel = Mapper.Map<JobViewModel>(job);

要将作业列表转换为JobViewModels,请使用Select扩展方法。

var jobViewModels = jobs.Select(job => Mapper.Map<JobViewModel>(job));

1
Jeremy,感谢您的回复,这个方法没有报错,但是它没有填充字段,它们都是空的。我已经添加了我的 .ForMember 行用于我要展开的其他几个字段,但是一旦完成投影,它们也是空的。 - oceanexplorer
哦,还有你问题中第二个代码块的第2行中的ListJobsViewModel类型是什么? - Jeremy
我正在尝试从一个工作(Job)创建一个JobViewModel。我从数据库中选择了许多工作,但是jobs表中有很多不需要的字段来显示我需要展示的数据(我在上面缩短了我的工作类),因此我创建了一个JobViewModel来仅公开我需要展示的数据。 - oceanexplorer
我更新了我的答案,并附上了我正在使用的完整测试代码。它将 prefix-1-2013 输出到控制台。 - Jeremy
那么我该如何将一个类Job的列表转换为JobViewModel的列表,以便我可以调用Mapper.Map<JobViewModel>(j)? - oceanexplorer
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接