Problem with checking an original database record with an edited one - database

I am having problems saving database records using Linq in visual studio 2010 and sql server 2008.
My problem is that when I am editing some records I sometimes check the original database record for validation purposes, only the original entry seems to be updated in real time - I.e. it is already exactly the same as the edited record, before I have submitted the changes!
Could anyone suggest an effective method of coping with this? I have tried using a 2nd database connection or a 2nd data repository to call the original record from the db but it appears to be already changed when I debug it.
public void SaveobjectEdit(object objectToEdit)
{
object originalObject = GetobjectById(objectToEdit.Id);
if (originalObject.objectStatus != objectToEdit.objectStatus)
{
originalObject.objectStatus = objectToEdit.objectStatus;
}
SaveChanges();
}
The save changes just calls _db.SubmitChanges(); by the way
Has no one got any ideas for the above question?
I hope I was clear - for validation purposes I would like to compare an original database record with one that I am editing. The problem is that when I edit a record and then attempt to retrieve the original record before saving - the original record is exactly the same as the edited record.

If you're trying to retrieve the original record in code, from the same 'context' using the same access method, then it will contain the updated object. Rather than ask why you're doing this or what you're trying to achieve, I'll instead explain how I understand the data context / object context to work (in a very loose and vague fashion).
The context is something like an in-memory representation of your database, where everything is lazy-loaded. When you instantiate the context you're given an object which represents your data model (of course it may not be a 1-1 representation, and can contain various abstractions). Nothing is loaded into the context until necessary; any queries you write stay as queries until you peer in their results. When you access an item (e.g. GetobjectById(objectToEdit.Id)) the item is loaded into the context from the database and you can get and set its properties at your leisure.
Now, the important part: When you access an item, if it has already been loaded into the context then that in-memory object is returned. The context doesn't care about checking changes made; the changes won't be persisted to the database until you submit, but they remain in memory.
The way to refresh the in-memory objects is to call the Refresh method on the context. Try this test:
using (var db = new MyObjectContext())
{
var item = db.Items.First();
item.Name = "testing this thing";
Console.WriteLine(db.Shifts.First().Name);
db.Refresh(System.Data.Objects.RefreshMode.StoreWins, db.Items);
Console.WriteLine(db.Shifts.First().Name);
}
I believe this pattern makes a lot of sense and I'm not sure it could work any other way. Consider this:
foreach (var item in db.Items)
{
item.Name = "test";
}
Assert(db.Items.All(item => item.Name == "test"));
Would you want the Assert to fail? Should those items be reloaded? I don't believe so. I'm looking at the items in my context, not in the database. I'm not checking whether items in the database have been updated, but instead that I've updated all the items in the context of my code.
This is a good reason why I don't use MyObjectContext db - it is not a 'db' or a database connection. It's a context within which I can change whatever I want, so I name it such: MyObjectContext context.

Related

in Entity Framework, DbSet.Local remains out of sync

This one is making me crasy : I have an EF model built upon a database that contains a table named Category with 6 rows in it.
I want to display this in a drop down list in WPF, so I need to bind it to the Categories.Local Observable collection.
The problem is that this observable collection never receives the content of the database table. My understanding is that the collection should get in sync with the database when performing a query or saving data with SaveChanges() So I ran the followin 2 tests :
Categories = _db.Categories.Local;
// test 1
Debug.WriteLine(_db.Categories.Count());
Debug.WriteLine(_db.Categories.Local.Count());
// test 2
_categories.Add(new Category() { CategoryName = "test" });
_db.SaveChanges();
Debug.WriteLine(_db.Categories.Count());
Debug.WriteLine(_db.Categories.Local.Count());
Debug.WriteLine(_categories.Count());
The test 1 shows 6 rows in the database, and 0 in local.
The test 2 shows 7 rows in the database, and 1 in local (both versions)
I also atempted to use _db.Category.Load() but as expected, it doesn't work because it is db first, not code first.
I also went through this page https://msdn.microsoft.com/en-us/library/jj574514(v=vs.113).aspx, created an object-based data source and linked my combo box to it, without success.
Does anyone know what I am doing wrong?
Thank you in advance for your help.
The DbSet<T> class is IQueryable<T>, hence DbSet<T>.Count() method maps to Queryable.Count<T> extension method, which in turn is translated to SQL query and returns the count of the records in the database table without loading anything into db context local cache.
While DbSet<T>.Local simply gives you access to the local cache. It contains the entities that you added as well as the ones being loaded by query that returns T instances (or other entities referencing T via navigation property). In order to fully load (populate) the local cache, you need to call Load:
_db.Categories.Load();
The Load is a custom extension method defined in QueryableExtensions class, so you need to include
using System.Data.Entity;
in order to get access to it (as well as to typed Include, XyzAsync and many other EF extension methods). The Load method is equivalent of ToList but without overhead of creating additional list.
Once you do that, the binding will work. Please note that the Local will not reflect changes made to the database through different DbContext instances or different applications/users.

