IQueryable with String.Format and PatIndex - linq

I am facing a issue when i try to used string.format on two db entities A, B and then using SqlFunctions.PatIndex on them
IQueryable<Data> dataRecords = DbSet<Data> M_Data;
dataRecords = dataRecords.Where(c => SqlFunctions.PatIndex(sqlFilter, String.Format(A,B)) > 0);
its throwing exception Linq to entities does not recognize method string.Format
When i use AsEnumarable()
dataRecords = dataRecords.AsEnumerable().Where(c => SqlFunctions.PatIndex(sqlFilter, String.Format(A,B)) > 0).AsQueryable();
than it's throwing This function can only be invoked from LINQ to Entities
Can any one suggest how to do this.

You have two method calls:
String.Format
SqlFunctions.PatIndex
Problem is, that the first one cannot be transformed into proper SQL query and the second one can only be executed within LINQ to Entities query context. Former makes your first attempt fail, latter breaks second try.
However, I don't see A nor B be part of the data you query. You should be able to call string.Format outside of you query and then use the result:
var formattedString = String.Format(A,B);
dataRecords = dataRecords.Where(c => SqlFunctions.PatIndex(sqlFilter, formattedString) > 0);

Related

Get All Entities From EntityCollection Where Values Matches X

I would like to get all matched Entities from an EntityCollection by a value, but my current statement only allow return of Entity, and not EntityCollection.
//only allow return 1 entity
var matchedRecords = allRecords.Entities.Where
(x => x.GetAttributeValue<EntityReference>
("ccc_batchId").Id == batchId);
May I know how can I tweak the above query?
EntityCollection is just a construct to store more than one Entity.
I know it's not ideal but you can always convert the allRecords.Entities inside a List of Entity and do your LINQ query against it.
Your code is probably returning an IEnumerable of Entity and not a single Entity (for example in the end of your query you can put a .ToList() to get a List of Entity.
Building on what Guido said, it is also possible to create a new EntityCollection with the results:
var matchedRecords = allRecords.Entities.Where(x => x.GetAttributeValue<EntityReference>("ccc_batchId").Id == batchId).ToList();
var matchedCollection = new EntityCollection(matchedRecords);

Linq to Entities Query explanation

Is there any way I can make this Linq to entities query in another way (better) and understand what I did?
First, can I have the string.jon() in the first part (select(p => new {...)?
Second, why do I need the first select to end with .ToList() for the string.join() to work?
The tables relation are as follow:
And here is the code:
Productos.Select(p => new {
Id = p.Id,
Code = p.CodigoProd,
Name = p.Nombre,
Cant = p.Inventario.Sum(i => i.Cantidad),
Pric = p.Inventario.OrderBy(i => i.Precio).Select (i => i.Precio).FirstOrDefault(),
cate = p.ProductosXCategoria.Select(pc => pc.CategoriasdeProducto.Nombre)
}).Where (p => p.Cant != null).ToList()
.Select (r => new {
r.Id, r.Code, r.Cant, r.Name, r.Pric, Categ = string.Join("-",r.cate)
})
the result is this (which is the result i expected to be):
IEnumerable<> (17 items)
**Id-- Code-- Cant-- Name-- Pric-- Categ**
1-- AXI-- 30-- Pepsi-- 10-- Granos
3-- ASI-- 38-- Carne blanca-- 12-- Granos-Limpieza
The query looks fine to me.
The reason you can't move the string.Join method to the first Select, is that LINQ-to-Entities ultimately has to be able to translate to SQL. string.Join has no direct translation to SQL, so it doesn't know how to translate your LINQ query to it. By calling ToList() first, you bring the results of the first Select into memory, where the subsequent Select works with Linq-to-Objects. Since Linq-to-Objects does not need to translate to SQL, it can operate directly on the results of the first query in memory.
Generally, you would want to put everything that would be better left to SQL before the ToList() call (such as filtering, sorting, averaging, grouping, etc.), and leave additional work that can't be translated to SQL (or isn't as efficient to do so) for after the results have been brought into local memory.

Var vs IEnumerable when it comes to Entity Framework

If I were to use IEnumerable instead of var in the code example below, will the SQL be generated only during the execution of the foreach statement? Or will it execute as an when the Linq statements are evaluated?
var query = db.Customers.Where (c => c.Age > 18);
query = query.Where (c => c.State == "CO");
var result = query.Select (c => c.Name);
foreach (string name in result) // Only now is the query executed!
Console.WriteLine (name);
Another example:
IEnumerable<Order> query = db.Orders.Where(o => o.Amount > 1000);
int orderCount = query.Count();
Would it be better to use var (or IQueryable) as it would be executed a select count(*)... when .Count() is executed or would it be exactly same with the IEnumerable code shown above?
It would make no difference. var is just syntactic sugar. If you hover over var, you will see what type C# thinks your query is.
From http://msdn.microsoft.com/en-us/library/bb383973.aspx
Beginning in Visual C# 3.0, variables that are declared at method scope can have an implicit type var. An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type. The following two declarations of i are functionally equivalent:
var i = 10; // implicitly typed
int i = 10; //explicitly typed
If you want to perform actions on your query that SQL wouldn't know what to do with, such as a method defined in your class, then you could use AsEnumerable().
For example:
var query = db.Customers
.Where(c => c.Age > 18)
.AsEnumerable()
.Select(c => GetCustomerViewModel());
//put definition of GetCustomerViewModel() somewhere in the same class
Update
As Omar mentioned, if you want your query to be executed immediately (rather than deferred), use ToList(). This will immediately enumerate the IQueryable/IEnumerable and fill the list with the actual data from the database.
In general, the SQL is generated when GetEnumerator is called on the IQueryable.
In your example, there is a subtle difference that you may want to consider. Let's take your original example:
var query = db.Customers.Where (c => c.Age > 18);
query = query.Where (c => c.State == "CO");
var result = query.Select (c => c.Name);
In this case if you change your first query to IEnumerable query = ..., then the second line would use the IEnumerable version of the Where extension (LINQ to Objects) rather than the IQueryable one (LINQ to SQL/EF). As a result, when we start iterating, the first where clause is passed to the database, but the second where clause is performed on the client side (because it has already been converted to an IEnumerable).
Another subtle item you want to be aware of is the following type of code:
var query = db.OrderBy(c => c.State);
query = query.Customers.Where(c => c.Age > 18); // Fails: Widening
In this case, since your original query returns IOrderedQueryable rather than IQueryable. If you try to then assign query to the result of the .Where operation, you're trying to widen the scope of the return type and the compiler will refuse to perform that widening. As a result, you have to explicitly specify the baseline type rather than using var:
IQueryable<Customer> query = db.OrderBy(c => c.State); // Is narrowing rather than widening.
query = query.Customers.Where(c => c.Age > 18);
Linq queries return IQueryable<> or IEnumerable<>, the execution of both is deferred.
As DanM stated, whether or not you use var or IEnumerable<> it all depends on the return value of the method you're calling: if it's an IEnumerable<> or IQuerable<> it'll be deferred, if you use .ToList(), it'll be executed right away.
When to use var comes down to personal choice/style. I generally use var when the return value is understood from the line of code and variable name or if I'm instantiating a generic with a long declartion, e.g. Dictionary<string, Func<Order, object>>.
From your code, it's clear that a collection of Customers/Orders is returned, so I would use the var keyword. Again, this is a matter of personal preference.

Nested query using Linq with ToDictionary

I'm having problems with this query using entity framework 4:
List<SomeResult> test = (from a in _entities.TableA
select new SomeResult
{
TestB = a.TableB.Name,
TestCDict = a.TableC.ToDictionary(x => x.SomeKey, x => x.SomeValue)
}).ToList();
It gives this error:
"Cannot compare elements of type 'System.Data.Objects.DataClasses.EntityCollection`1'. Only primitive types (such as Int32, String, and Guid) and entity types are supported."
How can I redo this query so it'll work? from a in _entities.TableA from c in a.TableC ....ToDictionary(.. ?
/Lasse
The problem is, that you are doing query against database. And LINQ provider that you are using, actually don't execute any of the operations, that you have written. It only tryes to translate all your code in Select into database query. Obviously, it can't parse really complex statents, like you have written with ToDictionary().
You can simply load all data from entities into memory, and then do all your dictionary stuff. Then your code will actually be executed, and should work.
Like:
List<SomeResult> test = from a in (from aa in _entities.TableA).AsEnumerable())
select new SomeResult
{
TestB = a.TableB.Name,
TestCDict = a.TableC.ToDictionary(x => x.SomeKey, x => x.SomeValue)
}).ToList();
Of course you can use DB side filtering in the inner query (before AsEnumerable()) to narrow amount of data loaded into memory.

