LINQ InvalidOperationException when calling ToList() - entity-framework

I want to update records in a table in my database using the code below:
context.Events
.Where(eventDb => !events.Any(#event => eventDb.Guid == #event.Guid))
.ToList()
.ForEach(eventDb => eventDb.IsCurrent = false);
But every time on calling ToList() I'm getting the following error, which isn't clear to me:
System.InvalidOperationException: The LINQ expression 'event => EntityShaperExpression:
WawAPI.Models.Event
ValueBufferExpression:
ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False
.Guid == event.Guid' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
I'm not sure what I'm doing wrong and I'd appreciate any help.

I think the problem is that you are asking the SQL server to perform a .Any() operation on events which is presumably some sort of in-memory C# object and does not exist on the SQL server and is too complicated to be sent to SQL.
If you extract the Guids from events into a simple list of strings, then that could be simple enough to send to sql. You also need to change your linq query slightly, but I think this will give you the results you are looking for.
var eventGuids = events.select(a=>a.Guid).ToList();
context.Events
.Where(eventDb => !eventGuids.Contains(event.Guid))
.ToList()
.ForEach(eventDb => eventDb.IsCurrent = false);

I think the issue is that EventDb.Guid == #event.Guid can't be converted to the database raw SQL.
What type are the Guid's?
See what happens if you move the ToList() to before the Where clause.

Related

How do I use Entity Framework to find a record in Cosmos with case insensitive conditions

I know tis question has been asked several times on SO but I haven't found a solution that works.
It's clear that Cosmos is capable of case insensitive searches since June 2020 but I haven't managed to find a solution that works with EF.
For example...
await objDbContext.Tags.SingleOrDefaultAsync(t => t.Value.Equals("value", StringComparison.InvariantCultureIgnoreCase))
... throws the following exception:
System.InvalidOperationException: 'The LINQ expression 'DbSet()
.Where(t => t.Value.Equals(
value: "Value",
comparisonType: InvariantCultureIgnoreCase))' could not be translated. Additional information: Translation of the 'string.Equals' overload with a 'StringComparison' parameter is not supported. See https://go.microsoft.com/fwlink/?linkid=2129535 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
I've also tried .ToLower and string.Equals with similar results.
Is there a right way to do it? If not, is there an alternative? I'm happy to store the value in lowercase along side the actual value, to be used for searching only, but it must be updated automatically.
EF Core 5 has now implemented the transactions. Once you have updated you can change this line
await objDbContext.Tags.SingleOrDefaultAsync(t => t.Value.Equals("value", StringComparison.InvariantCultureIgnoreCase));
to
await objDbContext.Tags.SingleOrDefaultAsync(t => t.Value.ToLower() == "value");

Performance issue with fluent query in EF vs SharpRepository

I was having some performance issues using SharpRepository, and after playing around the SQL Query Profiler I found the reason.
With EF I can do stuff like this:
var books = db.Books.Where(item => item.Year == '2016');
if (!string.IsNullorEmpty(search_author))
books = books.Where(item => item.Author.Contains(search_author);
return (books.ToList());
EF will not really do anything until books is used (last line) and then it will compile a query that will select only the small set of data matching year and author from the db.
But SharpRepository evaluates books at once, so this:
var books = book_repo.Books.FindAll(item => item.Year == '2016');
if (!string.IsNullorEmpty(search_author))
books = books.Where(item => item.Author.Contains(search_author);
return (books.ToList());
will compile a query like "select * from Books where Year == '2016'" at the first line, and get ALL those records from the database! Then at the second line it will make a search for the author within the C# code... That behaviour can be a major difference in performance when using large databases, and it explains why my queries timed out...
I tried using repo.GetAll().Where() instead of repo.FindAll().... but it worked the same way.
Am I misunderstanding something here, and is there a way around this issue?
You can use repo.AsQueryable() but by doing that you lose some of the functionality that SharpRepository can provide, like caching or and aspects/hooks you are using. It basically takes you out of the generic repo layer and lets you use the underlying LINQ provider. It has it's benefits for sure but in your case you can just build the Predicate conditionally and pass that in to the FindAll method.
You can do this by building an Expression predicate or using Specifications. Working with the Linq expressions does not always feel clean, but you can do it. Or you can use the Specification pattern built into SharpRepository.
ISpecification<Book> spec = new Specification<Book>(x => x.Year == 2016);
if (!string.IsNullorEmpty(search_author))
{
spec = spec.And(x => x.Author.Contains(search_author));
}
return repo.FindAll(spec);
For more info on Specifications you can look here: https://github.com/SharpRepository/SharpRepository/blob/develop/SharpRepository.Samples/HowToUseSpecifications.cs
Ivan Stoev provided this answer:
"The problem is that most of the repository methods return IEnumerable. Try repo.AsQueryable(). "

Linq To Entities: "Sequence contains no elements" with Count()

In our appliction we have a piece of code with some Linq-queries (EF) that sometimes throws an exception.
This has only happened to the end user, and we are not able to reproduce it so far.
From the logfile we got the following stacktrace for the exception:
System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.Single[TSource](IEnumerable1 source)
at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__3[TResult](IEnumerable1 sequence)
at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable1 query, Expression queryRoot)
at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
at System.Linq.Queryable.Count[TSource](IQueryable1 source)
at MT3.uctXGrid.LoadLayout(String strUniqueID, Boolean rethrowException, List`1 visibleColumns)
In the method LoadLayout there are only 2 instances of Count(), and they are just operating on standard IQueryables which interrogate an entity type based on one integer field and select all fields (no aggregations or anything).
ex:
from p in cxt.genData where datId = ID
In the stacktrace, it seems like internally .Single() is being used which could throw an exception if there are no records.
But why is it using single if we are just calling .Count() ?
How can a query like
(from p in cxt.genData where datId = ID).Count()
throw a "sequence contains no elements" exception?
We have had other strange problems with queries as well, I'm starting to wonder if there are any issues with our version of EF maybe.
We are still on 4.0 at the moment. (Standard version which came with VS2010).
Has anyone got an idea what could be going on here?
Update:
Here are the Linq-to-Entities queries we actually use
Dim qryLastLayout = From t In oContext.genGridLayouts Where t.layID = intCurrentLayoutID
If Not IsNothing(qryLastLayout) AndAlso qryLastLayout.Count <> 0 Then
Dim qryPrintSettings = From p In oContext.genPrintSettings Where p.prtDefault = True
If Not IsNothing(qryPrintSettings) AndAlso qryPrintSettings.Count <> 0 Then
Have you tried using the .Any() method?
if(cxt.genData.Any(x => x.datId == ID))
{
// do something here
}
One thing to be aware of wrt Linq to Entities is that the semantics of Count() are not those of .NET but those of the underlying datasource (somewhat undermining the whole language-integration aspect, but oh well...). I don't think this can cause issues like yours, but you never know.
MSDN link with more details: http://msdn.microsoft.com/en-us/library/vstudio/bb738551.aspx#sectionSection5

result return in zend

I am writing query like this in zend but I am not getting return result in controller file, then what I have to do for this.
$result=$db->query("insert into geofences (`name`,`description`,`polygon`,
`created_timestamp`,`company_id`)
values ('".$formData ['name']."',
'".$formData['description']."',
GeomFromText('POLYGON(($polygon))'),
now(),'".$formData ['company_id']."')
");
return $result;
after a query() statment you have to fetch the results (if you have a SELECT, SHOW, DESCRIBE and EXPLAIN statement).... i think it uses the standard mysqli classes of PHP!
In your case (an insert statement) you have no result to fetch...i think (i'm not sure but i think this is the case) that it returns true on success and false if the query fails.
Look here and here for reference

How can I use a stored procedure in a MySql database with Zend Framework?

I'm recently have learned to use Zend Framework. I did a simple CRUD application. But now I want to use a existing database for a more complex application and I want to know how I call a stored procedure in the Model, how to send parameters, how to read the results and store them in an array in PHP. Please. I appreciate any kind of help :)
It's not too hard. Here's an example of a MySQL stored procedure with an IN parameter, an OUT parameter, and a result set:
CREATE PROCEDURE MyProc(IN i INTEGER, OUT o INTEGER)
BEGIN
SELECT i+10 INTO o;
SELECT i, o;
END
You can call this with the query() method, and pass a parameter:
$stmt = $db->query("CALL MyProc(?, #output)", array(25));
print_r( $stmt->fetchAll() );
The trick is that MySQL stored procs might return multiple result sets (if the proc had multiple SELECT queries for instance). So the API must advance through all result sets before you can execute another SQL query. Or else you get the "Commands out of sync" error.
If you use the PDO_MySQL adapter:
while ($stmt->nextRowset()) { }
If you use the MySQLi adapter, you'll find that Zend_Db_Statement_Mysqli doesn't implement nextRowset(), so you have to call the internal mysqli connection object:
while ($db->getConnection()->next_result()) { }
Once you clear the result sets, you can run subsequent SQL queries, for example to fetch the value of the procedure's OUT parameter:
$stmt = $db->query("SELECT #output");
print_r( $stmt->fetchAll() );
Great answer from Bill. Just for completeness, if you encounter:
SQLSTATE[HY000]: General error: 2053
When using this method to get a result set from your procedure, check your arguments. I refactored a method and was passing NULLs as arguments to the procedure as the variables I'd used were out of scope. Once I'd fixed this silly mistake the problem went away (to be replaced by another):
SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other
unbuffered queries are active. Consider using PDOStatement::fetchAll().
I'm using $stmt->fetchAll() though. I switched to using prepare() and execute() in place of query(). Switching to mysqli from pdo_mysql in my Zend_Db config finally got things working for me. I found this information from the following SO question:
Call Multiple Stored Procedures with the Zend Framework
If someone is looking for ZendFramework 2 \ Zend Expressive using Zend\Db :
There is another way to do this using createStatement() method.
// prepare create statement from adapter
$stmt = $this->getAdapter()->createStatement();
$stmt->prepare('CALL myproc("myVal")');
// execute sql query
$records = $stmt->execute();
// manipulate results
if ($records instanceof ResultInterface && $records->isQueryResult()) {
$resultSet = new ResultSet;
$resultSet->initialize($records);
// return records if found
if (count($resultSet)) {
// return array of result set
return $resultSet->toArray();
}
// if no records found
return array()
}
$db = Zend_Db_Table::getDefaultAdapter();
$stmt = $db->query("CALL procedure()");
$data = $stmt->fetchAll();