Entity Framework throws DBUpdateConcurrencyException if table has trigger defined - asp.net

While working on RESTful service in ASP.NET with support of Entity Framework and SQL Server 2014 as DB engine, I met some unexpected obstacle on my way.
I've prepared some dummy case which exactly explains what kind of problem I'm facing right now.
I've got database in SQL Server named "dummy_database". It contains only one table - Person - and one trigger - TR_Person_Insert - which is responsible for adding some extra data (current date and time in this particular case) to every single record before add the record to the "Person" table. Code of database structure is included below:
USE dummy_database;
GO
IF EXISTS (SELECT * FROM sys.tables WHERE name LIKE 'person')
DROP TABLE [person];
GO
IF EXISTS (SELECT * FROM sys.triggers WHERE name LIKE 'TR_Person_Insert')
DROP TRIGGER [TR_Person_Insert];
GO
CREATE TABLE [dbo].[person]
(
[id] INT IDENTITY(1, 1),
[name] NVARCHAR(256) NOT NULL,
[surname] NVARCHAR(256) NOT NULL,
[age] INT NOT NULL,
[valid_from] DATETIME2 (7),
CONSTRAINT PK_Person_ID PRIMARY KEY ([id])
)
GO
CREATE TRIGGER TR_Person_Insert ON [dbo].[person]
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO [dbo].[person] ([name], [surname], [age], [valid_from])
SELECT i.[name], i.[surname], i.[age], GETDATE()
FROM inserted i
END
GO
Then I created dummy RESTful Service using ASP.NET and added Entity Framework with Database First approach to it. The code of one and only existing method of that Service is as below:
[RoutePrefix("api/person")]
public class DummyController : ApiController
{
[HttpPost, Route("")]
public IHttpActionResult AddPerson(PersonDto data)
{
using (var ctx = new DummyDatabaseModel())
{
var person = new person
{
name = data.Name,
surname = data.Surname,
age = data.Age
};
ctx.people.Add(person);
ctx.SaveChanges();
}
return Ok();
}
}
The problem is with saving changes method called on database's context. This method throws DBUpdateConcurrencyException exception with additional information as below:
An exception of type 'System.Data.Entity.Infrastructure.DbUpdateConcurrencyException' occurred in EntityFramework.dll but was not handled in user code
Additional information: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded.
I'm aware of the fact that this exception is caused by trigger, which is fired instead of regular 'insert' routine on database's side.
The question I ask is - how to get rid of this kind of exception without abandoning trigger in database. I'm out of ideas and to be frank - I count on your tips or solutions, if you faced same problem in the past.
Thank you for your help.

I had the same problem, in my case, the trigger was the expression "instead of insert"
Ex.
Create trigger TR_AA on TbAA INSTEAD OF INSERT ....
I changed the expression by "AFTER INSERT" It's work for me!
Ex.
Create trigger TR_AA on TbAA AFTER INSERT ....

Related

random EntityValidationErrors (The field is required)

I've been trying to update an Entity using the following code:
var db = new MyContext();
var data = db.Tableau.Find(Id);
if (data != null)
{
data.Name = model.Name;
data.EmbedCode = model.EmbedCode;
db.SaveChanges();
}
The problem is that my Tableaus table has a Parent field (FK not null to a DataTree table). Sometimes when I save the changes to this edited record, I get an error saying that "The Parent field is required". But I am not editing the Parent field. The parent field should be intact and existent, since I am only altering the Name and EmbedCode fields.
How to proceed? Thanks in advance.
That is because you are allowing null values in ParentId column in your Tableaus table, but in your Tableau entity you have ParentId as non-nullable property( which it means the relationship is required), and when you load a Tableau instance from your DB, EF expects that you set that property too. Try changing that property to nullable:
public int? ParentId {get;set;}
If you configure your relationship using Fluent Api it would be:
modelBuilder.Entity<Tableau>()
.HasOptional(t=>t.Parent)
.WithMany(dt=>dt.Tablous)// if you don't have a collection nav. property in your DataTree entity, you can call this method without parameter
.HasForeignKey(t=>t.ParentId);
Update 1
If you want ParentId property as Required in your Tableau entity, you need to make sure that you have a valid value in that column in your DB per each row. With a "valid value" I mean it should be different of the default value and it should exist as PK in your DataTree table.
Update 2:
One way to load a related entity as part of your query is using Include extension method:
var data = db.Tableau.Include(t=>t.Parent).FirstOrDefault(t=>t.Id==Id);

Linq-To-Sql SubmitChanges Not Updating Database

