Concurrency when deleting object in Entity Framework - asp.net

I'm developing a web app using the entity framework. I load a list of objects and bind it to a repeater to show a summary of all the items. The user may click an edit icon or a delete icon for each item in the repeater.
Example:
Item 1 | Edit | Delete
Item 2 | Edit | Delete
...
Editing works fine when using a rowversion column for concurrency because the record is loaded and the values for the ID and rowversion column are persisted in hidden form fields. These "original" values are then available to use later when doing the update.
However, if the user clicks Delete for a record, I load the object from the database, call DeleteObject(), then call SaveChanges(). The problem with this is that when I load the record, it gets the latest rowversion value, so any concurrency checking is rendered useless.
How can I ensure that concurrency checking takes place when deleting a record?

Actually you do not have to load the object from the database, if you want to delete it.
Instead, create an ObjectContext, attach your ObjectToDelete to that context via Attach(), then DeleteObject() and SaveChanges().
Thus you would be able to receive an exception about concurrency.

After reading the answer to this question, I decided to use the following approach.
Use hidden form fields to store the ID and rowversion value.
When the user clicks the delete button, load the object from the database. This object contains a rowversion value that may be different than what is stored in the hidden field.
Assign the rowversion value from the hidden field to the appropriate property
on the object.
Call the object state manager's AcceptChanges() method for this object. This causes the rowversion value that I had stored to be accepted as the "current" value.
Delete the object and call SaveChanges() on the object context.
Therefore, the original rowversion value I stored is passed to SQL when attempting to delete the record and is compared to the current value in the row. If they do not match, an OptimisticConcurrencyException is raised.

A different approach than Andreas H specified would be to use stored procedures to do your deletes. That way you could do concurrency checking and deletion within the stored proc, raising an exception if there is a violation.

Related

Audit.EntityFramework.Core 16.2.1 not tracking Foreign Object changes

In POST request we sent a payload with its Foreign object data and audit GetEntityFrameworkEvent() show correct values.
But when we make a PUT request then Audit.EntityFramework.Core 16.2.1 does not track Foreign Object changes i.e Changes Array Field has same values in every New and Old fields.
That coould be because of the nature of the update operation.
If you don't explicitly retrieve the object before the update, there is no way for the EF ChangeTracker to know the previous values.
Please check https://github.com/thepirat000/Audit.NET/issues/53

Is there a way to use the DBC views to find the last date and time that a database schema was altered?

I would like to find the date and time that any schema modification has taken place on a particular database. Modifications are things like tables or columns that have been created, altered, or dropped. It does not include any data that has been inserted, updated, or deleted.
The reason why I need this is because I am writing a .NET utility that depends heavily on the data returned from dbc.tables, dbc.columns, and dbc.indices. Since querying these views can be a very expensive operation, I want to read it all into custom business objects and then serialize the objects to an XML file stored on disk. This way, I can just deserialize the data when I need it unless the database's current_timestamp is greater than or equal to the datetime of the last schema change, at which point I'll refresh the local XML file with the updated schema.
LastAlterTimestamp - If it is equal to CreateTimestamp then object has not been modified since being created or replaced. It is updated when an attribute specific to that data dictionary object was updated.
For example, DBC.Databases.LastAlterTimestamp is not update when a child object (table, view, macro, stored procedure, function, etc.) is added, removed, or altered. It is updated in situations such as when the password, default role, profile, or account is changed.

LINQ to SQL - updating records

