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.
Related
I've been working through Adrian Hall's book on integrating Xamarin and Azure Mobile Apps. In Chapter 3 he adds a User table to facilitate "Friends" data. In his implementation, the client authenticates the user and then makes a request to a custom endpoint that either adds the user to the database or updates their record. Here's an abridged version of the method in the custom controller:
[HttpGet]
public async Task<IHttpActionResult> Get()
{
// ...Obtain user info
User user = new User()
{
Id = sid,
Name = name,
EmailAddress = email
};
dbContext.Users.AddOrUpdate(user);
dbContext.SaveChanges();
// ...
}
The trouble is, the 2nd time the same user logs in to the app, this code throws an exception saying
Modifying a column with the 'Identity' pattern is not supported. Column: 'CreatedAt'. Table: 'CodeFirstDatabaseSchema.User'.
This StackOverflow Answer explains that this is because the AddOrUpdate() method nulls out any properties not set on the entity, including CreatedAt, which is an identity column. This leaves me with a couple of questions:
What is the right way to Add or Update an entity if the CreatedAt value cannot be edited? The same SO thread suggests a helper method to look up the existing CreatedAt and apply it to the entity before trying to save it. This seems cumbersome.
Why is this implemented as a custom auth controller that returns a new Auth token when it only needs to add or update a User in a database? Why not use a normal entity controller to add/update the new user and allow the client to continue using the Auth token it already has?
For the CustomAuthController.cs code, see here.
When you focus on what you are trying to do from SQL perspective it would be like:
update dbo.some_table set some_primary_key = new_primary_key where some_primary_key = ...
which would result in cannot update identity column some_primary_key which makes sense.
But if you do have a reason to update the PK you still can do it if you set the identity insert
SET IDENTITY_INSERT dbo.some_table ON;
Then after you made an insert you set it off using similar syntax.
But this is rather exceptional scenario.
Usually there is no need to manually insert PKs.
Now going back to EF.
The error you are getting is telling you that you cannot modify a column with PK, most likely user_id and/or some other columns if you have composite PK.
So, first time round a new user gets created. Second time round, because you are suing GetOrUpdate a user gets udpated but because you are passing PK it breaks.
Solution?
AddOrUpdate was meant to help with seeding the migrations only.
Given its destructive nature I would not recommend using GetOrUpdate anywhere near production.
You can replace GetOrUpdate with two operations Get and Update
Fetch user and then
if not exists then create a new one
or if it does exist then update it
Using EF6 Framework4.5 – Creating my first n-tier app and first EF experience. I have CRUD working but one issue that I have a work-a-around but don’t like it. There must be a better way.
When data object is returned from my UI layer to the DAL layer, it has been detached, so I flag EntityState as “Modified.” But then it updates all columns in the db. Values that were not loaded in the form view (and not submitted) obviously are null and updated to such in the db.
1) My first solution does work:
Store the object in session in the UI layer and loop through the object updating edited values when the form is submitted. Thus, original values are passed back unchanged and updated to original values. I don’t think this would be best practice though.
2) The solution I think I want:
I am looking for a helper function in the DAL layer to loop through all values in the returned object and flag only non-null values as “IsModified” before calling SaveChanges.
I have found examples in C# on how to check for changed value but not null. (I am still a vb guy anyway. Don't hate.)
A) Is solution #2 a good way to do this?
B) Has anyone a piece of good to help me?
Thank you.
BTW, this is my best stab at it so far: (Errors on “CurrentValues”)
Public Overridable Function MarkEntriesModified(entity As Object)
Dim dbEntityEntry = DbContext.Entry(entity)
'Ensure only non-null values are inserted
For Each [property] In dbEntityEntry.CurrentValues.PropertyNames
If Not IsDBNull(dbEntityEntry.CurrentValues.GetValue(Of Object)([property])) Then
dbEntityEntry.[Property]([property]).IsModified = True
End If
Next
Return entity
Try this architecture. So if you are using EF then I suppose you have edmx updated and correctly representing your database objects.
eg: Say you wan to update Customer data in customer table
Create a Customer class.
when you extract a particular customer, get an instance of the
customer created.
pass this instance to the UI
and pass the instance back to Business layer to save
this way you don't loose anything in between.
some sample code
I am not sure if it's a bug, but when i add a new view or a new stored procedure to the model it updates all the tables that exist. So my question is should it work like this and if it should how can i add some new procedure without updating the whole model?
Yes, this is the correct functionality when using the "Update Model" function for EntityFramework. It looks at every database object and updates the EF Model to match what it finds in the database. This is, in part, because the designer does not let you specifically choose which tables or view to update, so it verifies any changes in the database. This allows the model to proactively ensure that when it connects to the database there won't be an error based on the database changing.
I am using GridView in asp .net and editing data with edit command field property (as we know after updating the edited row, we automatically update the database), and I want to use transactions (with begin to commit statement - including rollback) to commit this update query in database, after clicking in some button (after some events for example), not automatically to insert or update the edited data from grid directly to the DB...so I want to save them somewhere temporary (even many edited rows - not just one row) and then to confirm the transaction - to update the real tables in database...
Any suggestions are welcomed...
I've used some good links, but very helpful, like:
http://www.asp.net/learn/data-access/tutorial-63-cs.aspx
http://www.asp.net/learn/data-access/tutorial-66-cs.aspx
etc...
Well,
you can store your edited data in a DataTable in session. and then pass this data table as a bulk insert in to the database. 2 options are available for this
if you are using SQL Server 2005 you can use OpenXML to achieve this, as i have stated here
if you are using SQL Server 2008 youc an use Table Variables like i did here.
i hope it helps
First way:
Create session variable that will contain your DB object (DataTable or mapped objects).
The GridView should work with this instance instead of sending the data to the database.
Once editing is finished you may take the object from the session and save it in the way you normally do.
Second way:
I would use javascript to collect all changes on the client side while he is editing as a array of objects (each object is separate row).
Once the editing done, you can create json string from the collection and pass it to the server.
If your json object configuration is same as server class then you can use JavaScriptSerializer to deserialize your string into collection of object.
After that, you can save your objects in the way you normally do.
I have an application with user and admin sections. If an admin updates data with the help of sql datasource then it's updated the database. However, when we retrieve data with linq query then it's showing its old value rather than the updated value.
After some time, the linq query automatically shows the correct value.
I think its caching the value, but I find myself helpless. Please help me with this.
When you say
when we retrieve data with linq query
Do you mean you call your select methods again or are you using the current in memory objects?
In either case, you can always refresh an entity with :
Context.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, entity)
Make sure that you're using your DataContext efficiently (ideally one per unit of work).
After each update, make sure you call DataContext.SubmitChanges(); to commit your changes back to the database.
Also be aware that any context you instanciate between your changes being added to another context and calling SubmitChanges() will not reflect those changes.