I've read multiple questions similar to this one but none are exactly my situation.
Using linq-to-sql I insert a new record and submit changes. Then, in the same web request, I pull that same record, and update it, then submit changes. The changes are not saved. The DatabaseContext is the same across both these operations.
Insert:
var transaction = _factory.CreateTransaction(siteId, userId, questionId, type, amount, transactionId, processor);
using (IUnitOfWork unitOfWork = UnitOfWork.Begin())
{
transaction.Amount = amount;
_transactionRepository.Add(transaction);
unitOfWork.Commit();
}
Select and Update:
ITransaction transaction = _transactionRepository.FindById(transactionId);
if (transaction == null) throw new Exception(Constants.ErrorCannotFindTransactionWithId.FormatWith(transactionId));
using (IUnitOfWork unitOfWork = UnitOfWork.Begin())
{
transaction.CrmId = crmId;
transaction.UpdatedAt = SystemTime.Now();
unitOfWork.Commit();
}
Here's the unit of work code:
public virtual void Commit()
{
if (_isDisposed)
{
throw new ObjectDisposedException(GetType().Name);
}
_database.SubmitChanges();
}
I even went into the designer.cs file and put a breakpoint on the field that is being set but not updated. I stepped through and it entered and execute the set code, so the Entity should be getting "notified" of the change to this field:
public string CrmId
{
get
{
return this._CrmId;
}
set
{
if ((this._CrmId != value))
{
this.OnCrmIdChanging(value);
this.SendPropertyChanging();
this._CrmId = value;
this.SendPropertyChanged("CrmId");
this.OnCrmIdChanged();
}
}
}
Other useful information:
ObjectTracking is enabled
No errors or exceptions when second SubmitChanges is called (just silently fails update)
SQL profiler shows insert and select but not the subsequent update statement. Linq-To-Sql is not generating the update statement.
There is only one database, one database string, so the update is not going to another database
The table has a primary key.
I don't know what would cause Linq-To-Sql to not issue the update command and not raise some kind of error. Perhaps the problem stems from using the same DataContext instance? I've even refreshed the object from the database using the DataContact.Refresh method before it is pulled for the update, but that didn't help.
I have found what is likely to be the root cause. I am using Unity. The initial insert is being performed in a service class with a PerWebRequest lifetime. The select and update is happening in a class with a Singleton lifetime. So my assumption that the DataContext instances are the same was incorrect.
So, in my class with the Singleton lifetime, I get a fresh instance of the database repository and perform the update and no problem.
Now I still don't know why the original code didn't work and my approach could still be considered more a workaround than a solution, but it did solve my problem and hopefully will be useful to others.

Get Record ID in Entity Framework after insert

I'm developing an ASP.net application using Entity Framework. I'm using DetailsView to insert data into database. There is a table as Client and its primary key is client_id. client_id is auto generated by database. I need to get auto generated client_id after inserting a record into Client table and assign it to a hidden field for future use.
I searched about this and I found lot of solutions. But I don't know how to use them since I'm new to asp.net. I found that Entity Framework automatically populates business objects with the db-generated values after call SaveChanges(). My question is where should I call this in my partial class ? What is the event ?
I'm using DetailsView with EntityDataSource and binding EntityDataSource directly with Entity Model, so I'm not creating objects to insert data.
Following the call to _dbContext.SaveChanges(), the entity will automatically be updated with its new identity field value.
The following code assumes your Entity Framework entity container name is MyEntities, and your database's Client table has at least the two following fields:
client_id int identity
client_name varchar(25)
Your code might look something like this:
// Establish DbContext
private readonly MyEntities _dbContext = new MyEntities();
// Create new client table entity and initialize its properties
var clientEntity = new Client { client_name="MyCo" };
// Add it to the ORM's collection of Client entities
_dbContext.Clients.Add(clientEntity);
// Save the new entity to the database
_dbContext.SaveChanges();
// Return the identity field from the existing entity,
// which was updated when the record was saved to the database
return clientEntity.client_id;
After you have inserted the entity it should be updated so that the property that maps to the primary key in the database has the new PK value.
Like MyObject.Id will give you the new Id
This is what I'm looking for.
in partial class
protected void clientDataSource_OnInserted(object sender, EntityDataSourceChangedEventArgs e )
{
int newPrimaryKey = ((Client)e.Entity).ClientId;
Debug.WriteLine(" Client ID is " + newPrimaryKey);
}
and added below line in EntityDataSource in aspx page.
OnInserted="clientDataSource_OnInserted"
Thanks, I spent 3 days searching and searching with complicated results but this solution is brilliant! Here it is in vb.net:
Protected Sub dvArticulos_ItemInserted(sender As Object, e As EntityDataSourceChangedEventArgs) Handles EntityDataSource1.Inserted
Dim last_Serie As Long = DirectCast(e.Entity, articulos).Serie
Session("Articulo") = last_Serie
End Sub