Cakephp 3 - Building an entity over several forms/actions

This is a design question.
I'm trying to build a booking system in cakephp3.
I've never done something like this with cake before.
I thought the best way might be to -- as the post title suggests -- build up an entity over several forms/actions.
Something like choose location -> enter customer details -> enter special requirements -> review full details and pay
So each of those stages becomes an action within my booking controller. The view for each action submits its content to the next action in the chain, and i use patch entity with the request data, and send the result to the new action's view.
I've started to wonder if this is a good way to do it. One significant problem is that the data from each of the previous actions has to be stored in hidden fields so that it can be resubmitted with the new data from the current action.
I want the data from previous actions to be visible in a read only fashion so I've used the entity that i pass to the view to fill an HTML table. That's nice and it works fine but having to also store that same data in hidden fields is not a very nice way to do it.
I hope this is making sense!
Anyway, I thought I'd post on here for some design guidance as i feel like there is probably a better way to do this. I have considered creating temporary records in the database and just passing the id but i was hoping I wouldn't have to.
Any advice here would be very much appreciated.
Cheers.
I would just store the entity in the DB and then proceed with your other views, getting data from the DB. Pseudo:
public function chooseLocation() {
$ent = new Entitiy();
patchEntity($ent,$this->request->data);
if save entity {
redirect to enterCustomerDetails($ent[id]);
}
}
public function enterCustomerDetails($id) {
$ent = $this->Modelname->get($id);
// patch, save, redirect again ...
}

savid data to an underlying data base via strongly typed data set

My question may be quite stupid but I'm an absolute beginner, and I have a top urgent project to do.
I have created a WinForm app which works with a database containing several tables.
One of the tables is a users table which contains the following columns:
UserID - int, is identity = true| increment 1.
UserName - nvarchar.
Password - nvarchar.
VS2010 created a strongly typed Data set for me automatically, when I added the DB to my project.
I have created a form in which I have several text boxes. This form has a button that should update my dataset with information from several textboxes and than update the underlying database via the dataadapter.update() method.
Unfortunatly the data is never updated to the underlying database, I don't understand why and need your help. Thanks.
code sample (button click event):
LoginDataSetTableAdapters.LoginTableAdapter useraddadapter = new LoginDataSetTableAdapters.LoginTableAdapter();
LoginDataSet useraddset = new LoginDataSet();
LoginDataSet.LoginRow adduser = useraddset.Login.NewLoginRow();
adduser.UserName = textBoxUserName.Text;
adduser.Password = textBoxPassword.Text;
adduser.Email = textBoxEmail.Text;
adduser.Position = textBoxPosition.Text;
useraddset.Login.AddLoginRow(adduser);
useraddset.Tables[0].AcceptChanges();
useraddadapter.Update(useraddset.Login);
Calling the AcceptChanges method will commit all changes in the DataSet or DataTable. If it is called before the Update method is called, no changes will be committed when the Update method is called, unless further changes have been made since AcceptChanges or AcceptChanges was called.

How does the LINQ RefreshMode work?

In case of conflict, I need to overwrite the values in the database with my changes . I found the following article on MSDN that explains how to resolve conflicts using the RefreshMode:
http://msdn.microsoft.com/en-us/library/system.data.linq.refreshmode.aspx
I decided KeepCurrentValues makes sense for my requirement and I also found this page with an example for this mode:
http://msdn.microsoft.com/en-us/library/bb399421.aspx
However when I implemented this the values from the database always overwrote my changes. I tried changing the RefreshMode to OverwriteCurrentValues and KeepChanges and each time the values from the database were saved. My approach was to manually change values in the database while in debug mode in VisualStudio. The code in VS is:
[MyDataContext] db = new [MyDataContext]();
try
{
[MyLINQType] old = (from o in db.[MyLINQType] where o.ID=1 select o).Single();
old.IntField = 55;
// This is where I change the IntField value manually in the database in
// debug mode to generate the conflict.
db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException)
{
db.ChangeConflicts.ResolveAll(RefreshMode.KeepCurrentValues);
}
I know that the conflict appears but every time, no matter how I change the RefreshMode, the value 55 is never saved and the changes that I made manually in the database are kept. Is there some trick to achieve the desired result? I have tried generating the conflict from inside the code at first and that didn't work as expected either. Maybe I didn't understand how the RefreshMode should work. Any ideas are welcome.
You just need to call SubmitChanges again...
catch (ChangeConflictException)
{
db.ChangeConflicts.ResolveAll(RefreshMode.KeepCurrentValues);
db.SubmitChanges();
}
The conflict resolution method determines the state of the DataContext and not the underlying database.
KeepCurrentValues means keep all values as they are currently in the DataContext, which means the next call to SubmitChanges will save any changes made by the user, but it will also overwrite any changes made by other users after the data was loaded by the current user.
KeepChanges means keep only the values that have been changed since being loaded into the DataContext, which means the next call to SubmitChanges will save any changes made by the user and will preserve any changes made by other users. And, if another user changed the same value as the current user, the current user's change will overwrite it.
OverwriteCurrentValues means update the DataContext with the current database values, which means that all changes made by the current user will be discarded.
Before changing data, you refresh your object by overwriting from Db :
[MyLINQType] old = (from o in db.[MyLINQType] where o.ID=1 select o).Single();
Db.Refresh(RefreshMode.OverwriteCurrentValues, old);
old.IntField = 55;
db.SubmitChanges(ConflictMode.ContinueOnConflict);

How can I retrieve latest from database using NHibernate after an update?

Here is the scenario:
I have a winforms application using NHibernate. When launched, I populate a DataGridView with the results of a NHibernate query. This part works fine. If I update a record in that list and flush the session, the update takes in the database. Upon closing the form after the update, I call a method to retrieve a list of objects to populate the DataGridView again to pick up the change and also get any other changes that may have occurred by somebody else. The problem is that the record that got updated, NHibernate doesn't reflect the change in the list it gives me. When I insert or delete a record, everything works fine. It is just when I update, that I get this behavior. I narrowed it down to NHibernate with their caching mechanism. I cannot figure out a way to make NHibernate retrieve from the database instead of using the cache after an update occurs. I posted on the NHibernate forums, but the suggestions they gave me didn't work. I stated this and nobody replied back. I am not going to state what I have tried in case I didn't do it right. If you answer with something that I tried exactly, I will state it in the comments of your answer.
This is the code that I use to retrieve the list:
public IList<WorkOrder> FindBy(string fromDate, string toDate)
{
IQuery query = _currentSession.CreateQuery("from WorkOrder wo where wo.Date >= ? and wo.Date <= ?");
query.SetParameter(0, fromDate);
query.SetParameter(1, toDate);
return query.List<WorkOrder>();
}
The session is passed to the class when it is constructed. I can post my mapping file also, but I am not sure if there is anything wrong with it, since everything else works. Anybody seen this before? This is the first project that I have used NHibernate, thanks for the help.
After your update, Evict the object from the first level cache.
Session.Update(obj);
Session.Evict(obj);
You may want to commit and/or flush first.
what about refresh? - see 9.2. Loading an object of the docs:
"sess.Save(cat);
sess.Flush(); //force the SQL INSERT
sess.Refresh(cat); //re-read the state (after the trigger executes)
"

Resources