I tried to define a generic loading method.
I call this generic loading method with an array of expressions like this:
var includes = new Expression<Func<CatalogItem, object>>[]
{
ci => ci.Catalog.Select(ci => ci.Supplier.Region),
ci => ci.Test
}
In the method I create an IQueryable:
IQueryable<TAggregateRoot> queryable = dbContext.Set<TAggregateRoot>();
Then for each Expression I want to load the respective data like this:
foreach (var include in includes)
{
queryable = queryable.Include(include);
}
But this only works when the Expression is only one level. With multiple levels it throws an error.
Since there is no ThenInclude I have to use the EntityFrameworkQueryableExtensions. I tried it like this
queryable = EntityFrameworkQueryableExtensions.ThenInclude(queryable, include);
But this does not work either.
I cannot find any documentation to this problem. How do I solve this problem and how do I use EntityFrameworkQueryableExtensions.ThenInclude?
Instead of passing an expression to the Include() method, there are two overloads you can use that take strings.
The first takes either a single property or multi-level properties like so:
Include("property1")
OR
Include("property1.property2.property3")
The second takes advantage of the nameof() method like so:
Include(nameof(property1), nameof(property2), nameof(property3))
And if you have a generic loading method that takes an array of strings to iterate over and "Include" (in precisely the same fashion you are iterating over your array right now), then you can use the first overload (one string) and do something like this:
MyGenericRepo.MySetInclude(new string[] {$"{nameof(ParentEntity.ChildEntity)}.{nameof(ChildEntity.GrandchildEntity)}"});
So you are still only using the one Include() method without adding any additional logic to your repository, but you can now "include" as many levels as you wish.
To see the origins of these overloads, you can check it out here
Related
I am trying to call a controller action method inside the lambda expression like below.
Here dtImporteddata is my DataTable
public class DepartmentController : Controller
{
public ActionResult Create(FormCollection collection, int ParentDepartmentID)
{
return view();
}
}
dtImporteddata.Rows.Cast<DataRow>().Select(r => new DepartmentController().Create(new FormCollection{
{"ParentDepartmentID","57"},
{"DepartmentPrefix",r["Prefix"].ToString()},
{"DepartmentID","0"},
{"IsSpecialDepartment",null},
{"Description",r["Description"].ToString()},
{"Name",r["Name"].ToString()},
{"LocationIDs.$.PackedValue","4;;;"}
}, 0)).ToList();
if i write like above the Create() method is getting called perfectly but if i remove ToList() then the Create() is not getting called.
The problem is that the Select method actually doesn't do that much. It starts doing something when you iterate over its result.
That said, the ToList method does iterate over the iterator returned from Select, hence it executes your lambda expression.
I guess you want to pick up the result and do something with it, if so, assign it to a variable and iterate over it:
foreach(var row in dtImporteddata.Rows.Cast<DataRow>().Select(...))
{
// do something with row
}
LINQ methods can be split into two camps: those which always return a result (eg, FirstOrDefault) and those which project a different form of what's being given to them. You can think of these projection methods as performing filtering operations.
See what is a projection in LINQ, as in .Select()
Anyway, to answer your question, LINQ doesn't always perform the operation that you might think it's performing. In many cases LINQ uses subsequent operations to add filtering (or modify the projection) and only when you resolve the method call to a result are the calls executed.
I suspect that this is the case here. Without the ToList call you're only building the set of instructions, and only when you call ToList are these instructions resolved to a result.
If you're not actually bothered about the functionality offered by a List<DataRow> and you simply want an enumerable result, consider using ToArray as it has less overhead than ToList.
I would suggest abstracting the create functionality in a reusable component, that both the controller and your lambda can use. For example, you could create a class that has a method with the following signature:
public void CreateDepartment(Department newDepartment)
The Department class could probably expose the same fields as the FormCollection.
You could the use the new method directly in LINQ like so:
dtImporteddata.Rows.Cast<DataRow>().ToList()
.ForEach(r => CreateDepartment(
new Department {
Name = r.Name,
....//rest of the properties
}));
In this way, you would also be able to call the same method within the Create action.
Is the purpose of AsQueryable() just so you can pass around an IEnumerable to methods that might expect IQueryable, or is there a useful reason to represent IEnumerable as IQueryable? For example, is it supposed to be for cases like this:
IEnumerable<Order> orders = orderRepo.GetAll();
// I don't want to create another method that works on IEnumerable,
// so I convert it here.
CountOrders(orders.AsQueryable());
public static int CountOrders(IQueryable<Order> ordersQuery)
{
return ordersQuery.Count();
}
Or does it actually make it do something different:
IEnumerable<Order> orders = orderRepo.GetAll();
IQueryable<Order> ordersQuery = orders.AsQueryable();
IEnumerable<Order> filteredOrders = orders.Where(o => o.CustomerId == 3);
IQueryable<Order> filteredOrdersQuery = ordersQuery.Where(o => o.CustomerId == 3);
// Are these executed in a different way?
int result1 = filteredOrders.Count();
int result2 = filteredOrdersQuery.Count();
Do the IQueryable versions of these extension methods just build up an Expression that ends up doing the same thing once its executed? My main question is, whats a real use case for using AsQueryable?
There are a few main uses.
As mentioned in other answers, you can use it to mock a queryable data source using an in-memory data source so that you can more easily test methods that will eventually be used on a non-enumerable based IQueryable.
You can write helper methods for manipulating collections that can apply to either in-memory sequences or external data sources. If you write your help methods to use IQueryable entirely you can just use AsQueryable on all enumerables to use them. This allows you to avoid writing two separate versions of very generalized helper methods.
It allows you to change the compile time type of a queryable to be an IQueryable, rather than some more derived type. In effect; you'd use it on an IQueryable at the same times that you'd use AsEnumerable on an IEnumerable. You might have an object that implements IQueryable but that also has an instance Select method. If that were the case, and you wanted to use the LINQ Select method, you'd need to change the compile time type of the object to IQueryable. You could just cast it, but by having an AsQueryable method you can take advantage of type inference. This is simply more convenient if the generic argument list is complex, and it is actually necessary if any of the generic arguments are anonymous types.
The most valid case I have for AsQueryable is unit testing. Say I have the following somewhat contrived example
public interface IWidgetRepository
{
IQueryable<Widget> Retrieve();
}
public class WidgetController
{
public IWidgetRepository WidgetRepository {get; set;}
public IQueryable<Widget> Get()
{
return WidgetRepository.Retrieve();
}
}
and I want to write a unit test to make sure the controller passes back the results returned from the repository. It'd look something like this:
[TestMethod]
public void VerifyRepositoryOutputIsReturned()
{
var widget1 = new Widget();
var widget2 = new Widget();
var listOfWidgets = new List<Widget>() {widget1, widget2};
var widgetRepository = new Mock<IWidgetRepository>();
widgetRepository.Setup(r => r.Retrieve())
.Returns(listOfWidgets.AsQueryable());
var controller = new WidgetController();
controller.WidgetRepository = widgetRepository.Object;
var results = controller.Get();
Assert.AreEqual(2, results.Count());
Assert.IsTrue(results.Contains(widget1));
Assert.IsTrue(results.Contains(widget2));
}
where really, all the AsQueryable() method allows me to do is satisfy the compiler when setting up a mock.
I'd be interested where this is used in application code though.
As sanjuro noted, the purpose of AsQueryable() is explained in Using AsQueryable With Linq To Objects And Linq To SQL. In particular, the article states,
This offers an excellent benefits in real word scenarios where you have certain methods on an entity that return an IQueryable of T and some methods return List. But then you have business rule filter that needs to be applied on all the collection regardless if the collection is returned as IQueryable of T or IEnumerable of T. From a performance stand point, you really want to leverage executing the business filter on the database if the collection implements IQueryable otherwise fall back to apply the business filter in memory using Linq to object implementation of delegates.
The purpose of AsQueryable() is greatly explained in this article Using AsQueryable With Linq To Objects And Linq To SQL
From Remarks section of MSDN Queryable.AsQueryable Method:
If the type of source implements IQueryable, AsQueryable(IEnumerable) returns it directly. Otherwise, it returns an IQueryable that executes queries by calling the equivalent query operator methods in Enumerable instead of those in Queryable.
Thats is exactly what is mentioned and used in above article.
In your example, it depends on what is orderRepo.GetAll returning, IEnumerable or IQueryable(Linq to Sql). If it returns IQueryable, the Count() method will be executed on database otherwise it will be executed in memory. Look carefully at example in referenced article.
Interface IQueryable quoting documentation:
The IQueryable interface is intended for implementation by query
providers.
So for someone that intends to make its datastracture queryable in .NET, that datastructure that not necessary can be enumerated or have valid enumerator.
IEnumerator is an interface for iterating and processing stream of data instead.
In my EF later, I'm trying to pass in an anonymous function to be used as part of my Linq query. The function would pass in an INT and return a BOOL (u.RelationTypeId is an INT). Below is a simplified version of my function:
public IEnumerable<UserBandRelation> GetBandRelationsByUser(Func<int, bool> relation)
{
using (var ctx = new OpenGroovesEntities())
{
Expression<Func<UsersBand, bool>> predicate = (u) => relation(u.RelationTypeId);
var relations = ctx.UsersBands.Where(predicate);
// mapping, other stuff, back to business layer
return relations.ToList();
}
}
However, I get the error stated above. It seems like I'm going everything correct by building a predicate from the function. Any ideas? Thanks.
I was getting this very error and I'm using Entity Framework with PredicateBuilder by Joe Albahari to build dynamic where clauses. If you happen to be in the same condition, you should call the AsExpandable method:
If querying with Entity Framework, change the last line to this:
return objectContext.Products.AsExpandable().Where(predicate);
This method is part of LINQKIT DLL that you can grab here or through a NuGet package here.
Everything works fine now. :)
You're trying to pass an arbitrary .NET function in... how could the entity framework hope to translate that into SQL? You can change it to take an Expression<Func<int, bool>> instead, and build the Where clause from that, although it won't be particularly easy, because you'll need to rewrite the expression with a different parameter expression (i.e. replacing whatever parameter expression is in the original expression tree with the expression of calling u.RelationTypeId).
To be honest, for the sake of just specifying u.RelationTypeId in the lambda expression that you use to create the expression tree to pass into the method, you'd be better off just using:
public IEnumerable<UserBandRelation> GetBandRelationsByUser(
Expression<Func<UsersBand, bool>> predicate)
{
using (var ctx = new OpenGroovesEntities())
{
var relations = ctx.UsersBands.Where(predicate);
// mapping, other stuff, back to business layer
return relations.ToList();
}
}
You can call the Expand() method on your predicate before the Where request.
I know this answer is really late, but I ran into the same problem and it led me here, so I thought I'd share my solution.
I read Leniel's answer, and it gave me an idea. The default types have the method "AsEnumerable()" which behaves the same way, alleviating the issue.
I'm trying to create a method signature that takes multiple properties of various type using
I would call it something like this:
AllPropertiesExcept(() => Property1, () => Property2)
This method almost work, except that the type of the properties have to be the same. I'm only going to use the property name, but want to use lambda expression to enable easy refactoring.
public static string MyMethod<T>(params Expression<Func<T>>[] propertyExpression)
I would use AllPropertiesExcept(params Expression<Func<object>>[] properties), you can still get the property names out of it, but it doesn't matter what type the property is.
Edit: However, I would tend to use it the other way round - instead of excluding properties I don't want to see, I would include properties I want to see. The reason is simple - to make your way work, you still need reflection - with my way, you could easily use the Func you get to get the actual data directly.
Edit 2 (getting the property name out of an expression):
Expression<Func<object>> obj = something; // you get this in your method
((obj.Body as UnaryExpression).Operand as MemberExpression).Member.Name
I can really advise you to use LinqPad for such things, you can easily drill down objects via Dump(), which displays the objects very user friendly. Just recreate a small example and experiment.
Does the method AllPropertiesExcept() return anything? Otherwise you could make a fluent interface (using method chaining):
AllPropertiesExcept(() => Property1)
.And(() => Property2)
.And(() => Property3);
Even if the AllPropertiesExcept() method returns something, you can defer the execution until you invoke a method at the end of the method chain:
var foo = AllPropertiesExcept(() => Property1)
.And(() => Property2)
.And(() => Property3)
.DoSomeThing();
I think what you need is to understand the ModelMetadata class documented here:
http://msdn.microsoft.com/en-us/library/system.web.mvc.modelmetadata.aspx
This class is used in ASP.NET MVC in situations like Html.LabelFor(x -> x.Name)
An expression is passed to the ModelMetadata.FromLambdaExpression Method documented here:
http://msdn.microsoft.com/en-us/library/ee428393.aspx
After understanding how it is used in MVC, you could create your own code with some informed knowledge of how it was applied elsewhere.
In one of my previous questions about using dynamically built up strings (where clauses) and using them in LINQ, I was guided towards the LINQ Dynamic Query Library Dynamic LINQ.
The first issue was that it only applies to IQueryable, this however can be overcome by using the .AsQueryable() extension method on any IEnumerable.
The problem I ran into was that Dynamic LINQ is looking for a Property called "CustomerID" (or whatever was passed in to the string predicate for dynamic linq) on my Dictionary. Which obviously won't work since a Dictionary only has Keys and Values.
So thinking I'm being clever, I created a class extending : Dictionary<string, object>, ICustomTypeDescriptor`.
This allowed me to override GetProperties() on the type. Which is great. I can now iterate the Dictionary keys and add them to a PropertyDescriptorCollection which gets returned.
But then I ran into another problem. Throughout the Dynamic LINQ library, they work with 'Expression instance' which only contains a Type. But for my CustomTypeDescriptor solution to work I need an actual instance of the Type, before I can apply TypeDescriptor.GetProperties(instance, false).
So getting to the actual question. Taking all the above information into account, how do I apply a custom where clause in string format "CustomerID=1234 AND Quantity >= 10000" to a LINQ query if the data is stored in a Dictionary with Key-Value pairs.
My current solution is transforming the data into a DataTable and using the .Select(query) method. Which works, but I'm interested in finding other solutions. Especially for benchmarking purposes.
Any ideas?
Firstly - if you you access a dictionary in this way, then you aren't using it as a dictionary - have you tried:
var qry = myDictionary.Values.AsQueryable().Where(sQuery);
(note that if you are using object, you'll probably want a Cast<Customer> or OfType<Customer> in there somewhere)
Otherwise:
The T in IEnumerable<T> (and hence also for IQueryable<T> after calling the AsQueryable() extension method) for a Dictionary<TKey,TValue> is KeyValuePair<TKey,TValue> - so you should be able to use Where("Value.CustomerID == 12345") or something similar.