Updating object with related entities from detached state

When I query from the entity framework I always query in a detached state so that the records retrieved can be stored in cache for subsequent requests.
Right now I have a form that the user can edit which contains a parent record, and then two lists of parent records.
When the data is POSTed to the server, I take my view models and map them into the entity framework objects using AutoMapper. The data looks fine; AutoMapper is mapping the data correctly.
When I attach the object so that I can update it, an exception is thrown: A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.
public static void UpdateOrder(ShippingOrder shippingOrder) {
using (OrderEntity orderContext = new OrderEntity()) {
//Exception happens here
orderContext.ShippingOrders.Attach(shippingOrder);
//Update the order itself; mark the order has being modified so the EF will update it.
orderContext.ObjectStateManager.ChangeObjectState(shippingOrder, System.Data.EntityState.Modified);
//Perform the update.
orderContext.SaveChanges();
}
}
The EntityFramework (EF) seems to think that my keys aren't lining up, but I'm not sure what isn't correct. The foreign key property does have the correct value, so I'm not sure what it's checking. Does anyone have any ideas?
You might try something like this:
ShippingOrder existingShippingOrder = orderContext.ShippingOrders.Find(shippingOrder.ID);
orderContext.Entry(existingShippingOrder ).CurrentValues.SetValues(shippingOrder);
Instead of
orderContext.ObjectStateManager.ChangeObjectState(shippingOrder, System.Data.EntityState.Modified);
try this
orderContext.Entry(ShippingOrder).State = EntityState.Modified;
as explained here
Insert or update pattern A common pattern for some applications is to
either Add an entity as new (resulting in a database insert) or Attach
an entity as existing and mark it as modified (resulting in a database
update) depending on the value of the primary key. For example, when
using database generated integer primary keys it is common to treat an
entity with a zero key as new and an entity with a non-zero key as
existing. This pattern can be achieved by setting the entity state
based on a check of the primary key value. For example:
public void InsertOrUpdate(DbContext context, Unicorn unicorn)
{
context.Entry(unicorn).State = unicorn.Id == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
you can try
public static void UpdateOrder(ShippingOrder shippingOrder) {
using (OrderEntity orderContext = new OrderEntity()) {
orderContext.Entry(shippingOrder).State = shippingOrder.Id==0?
EntityState.Added :
EntityState.Modified;
orderContext.SaveChanges();
}
}
UPDATE:
for ObjectContext class you can try
public static void UpdateOrder(ShippingOrder shippingOrder) {
using (OrderEntity orderContext = new OrderEntity()) {
orderContext.ObjectStateManager.ChangeObjectState(shippingOrder, EntityState.Modified);
orderContext.SaveChanges();
}
}

attaching an entity with a related entity to a new entity framework context

Im trying to get my head around attaching an entity with a related entity to a new context when I want to update the entity.
I have a Person Table (Generalised to Personnel), which has a LanguageID field. This field is linked as a FK via the EF to another table Language with LanguageID as the primary key (1-M). I need to update a particular Persons language preference, however, the relationship seems to remain linked to the old context as i get a "Object cannot be referenced by multiple instances of IEntityChangeTracker" error on the line marked below. Is there any way to attach the Language entity to the new context as a relationship of the Personnel (Person) entity???
The entities were not detached in the orginal GetPersonnel() method which uses an .Include() method to return the PreferredLanguage
PreferredLanguage is the NavigationProperty name on the Person table...
public static void UpdateUser(Personnel originalUser, Personnel newUser )
{
using (AdminModel TheModel = new AdminModel())
{
((IEntityWithChangeTracker)originalUser).SetChangeTracker(null);
((IEntityWithChangeTracker)originalUser.PreferredLanguage).SetChangeTracker(null);
TheModel.Attach(originalUser);--Error Line
TheModel.ApplyPropertyChanges("Person", newUser);
TheModel.SaveChanges();
}
}
Thanks
Sean
To avoid these sort of problems you should make GetPersonnel() do a NoTracking query.
I.e.
ctx.Person.MergeOption = MergeOption.NoTracking;
// and then query as per normal.
This way you can get a graph of connected entities (assuming you use .Include()) that is NOT attached. Note this won't work if you try to manually detach entities, because doing so schreds your graph.
Hope this helps
Alex

Resources