Entity Framework ErrorHandlingValueReader - entity-framework

I've got an error that I cannot seem to track down when my page is trying to load a list of files from the server.
I pulled this code out of a TFS shelf-set, and it was running when it was saved.
I have tried breaking down the line where the error occurs (commented out in the code shown) and added extra checks just in case the data happen to have null entries.
Here is a snippet of it:
if (roadmap != null)
{
List<Guid> taskList = lstRoadmapTaskMapping.Select(o => o.TaskGuid).ToList();
var list = SessionManager.CurrentContext.TaskDecisionDetails.Where(x => x.Task != null && x.Task.TaskGuid != null && taskList.Contains(x.Task.TaskGuid));
var lstTaskDecisionDetail = new List<TaskDecisionDetail>(list);
//List<TaskDecisionDetail> lstTaskDecisionDetail = SessionManager.CurrentContext.TaskDecisionDetails.Where(o => taskList.Contains(o.Task.TaskGuid)).ToList();
lstOfTasks = lstTaskDecisionDetail.Select(o => o.TaskToStart).ToList();
lstOfTasks.AddRange(lstTaskDecisionDetail.Select(o => o.AssociatedTaskGuid ?? Guid.Empty).ToList());
lstOfTasks.AddRange(SessionManager.Current.CurrentContext.TaskDecisionDetailRoutes.Where(o => taskList.Contains(o.TaskDecisionDetail.Task.TaskGuid)).Select(o => o.NATaskGuid).ToList());
List<Guid> roadmapMappingGuid = lstRoadmapTaskMapping.Where(o => lstOfTasks.Contains(o.TaskGuid)).Select(o => o.RoadmapTaskMappingGuid).ToList();
treeHL.JSProperties["cp_NoDeleteIDs"] = string.Join(",", roadmapMappingGuid);
}
The exception is thrown at the green highlighted line in the screenshot below:
The error message is this common one:
Object reference not set to an instance of an object.
The question below goes fully into that error message.
What does "Object reference not set to an instance of an object" mean?
That is what got me to break the single line (commented out at the moment) into 2 lines, hoping that would solve my error.
The StackTrace is pointing to the Entity framework:
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetValue(DbDataReader reader, Int32 ordinal)
What else could be null in the expression?
How can I go about debugging this error?
I am also curious about what it means whenever the debugger stops on a green breakpoint instead of a yellow breakpoint.

It turned out that the database had corrupt entries.
Loading the data to an Entity was causing validation errors with its constraints.
I restored the database from a recent version and the issues went away.
I started to just delete this question, but it might help someone down the road.

Had the same issue with Entity Framework for .NET Framework.
Had a class Customer with a nested Dealer class, something like:
class Customer {
int Id;
Dealer Dealer;
}
class Dealer {
int Id;
bool IsActive;
}
The isActive flag on the Database was implemented as 'bit' (1 or 0), but the constraint on that column was that it can also be NULL. During migration the isActive flag was left out from INSERTS so it took on the default value of NULL for some Dealer records.
When running _customerRepository.GetAll() EntityFramework could not map the null to boolean within the Dealer object and apparently the Dealer object was not created, which caused the issue.
Hope that helps anyone.

Related

Entity Framework DbContext Update Fails if No Change in Field Values

When we pass our DbContext an object whose values have not changed, and try to perform an Update we get a 500 internal server error.
A user may open a dialog box to edit a record, change a value, change it back and then send the record to the database. Also we provide a Backup and Restore function and when the records are restored, some of them will not have changed since the backup was performed.
I was under the impression that a PUT would delete and re-create the record so I didn't feel there would be a problem.
For example, having checked that the Activity exists my ActivityController is as follows:
var activityEntityFromRepo = _activityRepository.GetActivity(id);
// Map(source object (Dto), destination object (Entity))
_mapper.Map(activityForUpdateDto, activityEntityFromRepo);
_activityRepository.UpdateActivity(activityEntityFromRepo);
// Save the updated Activity entity, added to the DbContext, to the SQL database.
if (await _activityRepository.SaveChangesAsync())
{
var activityFromRepo = _activityRepository.GetActivity(id);
if (activityFromRepo == null)
{
return NotFound("Updated Activity could not be found");
}
var activity = _mapper.Map<ActivityDto>(activityFromRepo);
return Ok(activity);
}
else
{
// The save failed.
var message = $"Could not update Activity {id} in the database.";
_logger.LogWarning(message);
throw new Exception(message);
};
My ActivityRepository is as follows:
public void UpdateActivity(Activity activity)
{
_context.Activities.Update(activity);
}
If any of the fields have changed then we don't get the error. Do I have to check every record for equality before the PUT? It seems unnecessary.
Perhaps I have missed something obvious. Any suggestions very welcome.
There is a lot of code missing here.
In your code you call your SaveChangesAsync (not the EF SaveChangesAsync).
Probably (but there is not the code to be sure) your SaveChangesAsync is something that returns false if there is an exception (and is not a good pattern because you "loose" the exception info) or if DbSet.SaveChangesAsync returns 0.
I think (but there is a lot of missing code) that this is your case. If you don't make any changes, SaveChangesAsync returns 0.
EDIT
The System.Exception is raised by your code (last line). EF never throws System.Exception.