Using asp.net 4 though C#.
In my data access layer I have methods for saving and updating records. Saving is easy enough but the updating is tedious.
I previously used SubSonic which was great as it had active record and knew that if I loaded a record, changed a few entries and then saved it again, it recognised it as an update and didn't try to save a new entry in the DB.
I don't know how to do the same thing in LINQ. As a result my workflow is like this:
Web page grabs 'Record A' from the DB
Some values in it are changed by the user.
'Record A' is passed back to the data access layer
I now need to load Record A again, calling it 'SavedRecord A', update all values in this object with the values from the passed 'Record A' and then update/ save 'SavedRecord A'!
If I just save 'Record A' I end up with a new entry in the DB.
Obviously it would be nicer to just pass Record A and do something like:
RecordA.Update();
I'm presuming there's something I'm missing here but I can't find a straightforward answer on-line.
You can accomplish what you want using the Attach method on the Table instance, and committing via the SubmitChanges() method on the DataContext.
This process may not be as straight-forward as we would like, but you can read David DeWinter's LINQ to SQL: Updating Entities for a more in depth explanation/tutorial.
let's say you have a product class OR DB, then you will have to do this.
DbContext _db = new DbContext();
var _product = ( from p in _db.Products
where p.Id == 1 // suppose you getting the first product
select p).First(); // this will fetch the first record.
_product.ProductName = "New Product";
_db.SaveChanges();
// this is for EF LINQ to Objects
_db.Entry(_product).State = EntityState.Modified;
_db.SaveChanges();
-------------------------------------------------------------------------------------
this is another example using Attach
-------------------------------------------------------------------------------------
public static void Update(IEnumerable<Sample> samples , DataClassesDataContext db)
{
db.Samples.AttachAll(samples);
db.Refresh(RefreshMode.KeepCurrentValues, samples)
db.SubmitChanges();
}
If you attach your entities to the context and then Refresh (with KeepCurrentValues selected), Linq to SQL will get those entities from the server, compare them, and mark updated those that are different
When LINQ-to-SQL updates a record in the database, it needs to know exactly what fields were changed in order to only update those. You basically have three options:
When the updated data is posted back to the web server, load the existing data from the database, assign all properties to the loaded object and call SubmitChanges(). Any properties that are assigned the existing value will not be updated.
Keep track of the unmodified state of the object and use Attach with both the unmodified and modified values.
Initialize a new object with all state required by the optimistic concurrency check (if enabled, which it is by default). Then attach the object and finally update any changed properties after the attach to make the DataContext change tracker be aware of those updated.
I usually use the first option as it is easiest. There is a performance penalty with two DB calls but unless you're doing lots of updates it won't matter.

ASP.NET - uniquely identify session objects with database generated ids

I have an object with multiple collections that is retrieved from a WCF service and stored in the session.
The collections are bound to ListViews on the page, with a final submit button at the bottom.
I want to be able to make changes to this object in the session (add/edit items in the collections), without persisting the changes until the final submit button is clicked.
The problem I'm having is that the ids are created in the db, so all newly added items will have an id of 0. I don't see a way to uniquely identify the collection items unless I add something like a clientID field to the datacontract. I feel like I'm missing something really obvious here.
If these are auto-generated identity values, you can insert additionally guids for each entry.

When assigning values to EntityRef ID fields in Linq to Sql, can EntityRef still delay load?

I've got an ASP.NET MVC app that uses Linq to Sql for data access.
Say I have two objects: An Order object that has a foreign key to a Customer object by CustomerID. So, in my Order class, you would see two properties: an int CustomerID field, and an EntityRef member accessible by a Customer property.
When the edits or submits an Order, my MVC app will update the CustomerID field directly of the Order class, instead of updating the Customer property. This saves us from having to fetch a customer record, and I can use the default model binding code to fill the property automatically as long as the submitted form request has a customerID entry.
This works ok, however, later on in some other part of the code--say a business rules portion, some logic will access the Customer property of the Order object. For example:
if (order.Customer.HasPreviousOrders) then ...
Even though the CustomerID field is set, the Customer field is null, so this business rule throws an exception.
I know Linq 2 Sql uses EntityRefs to do delayed loading. My question is: is there a way to trigger the delayed loading on an object's EntityRef if the ID field has been modified?
We have a dynamic rules engine, so I don't have control of what foreign key objects are going to be needed. I'd rather not have to go through all my controllers to set the EntityRef<> values directly.
Thanks for the help.
Ok, no takers. It looks like what I'm trying to do is just not doable--or maybe not a good idea.
I went ahead and implemented code so I am setting the association object property instead of the ID property so the business rules can be processed.

Resources