'Invalid attempt to read when no data is present' - exception happens "sometimes" in Entity Framework - sql-server

I get the above error sometimes during the read. The exception originates from ASP.NET SqlDataReader whenever you try to read data before calling the Read() method. Since EF does all these internally, I am wondering what else can cause this error. could it be network (or) db connectivity?
thanks
Additional Bounty Info (GenericTypeTea):
I've got the same error after upgrading to EF Code First RC (4.1):
"Invalid attempt to read when no data
is present"
This is the code in question:
using (var context = GetContext())
{
var query = from item in context.Preferences
where item.UserName == userName
where item.PrefName == "TreeState"
select item;
// Error on this line
Preference entity = query.FirstOrDefault();
return entity == null ? null : entity.Value;
}
The table structure is as follows:
Preference
{
Username [varchar(50)]
PrefName [varchar(50)]
Value [varchar(max)] Nullable
}
The table is standalone and has no relationships. This is the DbModelBuilder code:
private void ConfigurePreference(DbModelBuilder builder)
{
builder.Entity<Preference>().HasKey(x => new { x.UserName, x.PrefName });
builder.Entity<Preference>().ToTable("RP_Preference");
}
Exactly the same code works perfectly in CTP5. I'm guessing this is an RC bug, but any ideas of how to fix it would be appreciated.

This error occurs when there is a large amount of data in the RC release. The difference between the RC and CTP5 is that you need to specify the [MaxLength] property that contains a large amount of data.

Are you re-using contexts? I would guess this is happening as a result of something you are doing within GetContext
If GetContext() provides a stale context, in which the DataReader is closed/corrupted, I could see the above happening.

I cannot reproduce your problem on EF4.1 RC1.
POCO:
public class Preference
{
public string UserName { get; set; }
public string PrefName { get; set; }
public string Value { get; set; }
}
Context:
public class PreferenceContext : DbContext
{
public DbSet<Preference> Preferences {get;set;}
public PreferenceContext()
: base("Data Source=localhost;Initial Catalog=_so_question_ef41_rc;Integrated Security=SSPI;") {
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
ConfigurePreference(modelBuilder);
base.OnModelCreating(modelBuilder);
}
private void ConfigurePreference(DbModelBuilder builder)
{
builder.Entity<Preference>().HasKey(x => new { x.UserName, x.PrefName });
builder.Entity<Preference>().ToTable("RP_Preference");
}
}
My little Console App:
class Program
{
static void Main(string[] args)
{
string userName = "Anon";
for (int i = 0; i < 10000; i++)
{
var p = GetPreference(userName);
}
}
private static string GetPreference(string userName)
{
using (var context = new PreferenceContext())
{
var query = from item in context.Preferences
where item.UserName == userName
where item.PrefName == "TreeState"
select item;
// Error on this line
Preference entity = query.FirstOrDefault();
return entity == null ? null : entity.Value;
}
}
}
I do 10,000 reads, and no error. You will need to post more complete code to continue.

Increase the CommandTimeout on the context.

I had the same issue with EF4 - In my case I was (trying to) return the list of entities within the using{} section. This is the same as you are doing in your question:
return entity == null ? null : entity.Value;
} // end using
I moved the return to after the } and it worked.
I think I had the problem because the code was in a function which had already queried the database in another using block, I suspect the table was locking but not reporting the error, ending the using block before the return released the database lock.
Steve

Related

Concurrency control for table generated Transaction Id

