[Table("Authors")]
public class Author
{
[PrimaryKey, Identity]
public int Id { get; set; }
[Column(CanBeNull = false)]
public string Name { get; set; }
}
[Table("Books")]
public class Book
{
[PrimaryKey, Identity]
public int Id { get; set; }
[Column(CanBeNull = false)]
public int AuthorId { get; set; }
[Column(CanBeNull = false)]
public string Title { get; set; }
}
Обращение к ним идёт через две переменные:
var authors = db.GetTable<Author>();
var books = db.GetTable<Book>();
Запрос
from author in authors
let booksCount =
(
from book in books
where book.AuthorId == author.Id
select Sql.Ext.Count(book.Id).ToValue()
).Single()
where booksCount > 42
select new
{
author.Name,
BooksCount = booksCount
}
генерирует следующий SQL код:
SELECT
[t3].[Name],
[t2].[c1] as [c11],
[t2].[c2] as [c21]
FROM
[Authors] [t3]
OUTER APPLY (
SELECT
COUNT([t1].[Id]) as [c1],
1 as [c2]
FROM
[Books] [t1]
WHERE
[t1].[AuthorId] = [t3].[Id]
) [t2]
WHERE
(
SELECT
COUNT([t4].[Id])
FROM
[Books] [t4]
WHERE
[t4].[AuthorId] = [t3].[Id]
) > 42
Запрос получается неестественный и, возможно, не оптимальный.
Запрос
from author in authors
let booksAgg =
(
from book in books
where book.AuthorId == author.Id
select new
{
Count = Sql.Ext.Count(book.Id).ToValue()
}
).Single()
where booksAgg.Count > 42
select new
{
author.Name,
BooksCount = booksAgg.Count
}
падает:
LinqToDB.Linq.LinqException: 'Table([Books]).Where(book => (book.AuthorId == <>h__TransparentIdentifier0.author.Id)).Select(book => new <>f__AnonymousType5`1(Count = Sql.Ext.Count(book.Id).ToValue())).Single().Count' cannot be converted to SQL.
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1029
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertCompare(IBuildContext context, ExpressionType nodeType, Expression left, Expression right) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1588
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertPredicate(IBuildContext context, Expression expression) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1370
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSearchCondition(IBuildContext context, Expression expression, List`1 conditions) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 2529
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildWhere(IBuildContext parent, IBuildContext sequence, LambdaExpression condition, Boolean checkForSubQuery, Boolean enforceHaving) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 48
at LinqToDB.Linq.Builder.WhereBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\WhereBuilder.cs:line 23
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 175
at LinqToDB.Linq.Builder.SelectBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectBuilder.cs:line 36
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 175
at LinqToDB.Linq.Builder.ExpressionBuilder.Build[T]() in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 146
at LinqToDB.Linq.Query`1.CreateQuery(IDataContext dataContext, Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 280
at LinqToDB.Linq.Query`1.GetQuery(IDataContext dataContext, Expression& expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 233
at LinqToDB.Linq.ExpressionQuery`1.GetQuery(Expression& expression, Boolean cache) in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 84
at LinqToDB.Linq.ExpressionQuery`1.get_SqlText() in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 53
at ConsoleApp.Program.WorkWithDb(DbMain db) in C:\Src\Personal\TestPolygon\ConsoleApp\Program.cs:line 68
at ConsoleApp.Program.WorkWithDb(String dataSource, String initialCatalog) in C:\Src\Personal\TestPolygon\ConsoleApp\Program.Db.cs:line 57
at ConsoleApp.Program.Main() in C:\Src\Personal\TestPolygon\ConsoleApp\Program.Core.cs:line 21
Если делать фильтрацию попозже:
var query =
from author in authors
let booksAgg =
(
from book in books
where book.AuthorId == author.Id
select new
{
Count = Sql.Ext.Count(book.Id).ToValue()
}
).Single()
select new
{
author.Name,
BooksCount = booksAgg.Count
};
query = query.Where(x => x.BooksCount > 42);
то падает с другим исключением:
System.NotImplementedException: The method or operation is not implemented.
at LinqToDB.Linq.Builder.SelectContext.ProcessMemberAccess[T](Expression expression, MemberExpression levelExpression, Int32 level, Func`6 action) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectContext.cs:line 974
at LinqToDB.Linq.Builder.SelectContext.IsExpressionInternal(Expression expression, Int32 level, RequestFor requestFlag) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectContext.cs:line 731
at LinqToDB.Linq.Builder.SelectContext.IsExpression(Expression expression, Int32 level, RequestFor requestFlag) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectContext.cs:line 627
at LinqToDB.Linq.Builder.ExpressionContext.IsExpression(Expression expression, Int32 level, RequestFor requestFlag) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionContext.cs:line 116
at LinqToDB.Linq.Builder.ExpressionBuilder.<>c__DisplayClass97_0.<CheckSubQueryForWhere>b__0(Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 90
at LinqToDB.Expressions.Extensions.Visit(Expression expr, Func`2 func) in C:\projects\linq2db\Source\LinqToDB\Expressions\Extensions.cs:line 373
at LinqToDB.Expressions.Extensions.Visit(Expression expr, Func`2 func) in C:\projects\linq2db\Source\LinqToDB\Expressions\Extensions.cs:line 418
at LinqToDB.Linq.Builder.ExpressionBuilder.CheckSubQueryForWhere(IBuildContext context, Expression expression, Boolean& makeHaving) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 149
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildWhere(IBuildContext parent, IBuildContext sequence, LambdaExpression condition, Boolean checkForSubQuery, Boolean enforceHaving) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 32
at LinqToDB.Linq.Builder.WhereBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\WhereBuilder.cs:line 23
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 175
at LinqToDB.Linq.Builder.ExpressionBuilder.Build[T]() in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 146
at LinqToDB.Linq.Query`1.CreateQuery(IDataContext dataContext, Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 280
at LinqToDB.Linq.Query`1.GetQuery(IDataContext dataContext, Expression& expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 233
at LinqToDB.Linq.ExpressionQuery`1.GetQuery(Expression& expression, Boolean cache) in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 84
at LinqToDB.Linq.ExpressionQuery`1.get_SqlText() in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 53
at ConsoleApp.Program.WorkWithDb(DbMain db) in C:\Src\Personal\TestPolygon\ConsoleApp\Program.cs:line 22
at ConsoleApp.Program.WorkWithDb(String dataSource, String initialCatalog) in C:\Src\Personal\TestPolygon\ConsoleApp\Program.Db.cs:line 56
at ConsoleApp.Program.Main() in C:\Src\Personal\TestPolygon\ConsoleApp\Program.Core.cs:line 21
Для меня больше важен вариант с
from book in books
where book.AuthorId == author.Id
select new
{
Count = Sql.Ext.Count(book.Id).ToValue()
}
потому что на практике надо считать по подзапросу не один агрегат, а несколько.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re: [linq2db bug] Исключение в запросе с OUTER APPLY
Здравствуйте, IT, Вы писали:
IT>Какая-то каша. Как должен выглядеть запрос на SQL?
Прошу прощения за сумбур!
Итак, сначала:
Есть две таблицы, «Authors» (авторы) и «Books» (книги):
[Table("Authors")]
public class Author
{
[PrimaryKey, Identity]
public int Id { get; set; }
[Column(CanBeNull = false)]
public string Name { get; set; }
}
[Table("Books")]
public class Book
{
[PrimaryKey, Identity]
public int Id { get; set; }
[Column(CanBeNull = false)]
public int AuthorId { get; set; }
[Column(CanBeNull = false)]
public string Title { get; set; }
}
Пытаемся получить количество книг по каждому автору.
Первый вариант запроса
linq2db:
from author in authors
let booksCount =
(
from book in books
where book.AuthorId == author.Id
select Sql.Ext.Count(book.Id).ToValue()
).Single()
where booksCount > 42
select new
{
author.Name,
BooksCount = booksCount
}
Работает, но генерирует неестественный и, возможно, не оптимальный SQL:
SELECT
[t3].[Name],
[t2].[c1] as [c11],
[t2].[c2] as [c21]
FROM
[Authors] [t3]
OUTER APPLY (
SELECT
COUNT([t1].[Id]) as [c1],
1 as [c2]
FROM
[Books] [t1]
WHERE
[t1].[AuthorId] = [t3].[Id]
) [t2]
WHERE
(
SELECT
COUNT([t4].[Id])
FROM
[Books] [t4]
WHERE
[t4].[AuthorId] = [t3].[Id]
) > 42
Я ожидал, что будет как-то так:
SELECT
Authors.Name,
BooksAggregates.Count
FROM
Authors
OUTER APPLY (
SELECT
COUNT(Books.Id) as Count
FROM
Books
WHERE
Books.AuthorId = Authors.Id
) BooksAggregates
WHERE
BooksAggregates.Count > 42
т.е. в WHERE не будет повторяться подзапрос из OUTER APPLY .
Второй вариант запроса
linq2db:
from author in authors
let booksAgg =
(
from book in books
where book.AuthorId == author.Id
select new
{
Count = Sql.Ext.Count(book.Id).ToValue()
}
).Single()
where booksAgg.Count > 42
select new
{
author.Name,
BooksCount = booksAgg.Count
}
Не работает, падает с ошибкой. Разница с первым вариантом только в том что для агрегата Count используется анонимный тип. Ожидаемый SQL — такой же что и в первом варианте.
Ошибка:
LinqToDB.Linq.LinqException: 'Table([Books]).Where(book => (book.AuthorId == <>h__TransparentIdentifier0.author.Id)).Select(book => new <>f__AnonymousType5`1(Count = Sql.Ext.Count(book.Id).ToValue())).Single().Count' cannot be converted to SQL.
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1029
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertCompare(IBuildContext context, ExpressionType nodeType, Expression left, Expression right) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1588
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertPredicate(IBuildContext context, Expression expression) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1370
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSearchCondition(IBuildContext context, Expression expression, List`1 conditions) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 2529
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildWhere(IBuildContext parent, IBuildContext sequence, LambdaExpression condition, Boolean checkForSubQuery, Boolean enforceHaving) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 48
at LinqToDB.Linq.Builder.WhereBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\WhereBuilder.cs:line 23
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 175
at LinqToDB.Linq.Builder.SelectBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectBuilder.cs:line 36
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 175
at LinqToDB.Linq.Builder.ExpressionBuilder.Build[T]() in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 146
at LinqToDB.Linq.Query`1.CreateQuery(IDataContext dataContext, Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 280
at LinqToDB.Linq.Query`1.GetQuery(IDataContext dataContext, Expression& expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 233
at LinqToDB.Linq.ExpressionQuery`1.GetQuery(Expression& expression, Boolean cache) in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 84
at LinqToDB.Linq.ExpressionQuery`1.get_SqlText() in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 53
at ConsoleApp.Program.WorkWithDb(DbMain db) in C:\Src\Personal\TestPolygon\ConsoleApp\Program.cs:line 68
at ConsoleApp.Program.WorkWithDb(String dataSource, String initialCatalog) in C:\Src\Personal\TestPolygon\ConsoleApp\Program.Db.cs:line 57
at ConsoleApp.Program.Main() in C:\Src\Personal\TestPolygon\ConsoleApp\Program.Core.cs:line 21
Третий вариант запроса
linq2db:
var query =
from author in authors
let booksAgg =
(
from book in books
where book.AuthorId == author.Id
select new
{
Count = Sql.Ext.Count(book.Id).ToValue()
}
).Single()
select new
{
author.Name,
BooksCount = booksAgg.Count
};
query = query.Where(x => x.BooksCount > 42);
Не работает, падает с ошибкой. Тут, как и во втором варианте, для агрегата Count используется анонимный тип. Фильтрация выполняется позже. Ожидаемый SQL — такой же что и в первом варианте.
Ошибка:
System.NotImplementedException: The method or operation is not implemented.
at LinqToDB.Linq.Builder.SelectContext.ProcessMemberAccess[T](Expression expression, MemberExpression levelExpression, Int32 level, Func`6 action) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectContext.cs:line 974
at LinqToDB.Linq.Builder.SelectContext.IsExpressionInternal(Expression expression, Int32 level, RequestFor requestFlag) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectContext.cs:line 731
at LinqToDB.Linq.Builder.SelectContext.IsExpression(Expression expression, Int32 level, RequestFor requestFlag) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectContext.cs:line 627
at LinqToDB.Linq.Builder.ExpressionContext.IsExpression(Expression expression, Int32 level, RequestFor requestFlag) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionContext.cs:line 116
at LinqToDB.Linq.Builder.ExpressionBuilder.<>c__DisplayClass97_0.<CheckSubQueryForWhere>b__0(Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 90
at LinqToDB.Expressions.Extensions.Visit(Expression expr, Func`2 func) in C:\projects\linq2db\Source\LinqToDB\Expressions\Extensions.cs:line 373
at LinqToDB.Expressions.Extensions.Visit(Expression expr, Func`2 func) in C:\projects\linq2db\Source\LinqToDB\Expressions\Extensions.cs:line 418
at LinqToDB.Linq.Builder.ExpressionBuilder.CheckSubQueryForWhere(IBuildContext context, Expression expression, Boolean& makeHaving) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 149
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildWhere(IBuildContext parent, IBuildContext sequence, LambdaExpression condition, Boolean checkForSubQuery, Boolean enforceHaving) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 32
at LinqToDB.Linq.Builder.WhereBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\WhereBuilder.cs:line 23
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 175
at LinqToDB.Linq.Builder.ExpressionBuilder.Build[T]() in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 146
at LinqToDB.Linq.Query`1.CreateQuery(IDataContext dataContext, Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 280
at LinqToDB.Linq.Query`1.GetQuery(IDataContext dataContext, Expression& expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 233
at LinqToDB.Linq.ExpressionQuery`1.GetQuery(Expression& expression, Boolean cache) in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 84
at LinqToDB.Linq.ExpressionQuery`1.get_SqlText() in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 53
at ConsoleApp.Program.WorkWithDb(DbMain db) in C:\Src\Personal\TestPolygon\ConsoleApp\Program.cs:line 22
at ConsoleApp.Program.WorkWithDb(String dataSource, String initialCatalog) in C:\Src\Personal\TestPolygon\ConsoleApp\Program.Db.cs:line 56
at ConsoleApp.Program.Main() in C:\Src\Personal\TestPolygon\ConsoleApp\Program.Core.cs:line 21
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[3]: [linq2db bug] Исключение в запросе с OUTER APPLY
Здравствуйте, Петрухин Эдуард, Вы писали:
ПЭ>Здравствуйте, IT, Вы писали:
IT>>Какая-то каша. Как должен выглядеть запрос на SQL?
ПЭ>Прошу прощения за сумбур!
ПЭ>Итак, сначала: ПЭ>Есть две таблицы, «Authors» (авторы) и «Books» (книги): ПЭ>
ПЭ>[Table("Authors")]
ПЭ>public class Author
ПЭ>{
ПЭ> [PrimaryKey, Identity]
ПЭ> public int Id { get; set; }
ПЭ> [Column(CanBeNull = false)]
ПЭ> public string Name { get; set; }
ПЭ>}
ПЭ>[Table("Books")]
ПЭ>public class Book
ПЭ>{
ПЭ> [PrimaryKey, Identity]
ПЭ> public int Id { get; set; }
ПЭ> [Column(CanBeNull = false)]
ПЭ> public int AuthorId { get; set; }
ПЭ> [Column(CanBeNull = false)]
ПЭ> public string Title { get; set; }
ПЭ>}
ПЭ>
ПЭ>Пытаемся получить количество книг по каждому автору.
Э-э-э, а такие сложности точно нужны ??
var result =
from author in db.GetTable<Author>()
from book in db.GetTable<Book>().InnerJoin(b => b.AuthorId == author.Id)
group book by new {author.Id, author.Name}
into gr
select new {AuthorId = gr.Key.Id, AuthorName = gr.Key.Name, BookCount = gr.Count()}
генерирует вполне ожидаемый запрос
SELECT
t2.Id,
t2.Name,
Count(*) as c1
FROM
Authors t2
INNER JOIN Books t1 ON t1.AuthorId = t2.Id
GROUP BY
t2.Id,
t2.Name
Re[4]: [linq2db bug] Исключение в запросе с OUTER APPLY
Здравствуйте, Jack128, Вы писали:
J>Э-э-э, а такие сложности точно нужны ??
В данном примере конечно не нужны, но это только сокращённый пример кода, на котором ошибка воспроизводится. В реальности там не одна таблица «Authors», а соединение нескольких таблиц; и агрегатов несколько считается (не один); и данные для построения агрегатов через EXISTS отбираются; и фильтрация по агрегату выполняется, только если на UI соответсвующий фильтр задан. При таком подходе, как в моём примере, проще запрос по кускам строить.
К сожалению, не могу сюда добавить реальный пример, из рабочего кода.
Как я понимаю, проблема в том что не может linq2db построить запрос, в котором идёт фильтрация по данным из OUTER APPLY.
Разработчики linq2db, могу надеятся, что повяится поддержка таких запросов?
Может, какие-то неясности ещё остались?
Может, issue на GitHub завести?
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[5]: [linq2db bug] Исключение в запросе с OUTER APPLY
Здравствуйте, Петрухин Эдуард, Вы писали:
ПЭ>Здравствуйте, Jack128, Вы писали:
J>>Э-э-э, а такие сложности точно нужны ??
ПЭ>В данном примере конечно не нужны, но это только сокращённый пример кода, на котором ошибка воспроизводится. В реальности там не одна таблица «Authors», а соединение нескольких таблиц; и агрегатов несколько считается (не один); и данные для построения агрегатов через EXISTS отбираются; и фильтрация по агрегату выполняется, только если на UI соответсвующий фильтр задан. При таком подходе, как в моём примере, проще запрос по кускам строить. ПЭ>К сожалению, не могу сюда добавить реальный пример, из рабочего кода.
ПЭ>Как я понимаю, проблема в том что не может linq2db построить запрос, в котором идёт фильтрация по данным из OUTER APPLY.
ПЭ>Разработчики linq2db, могу надеятся, что повяится поддержка таких запросов? ПЭ>Может, какие-то неясности ещё остались? ПЭ>Может, issue на GitHub завести?
Да все можно, только времени свободного на это нет. К примеру такие запросы как вы пишете, я иногда сам не понимаю как оттранслировать в SQL.
Начинайте писать терминами SQL и все будет нормально. let — это вам кажется что его легко оттранслировать, но когда дальше начинается с этой переменной возня, это кошмар.
Re[5]: [linq2db bug] Исключение в запросе с OUTER APPLY
Здравствуйте, Петрухин Эдуард, Вы писали:
ПЭ>Здравствуйте, Jack128, Вы писали:
J>>Э-э-э, а такие сложности точно нужны ??
ПЭ>В данном примере конечно не нужны, но это только сокращённый пример кода, на котором ошибка воспроизводится. В реальности там не одна таблица «Authors», а соединение нескольких таблиц; и агрегатов несколько считается (не один); и данные для построения агрегатов через EXISTS отбираются; и фильтрация по агрегату выполняется, только если на UI соответсвующий фильтр задан. При таком подходе, как в моём примере, проще запрос по кускам строить. ПЭ>К сожалению, не могу сюда добавить реальный пример, из рабочего кода.
ПЭ>Как я понимаю, проблема в том что не может linq2db построить запрос, в котором идёт фильтрация по данным из OUTER APPLY.
ПЭ>Разработчики linq2db, могу надеятся, что повяится поддержка таких запросов? ПЭ>Может, какие-то неясности ещё остались? ПЭ>Может, issue на GitHub завести?
Желательно сюда кинуть запрос который строите с максимальной сложностью. Дабы понять что творится.
Re[3]: [linq2db bug] Исключение в запросе с OUTER APPLY
Здравствуйте, Петрухин Эдуард, Вы писали:
ПЭ>Пытаемся получить количество книг по каждому автору.
from a in authors
select new
{
a.Name,
Count = (from b in books where b.AuthorId == a.Id select b).Count()
} into a
where a.Count > 42
select a
SELECT
[a].[Name] as [Name1],
[a].[c1] as [c11]
FROM
(
SELECT
(
SELECT
Count(*)
FROM
[Books] [t1]
WHERE
[t1].[AuthorId] = [t2].[Id]
) as [c1],
[t2].[Name]
FROM
[Authors] [t2]
) [a]
WHERE
[a].[c1] > 42
Если нам не помогут, то мы тоже никого не пощадим.
Re: [linq2db bug] Исключение в запросе с OUTER APPLY
ПЭ>from book in books
ПЭ>where book.AuthorId == author.Id
ПЭ>select new
ПЭ>{
ПЭ> Count = Sql.Ext.Count(book.Id).ToValue()
ПЭ>}
ПЭ>
ПЭ>потому что на практике надо считать по подзапросу не один агрегат, а несколько.
Проанализировал я — дело непростое. То как вы записали выражение, это еще парсать и парсать.
Я записал его вот так, и все корректно. И блоками тоже можно достраивать.
var aggregates = from book in db.GetTable<Book>()
select new
{
book.AuthorId,
RN = Sql.Ext.RowNumber().Over().OrderBy(book.AuthorId).ToValue(),
BooksCount = Sql.Ext.Count(book.Id).Over().PartitionBy(book.AuthorId).ToValue(),
Count2 = Sql.Ext.Count(book.Title).Over().PartitionBy(book.AuthorId).ToValue(),
};
aggregates = aggregates.Where(a => a.RN == 1);
var query = from author in db.GetTable<Author>()
from a in aggregates.InnerJoin(a => a.AuthorId == author.Id)
where a.BooksCount > 42
select new
{
author.Name,
BooksCount = a.BooksCount
};
Если дадите сценарий более четко с типами запросов что будут, можно и солюшин придумать.
Клеить, напрмер можно так
int? minBookCount = 42;
int? minBookCount2 = null;
var query = from author in db.GetTable<Author>()
select new
{
Author = author,
BookCount = (from book in db.GetTable<Book>()
where book.AuthorId == author.Id
select book).CountExt(b => b.Id, Sql.AggregateModifier.None),
BookCount2 = (from book in db.GetTable<Book>()
where book.AuthorId == author.Id
select book).CountExt(b => b.Id, Sql.AggregateModifier.None)
};
if (minBookCount != null)
{
query = query.Where(b => b.BookCount > minBookCount);
}
if (minBookCount2 != null)
{
query = query.Where(b => b.BookCount2 > minBookCount2);
}
var resultQuery = from author in query
select new
{
author.Author.Name,
author.BookCount
};
Тоесть задаем все возможные поля фильтра в первом запросе, а потом используем только части. linq2db лишнее откинет.