Nhibernate linq. The where extension method does not add the where clause to the SQL command, why?

I want to add the where clause to a linq statement, but it doesn't behave as i would expected it to.
When i use this code:
IQueryable<Employee> EmpQuery = from e in Session.Query<Employee>() where e.Surname == "Test" select e;
EmpQuery.ToList();
or i use this code:
IQueryable<Employee> EmpQuery = (from e in Session.Query<Employee>() select e).Where(e => e.Surname == "Test");
EmpQuery.ToList();
The where clause is included in the SQL command, but when i try it this way:
IQueryable<Employee> EmpQuery = from e in Session.Query<Employee>() select e;
EmpQuery.Where(e => e.Surname == "Test");
The where clause is not included in the SQL command. Why is this? Is there another way to dynamically add criteria to a Nhibernate Linq query?
You're not using the return value of Where. LINQ is designed around functional concepts - calling Where doesn't modify the existing query, it returns a new query which applies the filter. The existing query remains as it was - which means you can reuse it for (say) a different filter.
Note that your current query expression (from x in y select x, effectively) is pretty pointless. I would suggest simply writing:
var query = Session.Query<Employee>().Where(e => e.Surname == "Test");
Just to clarify on Jon's remark, your implementation would be fine with the following tweak:
IQueryable<Employee> modifiedQuery = EmpQuery.Where(e => e.Surname == "Test");
Then just invoke the appropriate enumerator (ToList, ToArray, foreach) on modifiedQuery. And I wouldn't say that it create a complete new query, but instead creates a query which wraps around the original (kind of along the lines of the adapter pattern). Granted, your example doesn't need the additions, but this is how you would add additional criteria onto an existing LINQ expression, and that is what your question actually asked.

Resources