>>> a = "545.2222"
>>> float(a)
545.22220000000004
>>> int(float(a))
545
Вы должны быть очень осторожны с передачей IQueryables при использовании DataContext, потому что, как только контекст будет удален, вы больше не сможете выполнять этот IQueryable. Если вы не используете контекст, возможно, все в порядке, но имейте в виду.
.Any () и .FirstOrDefault () не отложены. Когда вы вызываете их, они вызывают выполнение. Однако это может не сделать то, что вы думаете. Например, в LINQ to SQL, если вы выполняете .Any () для IQueryable, он в основном действует как IF EXISTS (SQL HERE).
Вы можете связать IQueryable следующим образом, если хотите:
var firstQuery = from f in context.Foos
where f.Bar == bar
select f;
var secondQuery = from f in firstQuery
where f.Bar == anotherBar
orderby f.SomeDate
select f;
if (secondQuery.Any()) //immediately executes IF EXISTS( second query in SQL )
{
//causes execution on second query
//and allows you to enumerate through the results
foreach (var foo in secondQuery)
{
//do something
}
//or
//immediately executes second query in SQL with a TOP 1
//or something like that
var foo = secondQuery.FirstOrDefault();
}
Намного лучший вариант, чем кэширование объектов IQueryable, - это кэширование деревьев выражений. Все объекты IQueryable имеют свойство Expression (я полагаю), которое представляет текущее дерево выражений для этого запроса.
Позже вы можете воссоздать запрос, вызвав queryable.Provider.CreateQuery (выражение) или непосредственно на любом провайдере (в вашем случае это Linq2Sql Data Context).
Параметризация этих деревьев выражений немного сложнее, так как они используют ConstantExpressions для построения значения. Чтобы параметризовать эти запросы, вам придется перестраивать запрос каждый раз, когда вам нужны другие параметры.
Any ()
, используемый таким образом, откладывается.
var q = dc.Customers.Where(c => c.Orders.Any());
Any ()
, используемый таким образом, не откладывается, но по-прежнему транслируется в SQL (вся таблица клиентов не загружается в память).
bool result = dc.Customers.Any();
Если вам нужен отложенный Any (), сделайте это следующим образом:
public static class QueryableExtensions
{
public static Func<bool> DeferredAny<T>(this IQueryable<T> source)
{
return () => source.Any();
}
}
Что называется так:
Func<bool> f = dc.Customers.DeferredAny();
bool result = f();
Обратной стороной является то, что этот метод не позволяет выполнять подзапросы.
Создайте частичное применение вашего запроса внутри выражения
Func[Bar,IQueryable[Blah],IQueryable[Foo]] queryMaker =
(criteria, queryable) => from foo in queryable.Foos
where foo.Bar == criteria
select foo;
, а затем вы можете использовать его с помощью ...
IQueryable[Blah] blah = context.Blah;
Bar someCriteria = new Bar();
IQueryable[Foo] someFoosQuery = queryMaker(blah, someCriteria);
Запрос может быть инкапсулирован в класс, если вы хотите сделать это более портативный / многоразовый.
public class FooBarQuery
{
public Bar Criteria { get; set; }
public IQueryable[Foo] GetQuery( IQueryable[Blah] queryable )
{
return from foo in queryable.Foos
where foo.Bar == Criteria
select foo;
}
}