EF Core 2.0: How to discover the exact object, in object graph, causing error in a insert operation?

I have a complex and big object graph that I want to insert in database by using a DbContext and SaveChanges method.
This object is a result of parsing a text file with 40k lines (around 3MB of data). Some collections inside this object have thousands of items.
I am able to parse the file correctly and add it to the context so that it can start tracking the object. But when I try to SaveChanges, it says:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: String or binary data would be truncated.
I would like to know if there is a smart and efficient way of discovering which object is causing the issue. It seems that a varchar field is too little to store the data. But it's a lot of tables and fields to check manually.
I would like to get a more specific error somehow. I already configured an ILoggerProvider and added the EnableSensitiveDataLogging option in my dbContext to be able to see which sql queries are being generated. I even added MiniProfiler to be able to see the parameter values, because they are not present in the log generated by the dbContext.
Reading somewhere in the web, I found out that in EF6 there is some validation that happens before the sql is passed to the database to be executed. But it seems that in EF Core this is not available anymore. So how can I solve this?
After some research, the only approach I've found to solve this, is implementing some validation by overriding dbContext's SaveChanges method. I've made a merge of these two approaches to build mine:
Implementing Missing Features in Entity Framework Core - Part 3
Validation in EF Core
The result is...
ApplicationDbContext.cs
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
ValidateEntities();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
ValidateEntities();
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
private void ValidateEntities()
{
var serviceProvider = this.GetService<IServiceProvider>();
var items = new Dictionary<object, object>();
var entities = from entry in ChangeTracker.Entries()
where entry.State == EntityState.Added || entry.State == EntityState.Modified
select entry.Entity;
foreach (var entity in entities)
{
var context = new ValidationContext(entity, serviceProvider, items);
var results = new List<ValidationResult>();
if (Validator.TryValidateObject(entity, context, results, true)) continue;
foreach (var result in results)
{
if (result == ValidationResult.Success) continue;
var errorMessage = $"{entity.GetType().Name}: {result.ErrorMessage}";
throw new ValidationException(errorMessage);
}
}
}
Note that it's not necessary to override the other SaveChanges overloads, because they call these two.
The Error tells you that youre writing more characters to a field than it can hold.
This error for example would be thrown when you create a given field as NVARCHAR(4) or CHAR(4) and write 'hello' to it.
So you could simply check the length of the values you read in to find the one which is causing your problem. There is at least on which is too long for a field.

Entity Framework Db.SaveChanges() not working?