I have a system in which I generate the transaction ids based on a table. The number must have a specific format therefore using database sequences is not an option. Moreover, the number transactions types is variable which means creating variable number of sequences. The table has the following structure:
public class TransactionSequence : BaseEntity<int>, IAggregateRoot
{
public int Year { get; set; }
public string Prefix { get; set; }
public long Sequence { get; set; }
public string Service { get; set; }
public int Length { get; set; }
public bool IsCurrent { get; set; }
}
The code for the service which generates the number is as shown below:
public class NumberingService : INumberingService
{
public static int yearLength = 2;
public static int monthLength = 2;
public static int dayLength = 2;
private readonly IRepository<TransactionSequence> _repository;
private readonly NumberingConfiguration _numbering;
public NumberingService(IRepository<TransactionSequence> repository,
NumberingConfiguration numbering)
{
_repository = repository;
_numbering = numbering;
}
public async Task<Result<string>> GetNextNumberAsync(string service, int maxlength, UserEntity sysUser, string prefix = "")
{
string transactionId = string.Empty;
try
{
var spec = new CurrentYearNumberingSpec(service);
var sequence = await _repository.GetBySpecAsync(spec);
if (sequence == null)
{
await AddServiceNumberingAsync(service, maxlength, sysUser, prefix);
sequence = await _repository.GetBySpecAsync(spec);
}
sequence.Sequence = sequence.Sequence + 1;
await _repository.UpdateAsync(sequence);
int month = DateTime.Now.Month;
int day = DateTime.Now.Day;
var length = GetLength(sequence);
transactionId = sequence.Prefix + (sequence.Year % 100).ToString("D" + 2) + month.ToString("D" + 2) + day.ToString("D" + 2) + sequence.Sequence.ToString("D" + length);
}
catch (Exception ex)
{
return Result<string>.Error(ex.Message);
}
return Result<string>.Success(transactionId, "Retrieved the next number in the sequence succesfully!");
}
private static int GetLength(TransactionSequence sequence)
{
return sequence.Length - sequence.Prefix.Length - dayLength - monthLength - yearLength;
}
}
Note: I am only showing an excerpt of the code that contains the relative info!
The problem:
Since the system is highly concurrent, each request tries to obtain a transaction id when submitted. Thus, there is a high contention for TransactionSequence row which is currently active since it will be generating the transaction id via subsequent updates. This means that there will absolutely be locking.
Solutions I tried:
1- Optimistic Concurrency via ROWVERSION with retries, this had the worst performance since optimistic concurrency makes sense only if the collision possibility is rare! But since the collision is almost guaranteed this solution had the worst performance. Either that or I did not implement it correctly!
2- Locking via SemaphoreSlim, this had an acceptable performance but its problem was that it would not scale in load balanced scenarios.
3- Distributed Locking via Redis, this had an approximate performance to SemaphoreSlim but still not the performance I am looking for!
4- Queuing via RabbitMQ with prefetch size of 1, This had a better performance than the aforementioned solutions but still I wonder if there is an optimal solution!
5- Using HiLo algorithm, I did not implement this but I have read about it as in the link below:
CQS with Database-Generated Ids
I want to know if there is a better or a well-known solution to this problem
My Environment:
ASP .NET CORE 6
EF CORE 6
SQL SERVER 2019
I hope this was clear enough, and thanks in advance!

Comparing strings in a JDO query fails when value contains a "Comma"

I am attempting to check for an existing string using a JDO query, in my attempt to prevent the insertion of a duplicate string.
My query to check for an existing string works fine, unless the two strings I am comparing have a comma in the value. If the commas exists, the comparison bombs using "==".
For example, if I query to see if "Architecture" exists, I get the right result (Horrray!).
If I attempt to see if "Architecture, Engineering, and Drafting" exists, and it does, the query comes back and says an identical value does not exist (Boo!).
The code I'm using is as follows:
Called from the RPC
public void addCommas()
{
final Industry e = new Industry();
e.setIndustryName("Architecture, Engineering, and Drafting");
persist(e);
}
public void addNoCommas()
{
final Industry e = new Industry();
e.setIndustryName("Architecture");
persist(e);
}
Persist Operation
private void persist(Industry industry)
{
if (industryNameExists(industry.getIndustryName()))
{
return;
}
final PersistenceManager pm = PMF.get().getPersistenceManager();
pm.currentTransaction().begin();
try
{
pm.makePersistent(industry);
pm.flush();
pm.currentTransaction().commit();
} catch (final Exception ex)
{
throw new RuntimeException(ex);
} finally
{
if (pm.currentTransaction().isActive())
{
pm.currentTransaction().rollback();
}
pm.close();
}
}
Query
public static boolean industryNameExists(final String industryName)
{
final PersistenceManager pm = PMF.get().getPersistenceManager();
Query q = null;
q = pm.newQuery(Industry.class);
q.setFilter("industryName == industryNameParam");
q.declareParameters(String.class.getName() + " industryNameParam");
final List<Industry> industry = (List<Industry>) q.execute(industryName.getBytes());
boolean exists = !industry.isEmpty();
if (q != null)
{
q.closeAll();
}
pm.close();
return exists;
}
JDO Entity
#PersistenceCapable(detachable = "true")
public class Industry implements StoreCallback
{
#NotNull(message = "Industry Name is required.")
private String industryName;
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#PrimaryKey
private Key key;
public Industry()
{
super();
}
public Key getIndustryKey()
{
return key;
}
public String getIndustryName()
{
return industryName;
}
#Override
public void jdoPreStore()
{
if (industryName != null)
{
industryName = industryName.trim();
}
}
public void setIndustryName(final String industryName)
{
this.industryName = industryName;
}
}
Any thoughts on a resolution or pinpointing an oversight would be very much appreciated.
Cheerio.
So you're calling industryNameExists("Architecture, Engineering, and Drafting") and trying to match a JDO with industryName exactly equal "Architecture, Engineering, and Drafting"?
Assuming you don't have any typo or space difference the only thing suspect is the getBytes(). Try the following:
Query q = pm.newQuery(Industry.class, "this.industryName == :industryNameParam");
List<Industry> industry = (List<Industry>) q.execute(industryName);
You can also try variation filters like "this.industryName.equalsIgnoreCase(:industryNameParam)" and "this.industryName.startWith(:industryNameParam)" to troubleshoot.
If it still does not work, try logging the SQL generated for review and compare with a hand-written query that works.

