.NET Core/EF Core 2.0 升级后急切加载“类型之间未定义强制运算符”

Posted

技术标签:

【中文标题】.NET Core/EF Core 2.0 升级后急切加载“类型之间未定义强制运算符”【英文标题】:Eager Loading "No coercion operator is defined between types" after .NET Core/EF Core 2.0 Upgrade 【发布时间】:2018-03-01 14:29:34 【问题描述】:

在 .NET Core 1.x 中,我们有一个如下所示的方法:

public async Task<(PaperRecord Component, PaperPointerRecord Pointer)> GetOneAsync(DbSet<PaperPointerRecord> paperPointerRecords,
                                                                                   int? paperId = null,
                                                                                   long? externalPaperId = null,
                                                                                   Expression<Func<PaperPointerRecord, bool>> filter = null)

    var query = filter is null ? paperPointerRecords.AsQueryable() : paperPointerRecords.Where(filter);

    if (paperId.HasValue)
        query = query.Where(_ => _.PaperPointerId == paperId);

    if (externalPaperId.HasValue)
        query = query.Where(_ => _.ExternalId == externalPaperId);

    var record = await query.Include(_ => _.Paper)
                            .ThenInclude(_ => _.PaperColors)
                            .Select(_ => new
                                         
                                             PaperRecord = _.Paper,
                                             PaperPointerRecord = _
                                         )
                            .SingleOrDefaultAsync();

    return !(record is null) ? (record.PaperRecord, record.PaperPointerRecord) : throw NewPaperRecordNotFoundException(paperId, externalPaperId);

这对我们很有效。将整个项目升级到一切 .NET Core 2.0 & EF Core 2.0 后,该方法会抛出此异常:

发生 System.InvalidOperationException:在类型“PaperPointerRecord”和“PaperRecord”之间未定义强制运算符。

此块中发生此异常:

var record = await query.Include(_ => _.Paper)
                        .ThenInclude(_ => _.PaperColors)
                        .Select(_ => new
                                     
                                         PaperRecord = _.Paper,
                                         PaperPointerRecord = _
                                     )
                        .SingleOrDefaultAsync();

如果我删除了预先加载并使其成为这样,那么错误就会消失,但我也没有得到预期的结果:

var record = await query.Select(_ => new
                                     
                                         PaperRecord = _.Paper,
                                         PaperPointerRecord = _
                                     )
                        .SingleOrDefaultAsync();

我已经为此检查了Microsoft Documentation,但我没有看到那里显示任何表明我们在急切加载方面做错了什么。

【问题讨论】:

【参考方案1】:

Include 在这种情况下没有用,因为您正在返回一个投影并且Includes 被忽略(阅读有关被忽略的包括here)。

如果您所说的“预期结果”是指您希望 record.PaperRecord.Paper 有一个值,只需将其包含在您的投影中即可; EF 将建立关系。

new

    PaperRecord = _.Paper,
    PaperPointerRecord = _,
    PaperColor = _.Paper.PaperColor,

【讨论】:

我完全同意你的评价。我基本上按照你的建议解决了这个问题。最后,代码减少了,更直接了。但令我担心的是,它在 1.x 和 2.0 中运行良好,但它对此有异议。在某些方面,它有助于让事情变得更好。但是情况有点勉强,需要我们重新编写大量代码。

以上是关于.NET Core/EF Core 2.0 升级后急切加载“类型之间未定义强制运算符”的主要内容,如果未能解决你的问题,请参考以下文章

.Net Core EF Core之Sqlite使用及部署

asp.net core, Ef core : 在运行时动态映射存储库和服务

sqlite + .net core ef 3

ASP MVC 应用程序中的列加密与使用 .net Core / EF Core 的 SQL Server 2016

如何在 .net core ef 上应用 thenInclude 条件?

(17)ASP.NET Core EF基于数据模型创建数据库