I wrote a method that extends System.Linq class. My ContainsAnyWord method allows me to search all words in a string against a string instead of comparing one string to another.
Here is the method that I wrote to extend Linq
public static class LinqExtension
{
public static bool ContainsAnyWord(this string value, string searchFor)
{
if (!string.IsNullOrWhiteSpace(value) && !string.IsNullOrWhiteSpace(searchFor))
{
value = value.ToLower();
IEnumerable<string> tags = StopwordTool.GetPossibleTags(searchFor);
return tags.Contains(value);
}
return false;
}
}
This extension method works great on an IEnumerable object. But when I want to use it on IQueryable object I get the following error
LINQ to Entities does not recognize the method 'Boolean
ContainsAnyWord(System.String, System.String)' method, and this method
cannot be translated into a store expression.
The following example works great because I am working with a list.
using(var conn = new AppContext())
{
var allUsers = conn.Users.GetAll().ToList();
var foundUsers = allUsers.Where
(
user =>
user.FirstName.ContainsAnyWord("Some Full Name Goes Here")
|| user.LastName.ContainsAnyWord("Some Full Name Goes Here")
).ToList();
}
But the following example does not work because I am working with IQueryable which gives me the error listed above.
using(var conn = new AppContext())
{
var allUsers = conn.Users.Where
(
user =>
user.FirstName.ContainsAnyWord("Some Full Name Goes Here")
|| user.LastName.ContainsAnyWord("Some Full Name Goes Here")
).ToList();
}
How can I fix this issue and make this method available for IQueryable object?
UPDATED
Based on the feedback I got below, I tried to implement this using IQueryable like so
public static IQueryable<T> ContainsAnyWord<T>(this IQueryable<T> query, string searchFor)
{
if (!string.IsNullOrWhiteSpace(searchFor))
{
IEnumerable<string> tags = StopwordTool.GetPossibleTags(searchFor);
return query.Where(item => tags.Contains(item));
}
return query;
}
But this is also giving me an error
You have to keep in mind that this has to be translated to SQL at the end.
Obviously ContainsAnyWord cannot be translated to SQL...
So ,save your names in a List/Array and try
user => yourlist.Contains( user.FirstName)
EF will translate this to a WHERE ..IN
There is no need for a method but if for some reason you want it
internal static class MyClass2
{
public static IQueryable<T> ContainsAnyWord<T>(this IQueryable<T> value, string searchFor) where T: User
{
var names = searchFor.Split(' ').ToList();
return value.Where(u => names.Contains(u.DisplayName));
}
}
You can use it like
var result=conn.Users.ContainsAnyWord("abc def ght");
Linq to Entities converts Methods into database expressions. You can not implement an extension to System.String and expect it to be translated into a T-SQL expression, wich is what internally Entity Framework does.
My suggestion is trying to work around using pre-defined Linq methods. Try using Contains method.
You can't call methods inside the query expression the expression parser provided by the Linq to Entites does not know how to handle. The only thing you can really do is write a extension method that takes in a IQueryable<T> and build up the expression internally inside the function instead of calling Where(
This below code is totally untested and is something I came up with off the top of my head. But you would need to do something like this
public static IQueryable<T> WhereContainsAnyWord<T>(this IQueryable<T> #this, Expression<Func<T, string>> selector, string searchFor)
{
var tags = StopwordTool.GetPossibleTags(searchFor); //You might need a .ToArray() here.
var selectedItems = #this.GroupBy(selector);
var filteredItems = selectedItems.Where(selectedItem => tags.Contains(selectedItem.Key.ToLower()));
var result = filteredItems.SelectMany(x => x);
return result;
}
used like
using(var conn = new AppContext())
{
var allUsers = conn.Users.WhereContainsAnyWord(user => user.FirstName, "Some Full Name Goes Here").ToList();
}
Here is a simpiler non generic version
public static IQueryable<User> WhereContainsAnyWord(this IQueryable<User> #this, string searchFor)
{
var tags = StopwordTool.GetPossibleTags(searchFor); //You might need a .ToArray() here.
return #this.Where(user => tags.Contains(user.DisplayName.ToLower()));
}
used like
using(var conn = new AppContext())
{
var allUsers = conn.Users.WhereContainsAnyWord("Some Full Name Goes Here").ToList();
}
Related
I want to use LinqKit's PredicateBuilder and pass the predicate into .Any method for related model.
So I want to build a predicate:
var castCondition = PredicateBuilder.New<CastInfo>(true);
if (movies != null && movies.Length > 0)
{
castCondition = castCondition.And(c => movies.Contains(c.MovieId));
}
if (roleType > 0)
{
castCondition = castCondition.And(c => c.RoleId == roleType);
}
And then use it to filter model that has relation to model in predicate:
IQueryable<Name> result = _context.Name.AsExpandable().Where(n => n.CastInfo.Any(castCondition));
return await result.OrderBy(n => n.Name1).Take(25).ToListAsync();
But this causes a System.NotSupportedException: Could not parse expression 'n.CastInfo.Any(Convert(__castCondition_0, Func``2))': The given arguments did not match the expected arguments: Object of type 'System.Linq.Expressions.UnaryExpression' cannot be converted to type 'System.Linq.Expressions.LambdaExpression'.
I saw similar question and answer there suggests to use .Compile. Or one more question that build an extra predicate.
So I tried to use extra predicate
var tp = PredicateBuilder.New<Name>(true);
tp = tp.And(n => n.CastInfo.Any(castCondition.Compile()));
IQueryable<Name> result = _context.Name.AsExpandable().Where(tp);
Or use compile directly
IQueryable<Name> result = _context.Name.AsExpandable().Where(n => n.CastInfo.Any(castCondition.Compile()));
But I have an error about Compile: System.NotSupportedException: Could not parse expression 'n.CastInfo.Any(__Compile_0)'
So is it possible to convert the result from PredicateBuilder to pass into Any?
Note: I was able to build the desired behavior combining expressions, but I don't like that I need extra variables.
System.Linq.Expressions.Expression<Func<CastInfo,bool>> castExpression = (c => true);
if (movies != null && movies.Length > 0)
{
castExpression = (c => movies.Contains(c.MovieId));
}
if (roleType > 0)
{
var existingExpression = castExpression;
castExpression = c => existingExpression.Invoke(c) && c.RoleId == roleType;
}
IQueryable<Name> result = _context.Name.AsExpandable().Where(n => n.CastInfo.Any(castExpression.Compile()));
return await result.OrderBy(n => n.Name1).Take(25).ToListAsync();
So I assume I just miss something about builder.
Update about versions: I use dotnet core 2.0 and LinqKit.Microsoft.EntityFrameworkCore 1.1.10
Looking at the code, one will assume that the type of castCondition variable is Expression<Func<CastInfo, bool>> (as it was in earlier versions of PredicateBuilder).
But if that was the case, then n.CastInfo.Any(castCondition) should not even compile (assuming CastInfo is a collection navigation property, so the compiler will hit Enumerable.Any which expects Func<CastInfo, bool>, not Expression<Func<CastInfo, bool>>). So what's going on here?
In my opinion, this is a good example of C# implicit operator abuse. The PredicateBuilder.New<T> method actually returns a class called ExpressionStarter<T>, which has many methods emulating Expression, but more importantly, has implicit conversion to Expression<Func<T, bool>> and Func<CastInfo, bool>. The later allows that class to be used for top level Enumerable / Queryable methods as replacement of the respective lambda func/expression. However, it also prevents the compile time error when used inside the expression tree as in your case - the complier emits something like n.CastInfo.Any((Func<CastInfo, bool>)castCondition) which of course causes exception at runtime.
The whole idea of LinqKit AsExpandable method is to allow "invoking" expressions via custom Invoke extension method, which then is "expanded" in the expression tree. So back at the beginning, if the variable type was Expression<Func<CastInfo, bool>>, the intended usage is:
_context.Name.AsExpandable().Where(n => n.CastInfo.Any(c => castCondition.Invoke(c)));
But now this doesn't compile because of the reason explained earlier. So you have to convert it first to Expression<Func<T, bool> outside of the query:
Expression<Func<CastInfo, bool>> castPredicate = castCondition;
and then use
_context.Name.AsExpandable().Where(n => n.CastInfo.Any(c => castPredicate.Invoke(c)));
or
_context.Name.AsExpandable().Where(n => n.CastInfo.Any(castPredicate.Compile()));
To let compiler infer the expression type, I would create a custom extension method like this:
using System;
using System.Linq.Expressions;
namespace LinqKit
{
public static class Extensions
{
public static Expression<Func<T, bool>> ToExpression<T>(this ExpressionStarter<T> expr) => expr;
}
}
and then simply use
var castPredicate = castCondition.ToExpression();
It still has to be done outside of the query, i.e. the following does not work:
_context.Name.AsExpandable().Where(n => n.CastInfo.Any(c => castCondition.ToExpression().Invoke(c)));
It may not be exactly related to the original question, but considering the following model :
public Class Music
{
public int Id { get; set; }
public List<Genre> Genres { get; set; }
}
public Class Genre
{
public int Id { get; set; }
public string Title { get; set; }
}
List<string> genresToFind = new() {"Pop", "Rap", "Classical"};
If you are trying to find all Musics that their genres exist in genresToFind list, here's what you can do:
Create PredicateBuilder expressions chain on Genre model :
var pre = PredicateBuilder.New<Genre>();
foreach (var genre in genresToFind)
{
pre = pre.Or(g => g.Title.Contains(genre));
}
Then execute your query like this :
var result = await _db.Musics.AsExpandable()
.Where(m => m.Genres
.Any(g => pre.ToExpression().Invoke(g)))
.ToListAsync();
ToExpression() is a generic extension method that we've created to convert ExpressionStarter<Genre> type to Expression<Func<Genre, bool>> :
public static class ExpressionExtensions
{
public static Expression<Func<T, bool>> ToExpression<T> (this
ExpressionStarter<T> exp) => exp;
}
Also, you'll need LinqKit.Microsoft.EntityFrameworkCore package for efcore.
I have a project with TPT inheritance mapping, now I need to add it a search functionality that will find records in several tables. That's what I currently have:
public abstract class Customer
{
public int Id { get; set; }
public string Memo { get; set; }
...
}
public class Person : Customer
{
public string GivenName { get; set; }
public string Surname { get; set; }
...
}
public class Company : Customer
{
public string Name { get; set; }
...
}
I also have a unit of work with bunch of repositories, and I need to add the filtering functionality to several methods of CustomerRepository. Let's say I have a Count method with the following signature
public int Count(System.Linq.Expressions.Expression<Func<Customer, bool>> filter = null)
Now I need to get the quantity of customers whose GiveName or Surname contains searchTerm in case the customer is a Person or the same searchTerm in Name field in case it is a Company.
TL;DR
How a view with a single, searchable, paged list of Customers (containing both Person and Company types) should be implemented? I mean in terms of method with signature like public IHttpActionResult Get(string searchTerm, int pageSize, int pageNumber)...
That's what I tried:
I added to each of the classes a static method that would generate an Expression to search that specific class, that's how it looks for the Person class:
public static System.Linq.Expressions.Expression<Func<Person, bool>> GetFilter(string searchTerm)
{
if (String.IsNullOrWhiteSpace(searchTerm))
{
return null;
}
var parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(Person));
System.Reflection.MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
return System.Linq.Expressions.Expression.Lambda<Func<Person, bool>>(
System.Linq.Expressions.Expression.OrElse(
System.Linq.Expressions.Expression.Call(
System.Linq.Expressions.Expression.PropertyOrField(parameterExpression, "GivenName"),
method,
System.Linq.Expressions.Expression.Constant(searchTerm, typeof(string))
),
System.Linq.Expressions.Expression.Call(
System.Linq.Expressions.Expression.PropertyOrField(parameterExpression, "Surname"),
method,
System.Linq.Expressions.Expression.Constant(searchTerm, typeof(string))
)
), parameterExpression);
}
And tried to build an Expression that would check the type of the customer and then make an appropriate data check, but here I stumped... That's what I have right now:
var parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(Customer));
var typeIsPerson = System.Linq.Expressions.Expression.TypeIs(parameterExpression, typeof(Person));
var typeIsCompany = System.Linq.Expressions.Expression.TypeIs(parameterExpression, typeof(Company));
var q = System.Linq.Expressions.Expression.Block(
System.Linq.Expressions.Expression.IfThen(typeIsPerson, Person.GetFilter(searchTerm)),
System.Linq.Expressions.Expression.IfThen(typeIsCompany, Company.GetFilter(searchTerm)),
System.Linq.Expressions.Expression.Constant(false));
var a = System.Linq.Expressions.Expression.Lambda<Func<Customer, bool>>(
q, parameterExpression);
Here I have two problems(at least?), first when I try to call Count, I get a very unpleasant NotSupportedException exception that says Unknown LINQ expression of type 'Block'. The second is that I don't know how to return the result of execution for each of GetFilters, I suspect that I will get false for any record since it is default value that is the last Expression in my Block...
May be I'm on a wrong track and this is something that should be done in a completely different manner?
Expression blocks are generally unsupported in LINQ to Entities. And normally you don't need them because you could build almost any expression just using C# conditional operator ? : (which maps to Expression.Condition).
But before even trying to build an expression dynamically, you need to find a EF supported construct working with TPT (and other EF inheritance models) polymorphic query. Which is not so easy because all the examples use OfType method which is only applicable when you need to filter a concrete derived entities. With some trial and error, luckily there are two supported constructs - is and as (important: as, not cast!).
So the statically built predicate expression in question could be like this:
Expression<Func<Customer, bool>> predicate = c =>
c is Person ?
((c as Person).GivenName.Contains(searchTerm) || (c as Person).Surname.Contains(searchTerm)) :
c is Company ?
(c as Company).Name.Contains(searchTerm) :
false;
(Frankly you don't want to look at the generated SQL, but it works)
Now you can build it dynamically if you wish. You already found the is expression method (Expression.TypeIs), for as operator the corresponding expression metod is Expression.TypeAs.
You do not need to do all that. Just create a generic method that you will close when you call it. Your generic method can be like this:
public static int Count<T>(Expression<Func<T, bool>> filter = null)
{
var ctx = new StackContext();
return ctx.Customers.OfType<T>().Where(filter).Count();
}
You can call that like this:
// Here you are closing the generic to be of type Person
var personsCount = Count<Person>(x => x.GivenName == "George");
// Here you are closing the generic to be of type Customer
var companyCount = Count<Company>(x => x.Name == "Test");
I'm having product entity:
public class Product : DomainBase
{
public virtual string Name { get; set; }
}
And there should be option to select products by filter, which contains an array of names, like:
public static IEnumerable<Product> SearchArrayQueryLinq(IEnumerable<string> names)
{
using (var session = Database.OpenSession())
{
var products = session.Query<Product>();
var result = products.Where(product => names.Any(name => product.Name.Contains(name)));
return result.ToList();
}
}
but it throws
System.NotSupportedException: Specified method is not supported.
What is right approach, to accomplish such filtering?
Without knowing more about what database you're connecting to or what library (is it RavenDB.. having done a quick Google?) then it's hard to be completely sure what the problem is.
However, what I think is happening is that you are giving an expression to the IQueryable "Where" extension method and the library is trying to turn that into search criteria to run against the db.. and failing because "Any" is not supported in nested criteria like that (again, I'm guessing).
The LINQ expressions that may or may not be translated into the database language (eg. SQL) vary by the library that performs the translation and vary by the database being talked to.
For example, the following (which is basically what you want to do) works fine with Entity Framework:
private static void Test(IEnumerable<string> names)
{
using (var context = new NORTHWNDEntities())
{
foreach (var product in context.Products.Where(product => names.Any(name => product.ProductName.Contains(name))))
{
Console.WriteLine(product.ProductName);
}
}
Console.ReadLine();
}
One easy option for you is to change your code to
public static IEnumerable<Product> SearchArrayQueryLinq(IEnumerable<string> names)
{
using (var session = Database.OpenSession())
{
var products = session.Query<Product>();
return result = products.ToList().Where(product => names.Any(name => product.Name.Contains(name)));
}
}
This should work.. however, it will get all Products from the database and perform the filtering in-memory. This is less efficient than getting the database to perform the search.
An alternative would be to generate an "Expression<Func<Product, bool>>" filter yourself that is easier for the library that you're using to translate. If, instead, of a nested "Any" criteria, you could generate a simple set of "OR" name checks then there is a better change of it working. The following will achieve that - but it's quite a lot of code. If this is something that you need to do in several places then some of the code could be made more general and reused.
private static IEnumerable<Product> SearchArrayQueryLinq(IEnumerable<string> names)
{
using (var context = new NORTHWNDEntities())
{
return context.Products.Where(GetCombinedOrFilter(names)).ToList();
}
}
private static Expression<Func<Product, bool>> GetCombinedOrFilter(IEnumerable<string> names)
{
var filter = GetNameFilter(names.First());
foreach (var name in names.Skip(1))
filter = CombineFiltersAsOr(filter, GetNameFilter(name));
return filter;
}
private static Expression<Func<Product, bool>> GetNameFilter(string name)
{
return product => product.ProductName.Contains(name);
}
private static Expression<Func<Product, bool>> CombineFiltersAsOr(Expression<Func<Product, bool>> x, Expression<Func<Product, bool>> y)
{
// Combine two separate expressions into one by combining as "Or". In order for this to work, instead of there being a parameter
// for each expression, the parameter from the first expression must be shared between them both (otherwise things will go awry
// when this is translated into a database query) - this is why ParameterRebinder.ReplaceParameters is required.
var expressionParameter = x.Parameters.Single();
return Expression.Lambda<Func<Product, bool>>(
Expression.Or(x.Body, ParameterRebinder.ReplaceParameters(y.Body, toReplace: y.Parameters.Single(), replaceWith: expressionParameter)),
expressionParameter
);
}
// Borrowed and tweaked from https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/
public sealed class ParameterRebinder : ExpressionVisitor
{
public static Expression ReplaceParameters(Expression expression, ParameterExpression toReplace, ParameterExpression replaceWith)
{
return new ParameterRebinder(toReplace, replaceWith).Visit(expression);
}
private readonly ParameterExpression _toReplace, _replaceWith;
private ParameterRebinder(ParameterExpression toReplace, ParameterExpression replaceWith)
{
_toReplace = toReplace;
_replaceWith = replaceWith;
}
protected override Expression VisitParameter(ParameterExpression p)
{
if (p == _toReplace)
p = _replaceWith;
return base.VisitParameter(p);
}
}
Update: I didn't notice your nhibernate tag - whoops! Using the criteria combining methods that nhibernate has is probably easier than all this.. :) I would have commented on your answer rather than updating my own but I haven't got the requisite 50 rep yet..
You are trying to mix both kinds of conditions and applying IEnumerable methods on string properties.
Your query should look like this:
var result = products.Where(product => names.Contains(product.Name));
to find exact matches.
For a combination of exact matches and StartsWith it should look like this:
var results = products.Where(product => (names.Contains(product.Name) || names.Any(name => name.StartsWith(product.Name))));
As I did a dive into NHibenrate documentation, it contains CriteriaAPI, so I came up to this
using (var session = Database.OpenSession())
{
var products = session.CreateCriteria<Product>();
if (names == null)
{
return products.List<Product>();
}
var orClause = Expression.Disjunction();
foreach (var name in names)
{
orClause.Add(Expression.Like(nameof(Product.Name), name, MatchMode.Start));
}
products.Add(orClause);
return products.List<Product>();
}
I need to create a general routine in visual studio to get some parameters as input and return a list resulted from a repository. I am using Linq. But I am not sure how to develop this function and neither what key words I can use and find some resources.
This is a sample code that already is used in my program:
var lstReceiptDetails = Repository<TransactionDetail>()
.Where(current => current.HeaderId == headerId)
.OrderBy(current => current.DocumentRow)
.ToList();
I need to change the above linq statement to something like the following pseudocode:
private List<> GetQuery(repositoryName, conditionFieldName, orderFieldName )
{
var lstResult = Repository<repositiryName>()
.Where(current => current.ConditionFieldName == conditionFieldName)
.OrderBy(current => current.orderFieldName)
.ToList();
Return(lstResult);
}
Any help is appreciate.
Maryam
I think the closest way you can get is by using the following example below. I've tried a several ways to do this, but it would harm the usability and the readability. This is a compromise between code duplication and readability.
A sample POCO object:
class TransactionDetail
{
public DateTime DateProcessed { get; set; }
public string AccountName { get; set; }
}
The repositories:
abstract class GenericRepository<T>
{
public List<T> GetQuery<TKey>(
Func<T, bool> conditionFieldName,
Func<T, TKey> orderFieldName)
{
var lstResult = Repository()
.Where(conditionFieldName)
.OrderBy(orderFieldName)
.ToList();
return lstResult;
}
private IEnumerable<T> Repository()
{
throw new NotImplementedException();
}
}
class TransactionDetailRepository : GenericRepository<TransactionDetail>
{
}
And caller-side:
var repository = new TransactionDetailRepository();
var transactions = repository.GetQuery(
x => x.AccountName == "Foo Bar",
x => x.DateProcessed);
Argument checks should still be implemented properly though.
If this piece of code should be used in EntityFramework or Linq-to-SQL, parameters should be wrapped in Expression<T> such that, for example: Func<T, bool> becomes Expression<Func<T, bool>>
You can try to use the LINQ Dynamic Query Library that take string arguments instead of type-safe language operators.
Short example:
var result = Repository<repositoryName>().
Where("Id = 1").
Select("new(Id, Name)");
More information here: http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library
This question already has answers here:
C# Pass Lambda Expression as Method Parameter
(4 answers)
Closed 9 years ago.
I'm writing a layered ASP.Net Application which consist of Bussiness layer, Repository layer, service Layer... . In repository layer I'm using EntityFramework as ORM. In service layer, I want to pass a query in lambda form (which includes OrderBy or OrderByDescending ,take, skip,...) to repository layer and run the query on an DbSet and return result entities.
In Simple words : (How I can do something like the following mock code in asp.net c#)
public class Repository
{
public List<Book> findby(var query)
{
var dbcontext = DataContextFactory.GetDataContext();
//The following line should do this : dbcontext.Books.Where(B=>B.New==true && B.Id>99).OrderBy(B=>B.Date).ThenBy(B=>B.Id).Skip(2).Take(10);
List<Book> matchedBooks = RunQueryOnBooks(dbcontext.Books,query);
return matchedBooks;
}
}
public class Service
{
public List<Book> getTopNewBooks(Repository _repository)
{
var query = Where(B=>B.New==true && B.Id>99).OrderBy(B=>B.Date).ThenBy(B=>B.Id).Skip(2).Take(10);
List<Book> matchedBooks = _repository.findby(query);
return matchedBooks;
}
}
So the question is:
which type I should use instead of var for query (If there is any and is possible)
how I execute the query on dbcontext.Books ?
Please give a good and easy example like mine and more references. thanks in advance.
I think you probably want simply a Func<IQueryable<Book>, IQueryable<Book>>:
void RunQueryOnBooks(DbSet<Book> set, Func<IQueryable<Book>, IQueryable<Book>> query)
{
return query(set.AsQueryable());
}
The query input could then be a lambda:
Repository.FindBy(set => set.Where(B => B.new == true ... ));
LINQ uses Lambda Expressions, which can be represented as Funcs. As long as you build a Func that returns the appropriate type and takes the appropriate parameter type, you'll be all set.
var myFunc = new Func<IEnumerable<Book>, IEnumerable<Book>>(book => book.Where(i => true /* rest of your code here */));
var test = Enumerable.Empty<Book>();
var result = myFunc(test);
If you think about it, what you're saying is that you want to take some collection of books as input and give back some filtered/ordered collection of books back. Thus, the appropriate type for query would be Func<IEnumerable<Books>, IEnumerable<Books>.
With that in mind, I'd probably make the query a function (getTopNewBooks) instead of a lambda, but both will work. Either way, you can pass the delegate method to the findby function as something like:
public class Application
{
public static void Main()
{
var repo = new Repository();
foreach (var topBook in repo.findby(Service.getTopNewBooks))
{
// This is a matching top book
}
}
}
public class Repository
{
public List<Book> findby(Func<IEnumerable<Book>,IEnumerable<Book>> query)
{
var dbcontext = DataContextFactory.GetDataContext();
List<Book> matchedBooks = query(dbcontext.Books).ToList();
return matchedBooks;
}
}
public class Service
{
public static IEnumerable<Book> getTopNewBooks(IEnumerable<Book> input)
{
return input.Where(B=>B.New==true && B.Id>99).OrderBy(B=>B.Date).ThenBy(B=>B.Id).Skip(2).Take(10);
}
}
If you hover over the "var" in Visual Studio, it will tell you the inferred type. You can use that to show what type your query ends up being.