【问题标题】:EF Core - LINQ - Assign property to IQueryable<T>EF Core - LINQ - 将属性分配给 IQueryable<T>
【发布时间】:2018-11-30 09:44:00
【问题描述】:

我想使用 LINQ 查询一些实体:

public class Link: Entity, IAggregateRoot
{
    public Guid RelationId { get; private set; }
    public Guid ConstructionId { get; private set; }

    public virtual Relation Relation { get; private set; }
    public virtual Construction Construction { get; private set; }

    private Link()
    {
    }
}

public class Relation: Entity, IAggregateRoot
{
    public string Number { get; private set; }
    public Guid PersonId { get; private set; }
    public Guid RelationTypeId { get; private set; }

    public virtual Person Person { get; private set; }
    public virtual RelationType RelationType { get; private set; }

    [NotMapped]
    public int ContextKey { get; set; }

    private Relation()
    {
    }
}

我有一个查询,它通过提供构造 id 并使用链接实体来返回关系。查询如下,按预期工作:

public IQueryable<Relation> GetRelationsByConstructionId(Guid constructionId)
{
    var links base.Get(x => x.Construction.ConstructionId == constructionId);

    var relations = links.Include(x => x.Relation)
                         .Select(x => x.Relation)
                         .Include(x => x.Person)
                         .Include(x => x.RelationType);

    return relations;
}

在 Relation 中,我有一个 NotMapped 元素 ContextKey,我想在查询调用中设置这个 ContextKey(例如,我想将它设置为 30)。基本上我想做这样的事情来扩展我使用的查询:

public IQueryable<Relation> GetRelationsByConstructionId(Guid constructionId)
{
    var links base.Get(x => x.Construction.ConstructionId == constructionId);

    var relations = links.Include(x => x.Relation)
                         .Select(x => x.Relation)
                         .Include(x => x.Person)
                         .Include(x => x.RelationType);

    var updatedRelations = relations.ForEachAsync(x => x.ContextKey = 30);

    return updatedRelations;
}

当然这不起作用,因为在 ForEachAsync 之后 updatedRelations 的类型是 Task 并且预期的返回类型必须是IQueryable.

我怎样才能使我的查询工作并以正确的 IQueryable 类型获得我想要的输出?

【问题讨论】:

  • 直接的解决方法是在适当的位置添加asyncawait,但如果异步的唯一原因是使用ForEachAsync,那就太过分了。您的代码中有更多错误或可疑之处:1) var links base.Get... 甚至无法编译。 2) 第一个Include 是多余的,并且 3)(最重要的是)这个查询不一定返回不同的关系,因为多个构造可能具有相同的关系。如果您需要关系,请使用遍历到constructionId 的谓词直接查询关系。 (Relation 需要一个 Links 导航属性)。

标签: entity-framework linq iqueryable


【解决方案1】:

这是我反对未映射属性的原因之一 - 它们不适合 LINQ to Entities 查询。

您可以使用以下 LINQ to Objects 技巧:

var updatedRelations = relations
    .AsEnumerable()
    .Select(x => { x.ContextKey = 30; return x; })
    .AsQueryable();

但请注意,这不是真正的 EF Core 可查询的,因此对它的进一步操作(如过滤、排序、分页等)将在内存中对AsEnumerable() 之前的查询的具体化结果执行。

【讨论】:

    【解决方案2】:

    我通过如下更新查询自己修复了它:

    public IQueryable<Relation> GetRelationsByConstructionId(Guid constructionId)
    {
        var links base.Get(x => x.Construction.ConstructionId == constructionId);
    
        var relations = links.Include(x => x.Relation)
                         .Select(x => x.Relation)
                         .Include(x => x.Person)
                         .Include(x => x.RelationType);
    
        relations.ToList().ForEach(x => x.ContextKey = 30);
    
        return relations;
    }
    

    【讨论】:

    • 但这更糟。关系查询(和相关)将执行两次 - 一次使用 ToList,另一次来自外部调用者。
    猜你喜欢
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-26
    • 2018-02-03
    • 2023-01-17
    • 2018-11-23
    相关资源
    最近更新 更多