Existe uma razão específica para que o expansor do LinqKit não consiga captar expressões dos campo
Estou a usar LinqKit biblioteca que permite combinar expressões em tempo rea
Esta é uma alegria pura para escrever a camada de acesso a dados do Entity Framewok, porque várias expressões podem opcionalmente ser reutilizadas e combinadas, o que permite um código legível e eficient
Considere o seguinte trecho de código:
private static readonly Expression<Func<Message, int, MessageView>> _selectMessageViewExpr =
( Message msg, int requestingUserId ) =>
new MessageView
{
MessageID = msg.ID,
RequestingUserID = requestingUserId,
Body = ( msg.RootMessage == null ) ? msg.Body : msg.RootMessage.Body,
Title = ( ( msg.RootMessage == null ) ? msg.Title : msg.RootMessage.Title ) ?? string.Empty
};
Declaramos uma expressão que projetaMessage
paraMessageView
(Removi os detalhes para maior clareza
Agora, o código de acesso a dados pode usar esta expressão para obter mensagens individuais:
var query = CompiledQueryCache.Instance.GetCompiledQuery(
"GetMessageView",
() => CompiledQuery.Compile(
_getMessagesExpr
.Select( msg => _selectMessageViewExpr.Invoke( msg, userId ) ) // re-use the expression
.FirstOrDefault( ( MessageView mv, int id ) => mv.MessageID == id )
.Expand()
)
);
Isso é lindo porque a mesma expressão pode ser reutilizada para obter uma lista de mensagens:
var query = CompiledQueryCache.Instance.GetCompiledQuery(
"GetMessageViewList",
() => CompiledQuery.Compile(
BuildFolderExpr( folder )
.Select( msg => _selectMessageViewExpr.Invoke( msg, userId ) )
.OrderBy( mv => mv.DateCreated, SortDirection.Descending )
.Paging()
.Expand()
),
folder
);
Como você pode ver, a expressão de projeção é armazenada em_selectMessageViewExpr
e é usado para criar várias consultas diferente
No entanto, passei muito tempo rastreando um erro estranho ondeeste código falhou emExpand()
liga.
O erro disse:
Não foi possível converter o objeto do tipoSystem.Linq.Expressions.FieldExpression
digitarSystem.Linq.Expressions.LambdaExpression
.
Só depois de um tempo eu percebi quetudo funciona quando a expressão é referenciada em uma variável local antes de ser chamadaInvoke
e:
var selector = _selectMessageViewExpr; // reference the field
var query = CompiledQueryCache.Instance.GetCompiledQuery(
"GetMessageView",
() => CompiledQuery.Compile(
_getMessagesExpr
.Select( msg => selector.Invoke( msg, userId ) ) // use the variable
.FirstOrDefault( ( MessageView mv, int id ) => mv.MessageID == id )
.Expand()
)
);
Est código @ funciona como esperad
Minha pergunta é
Existe algum motivo específico para o LinqKit não reconhecerInvoke
em expressões armazenadas em campos? É apenas uma omissão do desenvolvedor, ou há algum motivo importante pelo qual as expressões precisam ser armazenadas nas variáveis locais primeir
Esta pergunta provavelmente pode ser respondida consultando o código gerado e verificando as fontes do LinqKit, no entanto, pensei que talvez alguém relacionado ao desenvolvimento do LinqKit pudesse responder a essa pergunt
Obrigado