updating values per row in parse.com using android platform

I have a problem with updating values per row in a cloud storage site called parse.com. I am only a newbie in using parse.com. I have read the documentation about it and have understand it. But what I want to do is a little bit different from the example there. Here's my code..
public void onClick(View arg0) {
if (arg0.getId() == R.id.button1) {
ParseQuery query = new ParseQuery("inventory");
query.findInBackground(new FindCallback() {
public void done(List<ParseObject> test, ParseException e) {
ParseObject testObject = new ParseObject("inventory");
if(e==null) {
String str="";
String str2="";
for(int x =0;x<test.size();x++){
str = test.get(x).getString("name");
str2 = test.get(x).getString("quantity");
if (!str.equals(et1.getText().toString())){
str = "";
}
if(str.equals(et1.getText().toString()))
{
testObject.put("quantity", et2.getText().toString());
testObject.saveInBackground();
x = test.size();
}
else{
tv1.setText("error" + e.getMessage());
}
}
}}
});
} }
I want to update the quantity of the product name that i have inputted. when my input is equal to the name on the cloud it will update the other column which refers to the product name that I have inputted. But as a result of my code, it creates a new row, instead of updating the existing row.. what is lacking/wrong in my code? can someone please help me? :) thanks in advance! :)
I'm figuring out the same problem. I have found this:
The answer says to update an existing object, you need to retrieve it first. The retrieve method is given in the documentation on their website.
Edit:
Done! Here is how you do it; first fetch the object and then update the values you want to through the update method.
ParseQuery query = new ParseQuery("UserName");
query.getInBackground("GKIp4pxBrF", new GetCallback() {
public void done(final ParseObject object, ParseException e) {
if (e == null) {
object.put("Name", username);
object.saveInBackground(new SaveCallback() {
public void done(ParseException e) {
object.put("Name", oldname);
}
});
}
else {
e.printStackTrace();
}
}
});
In case you don't know the object code before hand, I suggest you find the required row through a query.

Session-Per-Request with SqlConnection / System.Transactions

