Как сделать Exists с помощью Dynamic Linq

Как сделать так, чтобы существовал с динамическим LINQ?

Я пытаюсь создать предложение SQL с динамическим LINQ. Я много исследовал и не нашел удовлетворительного ответа.

Я пытаюсь преобразовать запрос SQL следующим образом:

SQL

select * from Documento where exists(
    select 1 from Titulo
    where Documento.codDocumento = Titulo.codDocumento
    and Documento.codEmpresa = Titulo.codEmpresaDocumento
    and Titulo.codFluxoConta = 'SomeValue'
    and Titulo.codEmpresaFluxoConta = 'StringNumerical')

В общем LINQ я сделал следующее:

var subquery2 = from T in db.Titulos
    where T.codFluxoConta == "SomeValue"
    && T.codEmpresaFluxoConta == "StringNumerical"
    select new {
        codDoc = (int?)T.codDocumento,
        codEmp = (string)T.codEmpresaDocumento
    };

var query2 = from D in db.Documentos
    where subquery2.Contains(new { codDoc = (int?)D.codDocumento, codEmp = (string)D.codEmpresa })
    select new{
        D.codDocumento,
        D.codEmpresa
    };

или же

var query4 = db.Documentos.Where(d =>
(db.Titulos.Where(t => t.codFluxoConta == "SomeValue" && t.codEmpresaFluxoConta == "StringNumerical").Select(t2 => new { codDoc = (int?)t2.codDocumento, codEmp = (string)t2.codEmpresaDocumento })).Contains(new { codDoc = (int?)d.codDocumento, codEmp = (string)d.codEmpresa }));

И это то, что я сделал со своими знаниями

IQueryable linq = db.Set(T);
var exists = linq.Where("codFluxoConta == @0 && codEmpresaFluxoConta == @1", "SomeValue", "StringNumerical").Select("new(\"codDocumento\" as codDoc, \"codEmpresaDocumento\" as codEmp)");
var query = db.Documentos.Where("@0.Contains(new (it[\"codDocumento\"] as codDocumento, it[\"codEmpresa\"] as codEmpresaDocumento))", exists);

Но когда я выполняю этот код, возникает следующее исключение:

Применимый индексатор не существует в типе "DynamicClass3".

2 ответа

Решение

Это похоже на работу... Он использует outerIt... и я не знаю, через какую магию Any внутри Where() работает...

var sq = titulo.Where("codFluxoConta == @0 && codEmpresaFluxoConta == @1", "SomeValue", "StringNumerical");
var result = documento.Where("@0.Any(it.codDocumento == outerIt.codDocumento && it.codEmpresaDocumento == outerIt.codEmpresaDocumento)", sq)
    .Select("new(codDocumento, codEmpresaDocumento)");

в Where(), it является элементом подзапроса, в то время как outerIt это documento,

Я проверил с помощью SQL Profiler, и результат запроса:

SELECT 
    [Extent1].[codDocumento] AS [codDocumento], 
    [Extent1].[codEmpresaDocumento] AS [codEmpresaDocumento]
    FROM [dbo].[Documento] AS [Extent1]
    WHERE  EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[Titulo] AS [Extent2]
        WHERE (N'SomeValue' = [Extent2].[codFluxoConta]) AND (N'StringNumerical' = [Extent2].[codEmpresaFluxoConta]) AND ([Extent2].[codDocumento] = [Extent1].[codDocumento]) AND ([Extent2].[codEmpresaDocumento] = [Extent1].[codEmpresaDocumento])
    )

это эквивалентно вашему запросу.

Обратите внимание, что в Dynamic Linq даже можно написать запрос, очень похожий на тот, который вы написали в Linq, используя .Contains() (но учтите, что я предпочитаю .Any() к .Contains()). Два запроса производят один и тот же SQL-запрос с Entity Framework.

var sq2 = db.Titulo.Where("codFluxoConta == @0 && codEmpresaFluxoConta == @1", "SomeValue", "StringNumerical")
    .Select("new(codDocumento, codEmpresaDocumento)");
var result2 = db.Documento.Where("@0.Contains(new(outerIt.codDocumento, outerIt.codEmpresaDocumento))", sq2)
    .Select("new(codDocumento as codDoc, codEmpresaDocumento as codEmp)");

Любой () ( https://msdn.microsoft.com/en-us/library/vstudio/bb534972%28v=vs.100%29.aspx) - это то, на чем вы должны сосредоточиться. Any() вернет True, если if сможет найти хотя бы один элемент в коллекции, который удовлетворяет заданному предикату.

У меня нет VS, чтобы проверить это, но это должно работать для вас.

db.Documento.Where(d => 
  db.Titulos.Any(t => 
    t.codDocumento == d.codDocumento &&
    t.codEmpresaDocumento == d.codEmpresa && 
    t.codFluxoConta == "" && 
    t.codEmpresaFloxoConta == ""
  )
);

Будьте осторожны, так как вы, вероятно, используете переменные для сравнения с codFluxoConta и codEmpresaFloxoConta, он не будет читать значения для оператора, пока вы не выполните запрос ( http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx). Так что, если вы запускаете это с другими значениями (как в цикле) и сохраняете результат, убедитесь, что.ToList() или что-то еще, прежде чем значение изменится.

Другие вопросы по тегам