0

我在将 POCO 对象投影到 DTO 对象时遇到了一些困难

我的 POCO 对象

public class LogEntry
{
    public LogEntry()
    {
        this.Username = Environment.UserName;
        this.LogNote = String.Empty;

        var now = DateTime.Now;
        this.LoginTime = now;
        this.LastSeenInput = now;
        this.ServerName = Environment.MachineName;
    }

    public int LogEntryId { get; set; }

    [Required(AllowEmptyStrings = false)]
    [Column(TypeName = "nvarchar")]
    [MaxLength(64)]
    public string Username { get; set; }

    [Required(AllowEmptyStrings = true)]
    [Column(TypeName = "varchar")]
    [MaxLength(20)]
    public string ServerName { get; set; }

    public DateTime LoginTime { get; set; }
    public TimeSpan ConnectedFor { get; set; }
    public TimeSpan IdleFor { get; set; }
    public DateTime? LastSeenInput { get; set; }

    [Required(AllowEmptyStrings = true)]
    public string LogNote { get; set; }
}

我的 DTO 对象

public sealed class ClientEventDTO
{
    public int LogEntryId { get; set; }
    public string Username { get; set; }
    public string ServerName { get; set; }
    public DateTime LoginTime { get; set; }
    public TimeSpan ConnectedFor { get; set; }
    public string LogNote { get; set; }

    public TimeSpan IdleForWithLast { get; set; }
}

我想做的是我想IdleForWithLast代表

public TimeSpan IdleForWithLast
{
    get
    {
        var tmp = IdleFor;
        if (LastSeenInput.HasValue)
            tmp = tmp.Add(DateTime.Now - LastSeenInput.Value);
        return tmp;
    }
}

但是,当我这样做时

static void Main(string[] args)
{
    Mapper.CreateMap<LogEntry, ClientEventDTO>()
        .ForMember(dto => dto.IdleFor, 
                   a => a.MapFrom(ent => ent.LastSeenInput == null ? 
                                            ent.IdleFor : 
                                            ent.IdleFor + (DateTime.Now - ent.LastSeenInput.Value)
                                 )
                  );

    Mapper.AssertConfigurationIsValid();

    using (var ctx = new LoginHistoryContext())
    {
        var username = "Scott";

        var query = ctx.LogEntries.Where(entry => entry.Username == username).Project().To<ClientEventDTO>();
        var result = query.ToList();

        Debugger.Break();
    }
}

我得到以下异常

System.ArgumentException 未处理
HResult=-2147024809
Message=DbArithmeticExpression 参数必须具有数字通用类型。
源=系统.数据.实体

更改ent.IdleFor + (DateTime.Now - ent.LastSeenInput.Value)ent.IdleFor.Add(DateTime.Now - ent.LastSeenInput.Value)只是给了我一个不同的例外

System.NotSupportedException 未处理
HResult=-2146233067
Message=LINQ to Entities 无法识别方法 'System.TimeSpan Add(System.TimeSpan)' 方法,并且此方法无法转换为存储表达式。
源=系统.数据.实体

在保持兼容性的同时使用这种操作的正确方法是什么QueryableExtensions

如果您不关心兼容性,可以通过这种方式轻松完成

static void Main(string[] args)
{
    Mapper.CreateMap<LogEntry, ClientEventDTO>()
        .ForMember(dto => dto.IdleFor, opt=>opt.ResolveUsing<CustomResolver>());

    Mapper.AssertConfigurationIsValid();

    using (var ctx = new LoginHistoryContext())
    {
        var username = "Scott";

        var query = ctx.LogEntries.Where(entry => entry.Username == username);
        var result = Mapper.Map<List<ClientEventDTO>>(query.ToList());

        Debugger.Break();
    }
}

public class CustomResolver : ValueResolver<LogEntry, TimeSpan>
{
    protected override TimeSpan ResolveCore(LogEntry source)
    {
        var tmp = source.IdleFor;
        if (source.LastSeenInput.HasValue)
            tmp = tmp.Add(DateTime.Now - source.LastSeenInput.Value);
        return tmp;
    }
}

这就是我可能会在这种情况下使用的解决方法,但我想知道将来如何处理这个问题,以防我处于必须使用的情况QueryableExtensions并且需要做类似的事情。

4

1 回答 1

2

可以忽略该成员,映射后手动映射:

Mapper.CreateMap<LogEntry, ClientEventDTO>()
      .ForMember(dto => dto.IdleForWithLast, m => m.Ignore())
      .AfterMap((ent, dto) =>
           dto.IdleForWithLast = ent.LastSeenInput.HasValue ?
           ent.IdleFor + (DateTime.Now - ent.LastSeenInput.Value) : ent.IdleFor);

或更改后映射中的默认映射:

Mapper.CreateMap<LogEntry, ClientEventDTO>()
      .ForMember(dto => dto.IdleForWithLast, m => m.MapFrom(ent => ent.IdleFor))
      .AfterMap((ent, dto) => {
            if (ent.LastSeenInput.HasValue)
                dto.IdleForWithLast += DateTime.Now - ent.LastSeenInput.Value;
       });
于 2013-08-14T14:42:53.043 回答