I've just started using Dapper for a project, having mostly used ORMs like NHibernate and EF for the past few years.
Typically in our web applications we implement session per request, beginning a transaction at the start of the request and committing it at the end.
Should we do something similar when working directly with SqlConnection / System.Transactions?
How does StackOverflow do it?
Solution
Taking the advice of both #gbn and #Sam Safron I'm not using transactions. In my case I'm only doing read queries so it seems there is no real requirement to use transactions (contrary to what I've been told about implicit transactions).
I create a lightweight session interface so that I can use a connection per request. This is quite beneficial to me as with Dapper I often need to create a few different queries to build up an object and would rather share the same connection.
The work of scoping the connection per request and disposing it is done by my IoC container (StructureMap):
public interface ISession : IDisposable {
IDbConnection Connection { get; }
}
public class DbSession : ISession {
private static readonly object #lock = new object();
private readonly ILogger logger;
private readonly string connectionString;
private IDbConnection cn;
public DbSession(string connectionString, ILogger logger) {
this.connectionString = connectionString;
this.logger = logger;
}
public IDbConnection Connection { get { return GetConnection(); } }
private IDbConnection GetConnection() {
if (cn == null) {
lock (#lock) {
if (cn == null) {
logger.Debug("Creating Connection");
cn = new SqlConnection(connectionString);
cn.Open();
logger.Debug("Opened Connection");
}
}
}
return cn;
}
public void Dispose() {
if (cn != null) {
logger.Debug("Disposing connection (current state '{0}')", cn.State);
cn.Dispose();
}
}
}
This is what we do:
We define a static called DB on an object called Current
public static DBContext DB
{
var result = GetContextItem<T>(itemKey);
if (result == null)
{
result = InstantiateDB();
SetContextItem(itemKey, result);
}
return result;
}
public static T GetContextItem<T>(string itemKey, bool strict = true)
{
#if DEBUG // HttpContext is null for unit test calls, which are only done in DEBUG
if (Context == null)
{
var result = CallContext.GetData(itemKey);
return result != null ? (T)result : default(T);
}
else
{
#endif
var ctx = HttpContext.Current;
if (ctx == null)
{
if (strict) throw new InvalidOperationException("GetContextItem without a context");
return default(T);
}
else
{
var result = ctx.Items[itemKey];
return result != null ? (T)result : default(T);
}
#if DEBUG
}
#endif
}
public static void SetContextItem(string itemKey, object item)
{
#if DEBUG // HttpContext is null for unit test calls, which are only done in DEBUG
if (Context == null)
{
CallContext.SetData(itemKey, item);
}
else
{
#endif
HttpContext.Current.Items[itemKey] = item;
#if DEBUG
}
#endif
}
In our case InstantiateDB returns an L2S context, however in your case it could be an open SQLConnection or whatever.
On our application object we ensure that our connection is closed at the end of the request.
protected void Application_EndRequest(object sender, EventArgs e)
{
Current.DisposeDB(); // closes connection, clears context
}
Then anywhere in your code where you need access to the db you simple call Current.DB and stuff automatically works. This is also unit test friendly due to all the #if DEBUG stuff.
We do not start any transactions per session, if we did and had updates at the beginning of our session, we would get serious locking issues, as the locks would not be released till the end.
You'd only start a SQL Server Transaction when you need to with something like TransactionScope when you call the database with a "write" call.
See a random example in this recent question: Why is a nested transaction committed even if TransactionScope.Complete() is never called?
You would not open a connection and start a transaction per http request. Only on demand. I'm having difficulty understanding why some folk advocate opening a database transaction per session: sheer idiocy when you look at what a database transaction is
Note: I'm not against the pattern per se. I am against unnecessary, too long, client-side database transactions that invoke MSDTC

Silverlight 4 LoadOperation returns null

LoadOperation on the client side returns null? How can I fix it? Is my code correct? Is it a best practice?
Serverside (Domain service:
public IQueryable<State> GetStates()
{
return this.ObjectContext.States.Include("Country") ;
}
//-----------------------------------------------------------------------
Clientside
LoadOperation<State> loadOp;
public IEnumerable<State> Entities()
{
DSCommon _context = new DSCommon();
loadOp = _context.Load(_context.GetStatesQuery());
loadOp.Completed += complete;
loadOp.Completed += new EventHandler(LoadOp_Completed);
return loadOp.Entities;
}
EventHandler complete;
void LoadOp_Completed(object sender, EventArgs e)
{
foreach (var item in loadOp.Entities)
{
/************* item.Country is Null ********************/
}
}
Your question is not very clear as first you say that LoadOperation return null whereas in your code, you state that item.Country is null.
However, I believe that I see the problem.
In you Domain Service you call the Include("Country") method on the States EntityCollection. However, on client side, the State.Country Entity is still null? I had the same issue some time ago. It seems that RIA Services (or WCF) does not return those entities, unless you apply the [Include] attribute on the Entity you want to return like so in a metadata class
[MetadataType(typeof(State.StateMetadata))]
public partial class State
{
internal sealed class StateMetadata
{
private StateMetadata()
{
}
[Include]
public EntityCollection<Country> Country;
}
}
Someone will probably be able to give an explanation on why it works this way. I just know that I had to do it this way around :-)

Resources