我们正在进行大型 .net 升级(从 4.8 升级到 7),但我们的一些预测存在问题。这一切在 automapper 8 和 .net 4.8 上都工作得很好,但自从升级到 12 后,当我们尝试投影到具有可选相关子项的实体时,我们现在会得到
NotSupportedException: Unknown LINQ expression of type 'Default'.
。
感觉我们正在做的事情非常基本,所以不确定出了什么问题。
实体:
[Table("PaymentUploads")]
public class PaymentUpload
{
[Key]
[Column("PaymentUploadId")]
public int Id { get; set; }
[Required]
[MaxLength(200)]
public string FileName { get; set; }
[Required]
public byte[] RawFileContents { get; set; }
public DateTime? ProcessedOn { get; set; }
public Guid? ProcessedById { get; set; }
[ForeignKey("ProcessedById")]
public virtual ApplicationUser? ProcessedBy { get; set; }
}
D对:
public class PaymentUploadDto
{
public int Id { get; set; }
public string FileName { get; set; }
public DateTime TransactionDate { get; set; }
public decimal TotalPaymentAmount { get; set; }
public DateTime? ProcessedOn { get; set; }
public Guid? ProcessedById { get; set; }
public ApplicationUserPreview? ProcessedBy { get; set; }
}
简介:
CreateProjection<PaymentUpload, PaymentUploadDto>();
要求:
DbContext.PaymentUploads.AsNoTracking().Where(g => g.CreatedOn >= createdOnOrAfter).ProjectTo<PaymentUploadDto>(Mapper.ConfigurationProvider);
如果我们将配置文件更改为:
CreateProjection<PaymentUpload, PaymentUploadDto>()
.ForMember(dest => dest.ProcessedBy, opt => opt.DoNotAllowNull());
然后,只要每个
ProcessedById
列条目都有一个值,所有内容都会按预期返回,但如果有任何确实包含 ProcessedById 的 null
,现在它会抛出: 'The cast to value type 'System.Guid' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.'
所有关联的属性似乎都被正确声明为可为空所以我们不确定为什么这没有转化为自动映射器试图执行的任何内容。
尝试过
AllowNull()
,但随后又回到了投掷Unknown LINQ expression of type 'Default'
。
不幸的是,这个问题使得 AutoMapper 很难与在新版本 .NET 上运行的 EF 6 一起使用(Microsoft 支持的用例,对于迁移旧应用程序非常有帮助)。
我使用简单的重写技术解决了这个问题(用常量替换默认表达式)。将
ProjectTo
替换为以下扩展方法 ProjectToWithDefaultExpressionFix
:
public static class QueryExtensions
{
public static IQueryable<TDestination> ProjectToWithDefaultExpressionFix<TDestination>(this IQueryable source, IConfigurationProvider configuration)
{
var rewrittenExpression = new FixAutoMapperExpressionRewriter().Visit(source.Expression);
return source.ProjectTo<TDestination>(configuration)
.Provider.CreateQuery<TDestination>(rewrittenExpression);
}
class FixAutoMapperExpressionRewriter : ExpressionVisitor
{
protected override Expression VisitDefault(DefaultExpression node)
{
return Expression.Constant(node.Type.IsValueType ? Activator.CreateInstance(node.Type) : null, node.Type);
}
}
}
AM 现在以 EF Core 为目标,不再支持 EF6。 https://github.com/AutoMapper/AutoMapper/issues/4205