簡體   English   中英

EF Core 5 - LINQ 無法翻譯

[英]EF Core 5 - LINQ cannot be translated

好吧,我知道這有很多問題,但我還沒有找到我的問題的答案。

我在實體類中有規則:

class 事件:

public virtual ICollection<Sessao> Sessao { get; set; }
public bool Ativo()
{
    return DataPublicacao <= DateTime.Today
                   && (!DataFim.HasValue || DataFim.Value >= DateTime.Today)
                   && Sessao.Any(sessao => sessao.Ativa());
}

class Sessao:

public bool Ativa() => Status == StatusSessao.Ativa && (Recorencia && DataInicio <= DateTime.Today || (!Recorencia && DataInicio <= DateTime.Today && DataFim >= DateTime.Today));
//I had try to put DateTime.Today in a variable, but same exception

LINQ 代碼:

var cardsEventos = await Consulta //DbSet<Evento>
            .Include(x => x.Sessao)
            .Where(ev => ev.Ativo())
            .Where(x => x.Destaque) //...

調用該方法時,它會拋出帶有該消息的異常:

System.InvalidOperationException: The LINQ expression 'DbSet<Evento>()
    .Where(e => e.Ativo())' could not be translated.

但是,如果我將相同的規則直接放在 linq 上,它就可以工作。

軟件其他部分的所有規則都是相同的,所以我認為這些規則只有一個失敗點,我該怎么做?

我建議使用LINQKit 它需要配置DbContextOptions

builder
    .UseSqlServer(connectionString) // or any other Database Provider
    .WithExpressionExpanding();     // enabling LINQKit extension

按以下方式定義您的方法。 我們只需要他們的表達式樹:

class Evento
{
    ... // other  properties 

    public virtual ICollection<Sessao> Sessao { get; set; }

    [Expandable(nameof(ActivoImpl))]
    public bool Ativo()
    {
        throw new InvalidOperationException("Server side only method");
    }

    // this method will be invoked by LINKQKit and LambdaExpression 
    // will be injected into final Expression Tree before passing to EF Core
    private static Expression<Func<Evento, bool>> ActivoImpl()
    {
        // for instance methods `this` is represented as first lambda parameter 
        return evento => evento.DataPublicacao <= DateTime.Today
            && (!evento.DataFim.HasValue || evento.DataFim.Value >= DateTime.Today)
            && evento.Sessao.Any(sessao => sessao.Ativa());
    }
}
class Sessao
{
    ... // other  properties 

    [Expandable(nameof(ActivaImpl))]
    public bool Ativa()
    {
        throw new InvalidOperationException("Server side only method");
    }

    private static Expression<Func<Sessao, bool>> ActivaImpl()
    {
        return sessao => sessao.Status == StatusSessao.Ativa 
            && (sessao.Recorencia && sessao.DataInicio <= DateTime.Today 
                || (!sessao.Recorencia && sessao.DataInicio <= DateTime.Today && sessao.DataFim >= DateTime.Today)
            );
    }
}

然后您的 LINQ 查詢應該可以在沒有任何更改的情況下工作:

var cardsEventos = await Consulta //DbSet<Evento>
    .Include(x => x.Sessao)
    .Where(ev => ev.Ativo())
    .Where(x => x.Destaque)

您可能希望將代碼重寫為

LINQ 代碼:

var ativa = sessao.Ativa();  
var cardsEventos = await Consulta //DbSet<Evento>
            .Include(x => x.Sessao)
            .Where(ev => DataPublicacao <= DateTime.Today
                   && (!DataFim.HasValue || DataFim.Value >= DateTime.Today)
                   && Sessao.Any(sessao => ativa))
            .Where(x => x.Destaque)

只需替換所需的代碼以顯示需要進行的更改。 OP 可能需要根據需要重新調整變量和屬性。

Linq 到實體不允許方法,因為所有條件都需要映射到 SQL 等效項,對於 C# 方法沒有。

如果您在變量中獲取返回值並在查詢中使用這些變量,則會更容易。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM