Timeout exception when querying view by DBML - sql

Using Visual Studio 2010 and DBML, I created small application that deals with SQL 2008 database. The database contains some views and procedures, all of them working fine with`LINQ except only one view. Please see the following code:
public vw_SubmissionCurrentStepInfo GetSubmissionCurrentStepInfo(int SubmissionID, int StepID)
{
return
db
.vw_SubmissionCurrentStepInfos
.Where(entity => entity.SubmissionID == SubmissionID && entity.StepID == StepID)
.FirstOrDefault();
}
It throws the following exception
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding
but it works fine when adding .ToList() to code like that:
return
db
.vw_SubmissionCurrentStepInfos
.Where(entity => entity.SubmissionID == SubmissionID && entity.StepID == StepID)
.ToList()
.FirstOrDefault();
Note I increased the connection string timeout with no effect.

Related

Deadlock with EF 6 entity update but not ExecuteSqlCommand

To handle concurrency in my database:
Client A updates a row
Client B tries to update the same row
Client B needs to wait for Client A to commit his updates
Both Client A & B instance are simulated and using this code:
using (myEntities db = new myEntities ())
{
db.Database.Connection.Open();
try
{
using (var scope = db .Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
{
var test = db.customer_table.Where(x => x.id == 38).FirstOrDefault();
test.bank_holder_name = "CLIENT NAME XXXX";
db.SaveChanges(); <=== CLIENT B stop here while client A still in progress. After CLIENT A finish commit, here will throw *Deadlock found error*"
scope.Commit();
}
}
}
catch (Exception ex)
{
throw;
}
}
This is not what I expected where Client B should wait and not allowed to query any data about row id=38, but somehow it can proceed until SaveChanges and throws an error in the end.
Thus, I suspected this might caused by linq (incorrect row/ table lock)
I edited my code as below:
using (myEntities db = new myEntities ())
{
db.Database.Connection.Open();
try
{
using (var scope = db .Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
{
var test = db.Database.ExecuteSqlCommand("Update customer_table set bank_holder_name = 'CLIENT XXXXX' where pu_id = 38"); <===== Client B is stop here and proceed after Client A is completed
db.SaveChanges();
scope.Commit();
}
}
}
catch (Exception ex)
{
throw;
}
}
Finally, the transaction is working with code above (not linq function). This is so confusing, what linq have done in behind making Transaction working inconsistent behavior?
This is due to the EF code generating two SQL statements: a SELECT for the line:
var test = db.customer_table.Where(x => x.id == 38).FirstOrDefault();
...and a subsequent UPDATE for the SaveChanges() call.
With a serializable isolation level both client A and client B take a shared lock for the duration of the transaction on the record when the SELECT statement is run. Then when one or other of them first tries to perform the UPDATE they cannot get the requisite exclusive lock because the other client has a shared lock on it. The other client itself then tries to obtain an exclusive lock and you have a deadlock scenario.
The ExecuteSqlCommand only requires a single update statement and thus a deadlock does not occur.
The Serializable isolation level can massively reduce concurrency and this example shows exactly why. You'll find that less stringent isolation levels will allow the EF code to work, but at the risk of phantom records, non-repeatable reads etc. These may well however be risks you are willing to take and/or mitigate against in order to improve concurrency.
Don't fetch the entity first. Instead create a "stub entity" and update that, eg
var test = new Customer() { id = 38 };
test.bank_holder_name = "CLIENT NAME XXXX";
db.Entry(test).Property(nameof(Customer.bank_holder_name)).IsModified = true;
db.SaveChanges();
Which translates to
SET NOCOUNT ON;
UPDATE [Customers] SET [bank_holder_name] = #p0
WHERE [id] = #p1;
SELECT ##ROWCOUNT;

SQL connection timeout error with Entity Framework

I am updating the 2600 records in a table at once with entity framework.
It was working previously but now suddenly started throwing the timeout error every time.
The timeout property is set to 150.
Also, multiple users are using the application at the same time.
Below is the code:
foreach (var k in context.Keywords.Where(k => k.CurrentDailyCount > 0))
{
k.CurrentDailyCount = 1;
}
context.SaveChanges();
This is the error I'm facing:
What can be the issue behind this error? It was working fine but suddenly started throwing the timeout error.
var entries = context.Keywords.Where(k => k.CurrentDailyCount > 0) ?? new List<Keyword>();
foreach (var k in entries)
{
k.CurrentDailyCount = 1;
}
await context.SaveChangesAsync();
Store the filtered keywords in a variable to save time it takes to search:
context.Keywords.Where(k => k.CurrentDailyCount > 0)
Ensure
filtered keywords is never null: ?? new List<Keyword>().
Save records Asynchronously: await context.SaveChangesAsync();
At first, you may consider to select only primaryKey field and CurrentDailyCount. you can make it like
context.Keywords.Select(x => new Keyword(){
PrimaryKeyColumn = x.primaryKeyColumn,
CurrentDailyCount = x.currentDailyCount
}).Where(k => k.CurrentDailyCount > 0)
And also you should check the execution time of your sql statement. If CurrentDailyCount column is not indexed, it is no surprise that your Code gets timeout error.
The timeout property is set to 150.
Which timeout are you addressing? is it SQL Connection Timeout or Kestrel Server timeout? If you set SQL timeout period to 150 and the kestrel timeout value is default (Which is 120s) your code interrupts when it reaches to 120 seconds.

How to reset counter of primary key in SQL Server provided by Visual Studio in ASP.Net MVC 5 application [duplicate]

This question already has answers here:
how to Reset AutoIncrement in SQL Server after all data Deleted
(3 answers)
Closed 5 years ago.
For learning purpose, I am developing one web site. And I have hardly run the website 100 times, but I don't know one of the table's primary key has reached 2012 count. And no way I have inserted even 100 records in total. I am not sure how did that happen. Currently, I have just 1 records in the table but their PK is 2013. I want it to reset to 0. I DO NOT Care about records being deleted as the web site is under development.
Below is the behavior:
This is the VS Debugger output:
You can clearly see I have just one record but PK is 2013
Controller Action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CoverLetter coverLetter, HttpPostedFileBase uploadedCoverLetter)
{
var x = User.Identity.GetUserId();
try
{
if (ModelState.IsValid)
{
if (uploadedCoverLetter != null && uploadedCoverLetter.ContentLength > 0)
{
var tempcoverletter = new CoverLetter
{
FileName = System.IO.Path.GetFileName(uploadedCoverLetter.FileName),
ContentType = uploadedCoverLetter.ContentType,
CoverLetterName = coverLetter.CoverLetterName,
CandidateId = User.Identity.GetUserId(),
datetime = System.DateTime.Now
};
using (var reader = new System.IO.BinaryReader(uploadedCoverLetter.InputStream))
{
tempcoverletter.Content = reader.ReadBytes(uploadedCoverLetter.ContentLength);
}
_context.CoverLetters.Add(tempcoverletter);
}
_context.SaveChanges();
return RedirectToAction("CoverLetterCenter");
}
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View("Index");
}
IDENTITY columns is keep track and auto increment by SQL Server, I think it has nothing to do with Entity Framework.
Run this query on SQL Server
DBCC CHECKIDENT ('CoverLetters', RESEED, 1)

Dapper.Net and the DataReader

I have a very strange error with dapper:
there is already an open DataReader associated with this Command
which must be closed first
But I don't use DataReader! I just call select query on my server application and take first result:
//How I run query:
public static T SelectVersion(IDbTransaction transaction = null)
{
return DbHelper.DataBase.Connection.Query<T>("SELECT * FROM [VersionLog] WHERE [Version] = (SELECT MAX([Version]) FROM [VersionLog])", null, transaction, commandTimeout: DbHelper.CommandTimeout).FirstOrDefault();
}
//And how I call this method:
public Response Upload(CommitRequest message) //It is calling on server from client
{
//Prepearing data from CommitRequest
using (var tr = DbHelper.DataBase.Connection.BeginTransaction(IsolationLevel.Serializable))
{
int v = SelectQueries<VersionLog>.SelectVersion(tr) != null ? SelectQueries<VersionLog>.SelectVersion(tr).Version : 0; //Call my query here
int newVersion = v + 1; //update version
//Saving changes from CommitRequest to db
//Updated version saving to base too, maybe it is problem?
return new Response
{
Message = String.Empty,
ServerBaseVersion = versionLog.Version,
};
}
}
}
And most sadly that this exception appearing in random time, I think what problem in concurrent access to server from two clients.
Please help.
This some times happens if the model and database schema are not matching and an exception is being raised inside Dapper.
If you really want to get into this, best way is to include dapper source in your project and debug.

Finding the actual Job number for a particular JDBC SQL connection to iSeries?

I am using the JTOpen JDBC driver to connect to the iSeries (aka AS/400, IBM System-i, IBMi, WTH?!...). I am having problems with a particular statement and it appears I need to go back to the actual SQL job QSQSRVR (or QZDASOINIT?) to find more details. Only problem is that there are hundreds of these on the system. Is there an easy way to determine the job which is actually handling my SQL connection or a particular statement?
From the JT400 javadoc of the class AS400JDBCConnectionHandle :
getServerJobIdentifier
public String getServerJobIdentifier()
throws SQLException
Returns the job identifier of the host server job corresponding to this
connection. Every JDBC connection is
associated with a host server job on
the system. The format is:
* 10 character job name
* 10 character user name
* 6 character job number
Note: Since this method is not defined in the JDBC Connection
interface, you typically need to cast
a Connection object returned from
PooledConnection.getConnection() to an
AS400JDBCConnectionHandle in order to
call this method:
String serverJobIdentifier = ((AS400JDBCConnectionHandle)connection).getServerJobIdentifier();
Returns:
The server job identifier, or null if not known.
Throws:
SQLException - If the connection is not open.
If the remote app can't be modified, there are a couple possibilities on the server side. The most common method is to search for jobs that have a lock on the user profile (*USRPRF) that logged on through a connection. The system won't allow a user profile to be deleted while it's active in a job, so the lock can be handy:
WRKOBJLCK logonuser *USRPRF
The connection itself can also be useful. The NETSTAT command can list connections:
NETSTAT *CNN
The remote IP address can be checked against the listed services to determine the particular connection. The matching system job can be accessed from there.
The following approach is safer in case you are not using connection pooling (no idea why you wouldn't pool your connections :), but...)
public static String getQualifiedJobNumber(Connection connection) throws SQLException, CustomException {
if (connection != null && !connection.isClosed()) {
String jobName = null;
try {
AS400JDBCConnectionHandle handle = ((AS400JDBCConnectionHandle) connection);
if (handle != null) {
jobName = handle.getServerJobIdentifier();
}
}
catch (ClassCastException e) {
try {
AS400JDBCConnection as400Connection = ((AS400JDBCConnection) connection);
if (as400Connection != null) {
jobName = as400Connection.getServerJobIdentifier();
}
}
catch (ClassCastException e2) {
throw new CustomException("Attempting to retrieve an AS400 qualified job number from a non-AS400 connection");
}
}
if (jobName != null && jobName.length() == 26) {
return jobName.substring(20) + "/" + jobName.substring(10, 20).trim() + "/" + jobName.substring(0, 10).trim();
}
}
return null;
}