Can u tell me what is the problem?
If you are using two different instances of the DbContext (the db variable as you named it) then nothing will be saved when you call SaveChanges on a context different than the one where your entities are tracked. You need to use the Attach method first.
db.customer_images.Attach(item);
db.SaveChanges();
However I think in your case you can avoid the attach step if you refactor a bit you code and don't use the DbContext from the entity itself.
Before going through my answer, you must check, if you are attaching the item as shown in excepted answer or check this code:.
if (dbStudentDetails != null && dbStudentDetails.Id != 0)
{
// update scenario
item.Id = dbStudentDetails.Id;
_context.Entry(dbStudentDetails).CurrentValues.SetValues(item);
_context.Entry(dbStudentDetails).State = EntityState.Modified;
}
else
{
// create scenario
_context.StudentDetails.Add(item);
}
await _context.SaveChangesAsync();
If above solution doesn't work, then check the below answer.
Saw a very wired issue, and thought to must answer this. as this can
be a major issue if you have lots of constraints and indexes in your
SQL.
db.SaveChanges() wasn't throwing any error, but not working (I have tried Exception or SqlException). This was not working because the Unique constraint was not defined properly while creating the Entity Models.
How you can Identified the issue:
I connected my SQL Server and opened the SQL Profiler.
Just before the db.SaveChanges(), I cleared all my profiler logs and ran the db.SaveChanges(). It logged the statement. I copied the script from the profiler and ran the script in SQL Server.
And bingo, I can see the actual error, which is being thrown at SQL Server side.
(images: have some hints, how you can get the execute statement from Profiler and run on sql server)
What you can do For Entity Framework Core:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Students>().HasIndex(p => new { p.RollNumber, p.PhoneNumber }).IsUnique(true).IsClustered(false).HasDatabaseName("IX_Students_Numbers");
}
What you can do For Entity Framework 6 and below:
using System.Data.Entity.ModelConfiguration;
internal partial class StudentsConfiguration : EntityTypeConfiguration<Students>
{
public StudentsConfiguration()
{
HasIndex(p => new { p.RollNumber, p.PhoneNumber }).IsUnique(true).IsClustered(false).HasName("IX_Students_Numbers");
}
}
Try to query your entity by Id, eg:
entity = this.repo.GetById(item.id);
entity.is_front = false;
if (dbSaveChanges() > 0)
{
....
}

Entity Framework Update/Insert

We are using EF 4.0 for performing database operation. we are using following code to save products to database :
public void SaveProduct(Product updatedProduct)
{
using (model)
{
Product originalProduct = model.Products.Single(p => p.ProductID == updatedProduct.ProductID);
if(originalProduct.Any())
{
model.Products.ApplyCurrentValues(updatedProduct);
}
else
{
model.Products.Attach(updatedProdut);
}
model.SaveChanges();
}
}
But while attaching a product, I am getting following error :
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same
key.
Im a little surprised by the code. Would not work in EF6.
Anyway:
Single returns 1 entry or Exception if not found.
EF 4.x had SingleOrDefault, which returns a null if not found.
IEnumerable.Single extension returns T.
Are you sure T supports Any().?
Clearly the error is you cant put the record in to the context twice.
If the single worked but Any() test didnt, that might explain.
See SingleOrDefault.
Consider test for Null instead of any.

Silverlight 4 Entity framework issue

I have created a sample application in Silverlight with RIA services. I am using entity framework for CRUD operation but it does not work for INSERT Operation with following Exception, "Submit operation failed validation. Please inspect Entity.ValidationErrors for each entity in EntitiesInError for more information." I have not apply any validation but don't know how the error occurs.
I have tested that when I create an object of DB entity and assign values to it and then save by calling object.SaveChages(), it works fine. But its default method does not work. Any help is appreciated.
Thanks
The SubmitOperation callback has an EntitiesInError property which you can use to iterate thru the entities. That's the way of getting the "real" error.
Here's the method I have to show the user what went wrong...
public static bool WasSubmittedOK(SubmitOperation so, string errorMessageHeader, out string errorMessage)
{
errorMessage = string.Empty;
if (!so.HasError)
return true;
so.MarkErrorAsHandled();
errorMessage = "An unknown error has occurred";
if (so.EntitiesInError.Count() > 0)
{
StringBuilder builder = new StringBuilder();
builder.AppendFormat("{0}\r\n", errorMessageHeader);
foreach (Entity item in so.EntitiesInError)
{
#if DEBUG
builder.AppendFormat("\r\nFor {0}", item.GetType());
#endif
foreach (ValidationResult error in item.ValidationErrors)
{
builder.AppendFormat("\r\n- {0}", error.ErrorMessage);
Debug.WriteLine(string.Format("Error in {0}:'{1}'", string.Join(",", error.MemberNames.ToArray()), error.ErrorMessage));
}
}
errorMessage = builder.ToString();
}
else if (so.Error != null) { errorMessage = so.Error.Message; }
return false;
}
Are you able to drill into the validation errors? I actually have an article about this coming in December MSDN Magazine Data Points but I bet you don't want to wait, right? :)
Even if you haven't applied any specific validations, there are things like foreign key contsraints that EF will still check. If you can see what the error is that will be ultimately useful in solving your problem. Debug into the exception. See if there is a DbEntityValidationException available...maybe it's in an innerexceptoin. DbEntityValidationException will have one or more EntityValidationErrors. Each of those contains a list of all of the errors found for one instance. That means expanding the EntityValidationErrors items one at a time and looking at the ValidationError items contained within.