Здравствуйте, Димчанский, Вы писали:
Д>A можно ли в BLToolkit использовать динамически генерируемые предикаты (в виде Expression)? Как в L2S это делают.
Любой предикат и так динамический
... << RSDN@Home 1.2.0 alpha 4 rev. 1464 on Windows 7 6.1.7600.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Любой предикат и так динамический
Т.е., как я понимаю, во второй параметр в Expressions.MapMember передается просто Expression?
static decimal? RoundToEven(decimal? value)
{
throw new NotImplementedException();
}
static void RoundToEvenTest()
{
Expressions.MapMember<decimal?,decimal?>(
value => RoundToEven(value),
value =>
value - Sql.Floor(value) == 0.5m && Sql.Floor(value) % 2 == 0?
Sql.Floor(value) :
Sql.Round(value));
using (var db = new NorthwindDB())
{
var query =
from o in db.Order
let sum = o.OrderDetails.Sum(d => d.Quantity * d.UnitPrice)
where RoundToEven(sum) >= 10
select o.Freight;
foreach (var item in query)
{
Console.WriteLine(item);
}
}
}
Здравствуйте, IT, Вы писали:
IT>Да. При нахождении RoundToEven в запросе он будет заменён на соответствующее выражение.
Тогда возникает вопрос с многопоточностью.
Т.е., к примеру, я хочу формировать предикат на выборку объектов в зависимости от условий поиска, которые ввел пользователь. Таким образом для каждого пользователя должен генерироваться свой предикат.
Как реализовать такой сценарий? Ведь, на сколько я понимаю, Expressions.MapMember — это регистрация замены выражения, которая будет работать глобально.
Здравствуйте, Димчанский, Вы писали:
Д>Как реализовать такой сценарий? Ведь, на сколько я понимаю, Expressions.MapMember — это регистрация замены выражения, которая будет работать глобально.
Именно. Тот вариант, который ты привёл по ссылке должен работать и без этого. Точно так же как и для L2S.
Если нам не помогут, то мы тоже никого не пощадим.
Re: Linq with BLToolkit
От:
Аноним
Дата:
10.04.10 07:25
Оценка:
Здравствуйте.
Прочитал статью, впечатляет объем и профессионализм проделанной работы. Лёгкость BLT — именно то, что я искал. Но вот в результате просмотра примеров из статьи возник вопрос: в листинге сгенерированного SQL все константы перешли в константы — это на самом деле так происходит, или же всё таки используются параметры? Тот же L2S везде пихает параметры (имеется в виду SqlParameter("@p1", 5)) для оптимизации и безопасности запросов к БД, а как это устроено внутри BLT?
Здравствуйте, Аноним, Вы писали:
А>Но вот в результате просмотра примеров из статьи возник вопрос: в листинге сгенерированного SQL все константы перешли в константы — это на самом деле так происходит, или же всё таки используются параметры?
Константы преобразуются в константы. Параметры в параметры. Существуют случаи, когда для некоторых провайдеров константы преобразуются в параметры, а параметры в константы. Это связано с совместимостью провайдеров.
А>Тот же L2S везде пихает параметры (имеется в виду SqlParameter("@p1", 5)) для оптимизации и безопасности запросов к БД, а как это устроено внутри BLT?
О какой оптимизации речь? Насчёт безопасности, если речь идёт об SQL injection, то с этим всё впорядке, да и программист, написавший такой код сам себе злобный буратино.
Если нам не помогут, то мы тоже никого не пощадим.
Только начинаю пользоваться BLT, и уже сразу с Linq . Увидел, что после выполнения Linq запроса подключение к БД остаётся открытым. Вопрос: можно ли как-то настроить MyDbManager так, чтобы он закрывал подключение автоматически, без вызова Dispose, а по завершении запроса?
Здравствуйте, Димчанский, Вы писали:
Д>A можно ли в BLToolkit использовать динамически генерируемые предикаты (в виде Expression)? Как в L2S это делают.
Здравствуйте!
Пробую с BLT выполнить следующую вещь:
((IQueryProvider)GetBltContext().GetTable<T>()).CreateQuery<T>(expression)
где expression это Expression<Func<T, bool>> expression.
Это кусок метода
public T GetSingle<T>(Expression<Func<T, bool>> expression) where T : class
{
IQueryable<T> queryable = ((IQueryProvider)GetBltContext().GetTable<T>()).CreateQuery<T>(expression);
var list = queryable.ToList();
return queryable.FirstOrDefault();
}
Соответствующий вызов, например,
GetSingle<Customer>(c => c.CustomerID == "NEWCS")
(это для базы Northwind)
При выполнении такого кода ловиться исключение System.ArgumentException: Queryable method call expected. Got 'c => (c.CustomerID == "NEWCS")'. Блуждание в дебаггере привело к мысли, что в качестве рутового узла при разборе дерева поддерживается только MemberAccess или Call или Parameter, но никак не Lambda...
Статью Игоря про Linq в BLT прочитал, но наверное не все/не так понял... Так или иначе непонятно, почему не обрабатывается такое выражение/что я делаю не так. EF4 и LinqToSql такие вещи проглатывают на счет раз.
Здравствуйте, ghostknight83, Вы писали:
G>Здравствуйте, Димчанский, Вы писали:
Д>>A можно ли в BLToolkit использовать динамически генерируемые предикаты (в виде Expression)? Как в L2S это делают. G>
G> public T GetSingle<T>(Expression<Func<T, bool>> expression) where T : class
G> {
G> IQueryable<T> queryable = ((IQueryProvider)GetBltContext().GetTable<T>()).CreateQuery<T>(expression);
G> var list = queryable.ToList();
G> return queryable.FirstOrDefault();
G> }
G>
Если конкретно этот пример — то он реализуется просто
G>При выполнении такого кода ловиться исключение System.ArgumentException: Queryable method call expected. Got 'c => (c.CustomerID == "NEWCS")'. Блуждание в дебаггере привело к мысли, что в качестве рутового узла при разборе дерева поддерживается только MemberAccess или Call или Parameter, но никак не Lambda...
Потому, что анализатор ищет экспрешены вызовов методов IQuerable<T> — Where, Select, Single, etc.
Я имею в виду если параллельно с полями таблицы надо еще вернуть значение хранимой функции, т.е. типа SELECT Field1, Field2, MyFunc(Field3) FROM mytable;
Здравствуйте, MozgC, Вы писали:
MC>Я имею в виду если параллельно с полями таблицы надо еще вернуть значение хранимой функции, т.е. типа SELECT Field1, Field2, MyFunc(Field3) FROM mytable;
Можно. См. Расширение BLToolkit. SQL функции.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Можно. См. Расширение BLToolkit. SQL функции.
Прокопался полчаса.. что-то не получается как я хочу.
Во-первых, я так понял, что нельзя сделать одну функцию на все хранимые функции (т.е. чтобы можно было просто название ХП указывать и параметры)?
Во-вторых, у меня не получается по-простому вернуть поля + значение хранимой функции, т.к. свойству анонимного класса нельзя указать значение типа Sql.MyFunc(customer.ID). Если использовать let, например так:
var q = from c in db.GetTable<Customer>()
let balance = MySql.GetCustomerBalance(c.ID)
select new {c.ID, c.Name, balance};
то получаю исключение "'c.ID' cannot be converted to SQL."
Хочется же как-то так (в идеале):
var q = from c in db.GetTable<Customer>() select new { c.Name, MySql.GetCustomerBalance(c.ID) };
Здравствуйте, MozgC, Вы писали:
MC>Во-первых, я так понял, что нельзя сделать одну функцию на все хранимые функции (т.е. чтобы можно было просто название ХП указывать и параметры)?
Можно. Но придётся создать несколько таких функций по числу параметров и определиться с типом возвращаемого значения.
[SqlExpression("{0}({1})", 0, 1, ServerSideOnly=true)]
public static T SqlFunction<T>(string functionName, T p1)
{
return p1;
}
[SqlExpression("{0}({1}, {2})", 0, 1, 2, ServerSideOnly=true)]
public static T SqlFunction<T1,T2>(string functionName, T p1, T2 p2)
{
return obj;
}
MC>Во-вторых, у меня не получается по-простому вернуть поля + значение хранимой функции, т.к. свойству анонимного класса нельзя указать значение типа Sql.MyFunc(customer.ID). Если использовать let, например так:
MC>
var q = from c in db.GetTable<Customer>()
MC> let balance = MySql.GetCustomerBalance(c.ID)
MC> select new {c.ID, c.Name, balance};
MC>то получаю исключение "'c.ID' cannot be converted to SQL."
MC>Хочется же как-то так (в идеале):
MC>
var q = from c in db.GetTable<Customer>() select new { c.Name, MySql.GetCustomerBalance(c.ID) };
А как ты GetCustomerBalance объявлял? Нужно как-то так:
[SqlFunction(ServerSideOnly=true)]
public static double GetCustomerBalance(int ID)
{
throw new NotInplementedException();
}
Если нам не помогут, то мы тоже никого не пощадим.
public static class MySql
{
[SqlExpression("{0}({1})", 0, 1, ServerSideOnly = true)]
public static TResult StoredFunction<TResult, TParameter>(string functionName, TParameter parameter)
{
throw new NotImplementedException();
}
}
var q = from c in db.GetTable<Customer>()
let func = MySql.StoredFunction<double, int>("GetCustomerBalance", c.ID)
select new {c.ID, c.Name, func};
Тут выпадает исключение "'c.ID' cannot be converted to SQL."
Если избавиться от let, т.е. написать например так:
var q = from c in db.GetTable<Customer>()
select new Pair(c.Name, MySql.StoredFunction<double, int>("GetCustomerBalance", c.ID));
То получаем такой SQL:
SELECT
c.Name,
'GetCustomerBalance'(c.ID) as c1
FROM
customers c
Здравствуйте, MozgC, Вы писали:
MC>Тут выпадает исключение "'c.ID' cannot be converted to SQL."
Это скорее всего бага.
MC>Если избавиться от let, т.е. написать например так: MC>
var q = from c in db.GetTable<Customer>()
MC> select new Pair(c.Name, MySql.StoredFunction<double, int>("GetCustomerBalance", c.ID));
MC>То получаем такой SQL: MC>
SELECT
MC> c.Name,
MC> 'GetCustomerBalance'(c.ID) as c1
MC>FROM
MC> customers c
MC>ну и соответственно ошибку в синтаксисе запроса.
Да, точно. Строка будет рассмотрена как значение и заключена в кавычки. Тогда только наследование от SqlExpressionAttribute с перекрытием метода GetExpression.
Если нам не помогут, то мы тоже никого не пощадим.