LINQ to SQL "1 of 2 Updates failed" on "SubmitChanges()" - c#

I am updating an object of type X and its children Y using LINQ to SQL and then submitting changes and getting this error
Example Code
X objX = _context.X.ToList().Where(x => x.DeletedOn == null).First();
objX.DeletedOn = DateTime.Now;
EntitySet<Y> objYs = objX.Ys;
Y objY = objYs[0];
objY.DeletedOn = DateTime.Now;
_context.SubmitChanges();
On SubmitChanges() I get an exception "1 of 2 Updates failed", no other information as to why that happened. Any ideas?
Also the exception type is
ChangeConflictException

Sooo what was the cause of the problem
- A trigger
I did a sql profiler and saw that
When ObjY's DeletedOn property got updated a trigger updated
ObjX's property (value in table) called CountOfX
which led to an error as the SQL created by LINQ to SQL had the old CountOfX value in it.
Hence the conflict.
If you ever get this error - SQL profiler is the best place to start your investigation
ALSO NOT RELATED TO THE QUESTION
I am testing LINQ to SQL and ADO.net Framework, weirdly this error happened in LINQ to SQL but not in ADO.net framework. But I like LINQ to SQL for its Lazy Loading. Waiting for EF to get outta beta

I'm not sure what the cause of the error may be exactly, but there seem to be a number of problems with the example you've provided.
Using ToList() before the Where() method would cause your context to read the entire table from the DB into memory, convert it to an array; and then in the same line you immediately call Where which will discard the rows you've loaded, but don't need. Why not just:
_context.X.Where(...
The Where method will return multiple items, but the second line in the example doesn't appear to be iterating through each item individually. It appears to be setting the DeletedOn property for the collection itself, but the collection wouldn't have such a property. It should fail right there.
You are using DateTime.Now twice in the code. Not a problem, except that this will produce ever so slightly different date values each time it is called. You should call DateTime.Now once and assign the result to a variable so that everything you use it on gets identical values.
At the point where you have "Y objY = objYs[0]" it will fail if there are no items in the Y collection for any given X. You'd get an index out of bounds exception on the array.
So given this example, I'm not sure if anyone could speculate as to why code modeled after this example might be breaking.

In LINQ2SQL Data Context diagram select the Entity and the field where the count is stored. (A denormalized figure)
Now set the UpdateCheck = Never.

I had this kind of issue. I was debugging running single lines at a time. It turned out another process was modifying this record.
My manual debugging process was slowing down the normal speed of the function. When I ran it all the way to a line after the SubmitChanges method, it succeeded.
My scenario would be less common, but the nature of this error relates to the record becoming superceded by another function/process. In my case it was another process.

Related

Simple LINQ query gets NullReferenceException even though SQL Server table has data

I have a simple Linq query that is failing suddenly. This worked up until yesterday and I have not been able to determine the problem.
The query is simply getting a complete view from SQL Server
using(JobEntities JE = new JobEntities())
{
var BatchData = (from x in JE.vwBatchObjectActiveBatches select x).ToList();
}
Starting yesterday this line gets a
NullReferenceException (Object reference not set to an instance of an object)
My suspicion was that a user put in bad data causing the view to fail on SQL Server, but I have checked SQL Server itself and the view runs fine and populates with data.
This query was running in the middle of a larger function loading data from many places, so I have created a test case where I simply load the main window and run this query directly in the code behind to make sure that nothing else is affecting it, and the query still fails. All other Linq queries that I run in this project work still, only this one fails. The app is not under any production right now, and has been static for several months at least.
When I look at the JE in the watch window I can see the vwBatchObjectActiveBatches and it lists 164 records in the Local section -- this matches the view results on SQL Server. Expanding the Results View shows the null error again.
How can I find and fix whatever is causing this query to fail? Why does the results view show an error but the local Line shows the data that I am attempting to get?
It looks like your database returns NULL where Entity Framework does not expect/allow it. Data returned should be in accordance with the definition of its datamodel objects.
Solution: either 'fix' the data, or fix the query that produces it, or change the definition of your datamodel objects to allow NULL for the conflicting field(s).

MVC: Timeout issue

I'm trying to extract the results of a SQL server view in MVC. The view itself is relatively straightforward and UNIONs a couple of tables together - when run it takes around 2 seconds to return its rows. I've added the view to my model in MVC.
In my controller I have the following code, which is designed to return in JSON format the values from the SQL view:-
public JsonResult GetActivity(string LocalIdentifier)
{
return Json(db.Activities.Where(r => r.LocalIdentifier== LocalIdentifier).ToList(), JsonRequestBehavior.AllowGet);
}
When I try to run this, supplying a valid LocalIdentifier nothing happens for a while and then I get an exception (unhandled in user code) in Visual Studio. For reference, this would generally only return between 30 and 50 rows of data from SQL.
Looking at the Inner Exception I get this error:-
"Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding."
I've done something similar elsewhere in my application and it works fine - I can't see anything wrong with my code in MVC. Is there anything else I could look at to help diagnose and fix this issue?
Update
Interestingly I've just changed the code to extract just one row (just to see what happens - see below) and it runs instantly...could this be a problem with ToList()?? Is there another way of achieving what I'm trying to do that I could try?
public JsonResult GetActivity(string LocalIdentifier)
{
return Json(db.Activities.First(r => r.LocalIdentifier== LocalIdentifier), JsonRequestBehavior.AllowGet);
}
you should try running the resulting query directly on the sql server. I expect that the query runs for more then 30s, resulting in a timeout. The default timeout value is 30s, so the behaviour you're seeing is expected.
2 ways to deal with it:
speed up the query (maybe you're missing an index?)
change the default timeout (but this is not the preferred option in my opinion)
It depends on how db.Activities is defined. If it has properties for other entities (meaning other tables in the database) then these could also be loaded by EF, even though you did not specify so explicitly, because JSON is serializing each object and its properties. Half your database or more could end up being loaded, even from a simple statement like this.
This SO question has several answers that may help you understand better what is going on behind the scenes, and then fix it.
Enable profiling and see the query inside
Launch this query in SSMS and build the query execution plan
Analyse the plan and make the updates to the database - change structure, build index, change query
If the query runs fine in DB then it seems something wrong with your ORM side part and you should search for the problem there

Enumeration of EF stored procedure results

I'm calling a simple stored procedure that returns around 650 rows. There are several joins and the procedure takes about 5-6 seconds. No problem.
Enumerating the results, however, is taking about a minute to complete.
using (var context = new DBContext())
{
var results = context.GetResults(param); //5-6 seconds
var resultList = results.ToList(); //1 minute+
}
I don't use Entity Framework much, but this seems abnormal. Am I doing something wrong? Is there something I can look at to speed this up? The table is huge, but the way I read it, this code should only be enumerating the 650 results... which should take no time at all.
Note: Not sure if this is related, but the time it takes to select all rows from said table is about the same (around a minute)
The solution to my problem was to disable parameter sniffing by creating a copy of the input parameter.
alter procedure dbo.procedure
#param int
as
begin
set nocount on;
declare #paramCopy int
set #paramCopy = #param
...
Based on your recent edit, I have an idea of what's happening. I think that the .GetResults() call is simply getting the query ready to be run, utilizing deferred execution. Only when you are calling .ToList() in the next line is it actually going out and trying to build the entities themselves (hence the time difference).
So why is it taking so long to load? That could be for a number of reasons, including:
You might have lazy loading disabled. This will cause all of the records to be fully loaded, with all of their respective navigational properties as well, and have all of that be tracked by the DbContext. That makes for a lot of memory consumption. You might want to consider turning it on (but not everyone likes having lazy loading enabled).
You are allowing the tracker to track all of the records, which takes up memory. Instead of this, if the data you're grabbing is going to be read-only anyway, you might want to consider the use of AsNoTracking, like in this blog post. That should reduce the load time.
You could be grabbing a lot of columns. I don't know what your procedure returns, but if it's a lot of rows, with lots of different columns, all of that data being shoved into memory will take a loooong time to process. Instead, you might want to consider only selecting as few columns as needed (by using a .Select() before the call to .ToList()) to only grab what you need.

Linq DataContext SubmitChanges InvalidOperationException from ZombieCheck

I am getting an InvalidOperationException when trying to add a row using LinqToSql. We cannot duplicate it in house, and it happens about 0.06% for only one of our customers, always on a relatively simple change to the database. (Single row insert, or single field update)
Message:
This SqlTransaction has completed; it is no longer usable.
Stack Trace:
at System.Data.SqlClient.SqlTransaction.ZombieCheck()
at System.Data.SqlClient.SqlTransaction.Rollback()
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
Here is a sample piece of code (the database autogenerates the primary key)
TableName row = new TableName();
row.Description = "something";
row.Action = "action";
Context.TableName.InsertOnSubmit(row);
Context.SubmitChanges();
We use SQL Server 2008 R2. The inserts and updates do go through on the server. But we still get the exception. There is nothing that should ever prevent these updates and inserts from taking place. No dependencies or other stuff.
How do we stop these exceptions / zombie checks / rollbacks from happening, or what is causing them in the first place?
EDIT:
After further inspection, the database update that being done by the SubmitChanges() is actually occurring. This exception is getting called after the transaction has successfully completed, and the database row is updated to the new value.
One thing to be aware of is that LinqToSql (and EntityFramework) will by default assign null to DateTime fields in your data objects, so if your table has a datetime field it will throw an exception on insert if the datacontext tries to insert that null value.
You can get around this error by either using the datetime2 type in MSSQL (which will allow the "null" value of a DateTime object - 01/01/0001) or manually assigning a valid date to the data object's DateTime field(s) prior to insert/update.
Without a more detailed stack trace, this is the only obvious problem that comes to mind. HTH.
EDIT:
Looks like this isn't entirely uncommon: http://connect.microsoft.com/VisualStudio/feedback/details/588676/system-data-linq-datacontext-submitchanges-causes-invalidoperationexception-during-rollback#details
The root problem seems to be that the internal ADO logic that LinqToSql uses isn't really configured properly for handling transactional rollbacks. From what I can tell, the only real solution is to provide a transaction object to LinqToSql and manage rollbacks yourself, which doesn't really seem all that appealing.

Why is IEnumerable.Count() capped at 200?

Is there a limit to the rows that IEnumerable.Count() (or IQueryable.Count()) using LINQ to SQL? For whatever reason, if my query returns more than 200 records, I only get 200 from IEnumerable.Count(). I've even tried using IEnumerable.LongCount() (even though the number of results shouldn't be high enough to need it). I've also verified that calling COUNT on the database returns more than 200 records.
I've checked MSDN and tried Googling it, but to no avail.
Am I going crazy, or is there something that I'm missing somewhere? I suppose this isn't really a big deal (as the program is inserting the right number of records), but it'd be nice to be able to log the number of records transferred.
Could we see some sample code?
public IEnumerable<Irms_tx_modify_profile_ban> ExtractNewAdmits()
{
var results = from a in _dc.Applications
select (Irms_tx_modify_profile_ban)new RMSProfile
{
//assign column names to property names
};
//Don't know why, but Bad Things happen if you don't put the
//OfType call here.
IEnumerable<Irms_tx_modify_profile_ban> narrowed_results = results.OfType<Irms_tx_modify_profile_ban>();
Program.log.InfoFormat("Read {0} records from Banner.", narrowed_results.Count());
return narrowed_results;
}
The reason for the comment about bad things happening is due to the issues brought up in this thread. What I did just find out is that if I call Count on narrowed_results (IEnumerable), it returns the right amount. If I call it on results (IQueryable), it returns just 200. I'll go ahead and solve Skeet's answer (since he mentioned the difference between IQueryable and IEnumerable), but if anyone is able to explain why this is happening, I'd like to hear it.
I've not heard of anything like that, and it does sound very odd.
The most obvious thing to check is what query is being sent to the database. Also, it matters a great deal whether you're calling Enumerable.Count() (i.e. on an IEnumerable<T>) or Queryable.Count() (i.e. on an IQueryable<T>). The former will be iterating through the actual rows in .NET code to retrieve the count; the latter will put the count into the query.
Could we see some sample code?
EDIT: Okay, so having seen the code:
When you didn't call OfType, it was executing the count at the SQL level. That should have been visible in the SQL logged, and should be reproducible with any other SQL tool.
I suspect you didn't really have to call OfType. You could have called AsEnumerable, or just declared results as IEnumerable<Irms_tx_modify_profile_ban>. The important thing is that the type of the variable decides the extension method to use - and thus where the count is executed.
It's worth noting that your current solution is really inefficient - it's fetching all the data, and counting it but ignoring everything but the count. It would be much better to get the count onto the server side - and while I know that doesn't work at the moment, I'm sure with a bit of analysis we can make it work :)

Categories