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);
Related
I read the stack-trace and found that the error comes from oracle.jbo.EntityImpl.lock(). I read that is caused by RowInconsistentException. So the problem is data difference between my database and OAF page.
I put a break-point in the beginning of the method. I saw three interesting child objects: mData, mOrigData and mChanged. I saw that in my case mData content is identical to the database and mOrigData differes. How should I interpret it?
I found that mData means state before OAF operations, and mOrigData - state afterwards. mChanged contains ids of changed attributes. In my case I already had a non-null value in the database (non-null in mData) but on the page I was losing that value and tried to put null into the database (null in mOrigData). The framework decided that it was wrong.
I also had another case: updated_at attribute in the database was larger than in the mData object. It turned out that the database processed the row in the background after 2 seconds, but OAF read the row earlier. When I was trying to commit, OAF found that its state is older in the database and threw the same error.
SCENARIO 1:
I have a SQL Server stored procedure that returns rows/columns. Then in SP Designer (SPD) I create an external content type (ECT) and push to Central Admin (CA). In CA, I assign permissions. On the site, I create an External List (EL) and can view my data. All good.
I change a column name from "Vendor Name" to "Vendor in the procedure. Now I go into SPD to alter the ECT and SOMETIMES it cannot be opened, giving an error:
"The BDC Service application Business Data Connectivity Service is not accessible. The full exception text is: Xml type 'List of xdt:untypedAtomic' does not support a conversion from Clr type 'Guid' to Clr type 'String'."
I didn't see what that had to do with my changes. Undoing my change to the procedure didn't resolve it. I had to delete the ECT and ET and recreate them. However, it sometimes happened again.
SCENARIO 2
While testing to see if it happened again, I discovered it sometimes did not. I had different problems.
After renaming the field in the proc, I went into SPD and successfully opened the ECT and made changes, pushing it CA. In CA, I discovered all permissions had been removed. This is a problem. Why does this happen? How to avoid?
So I redo permissions, then go to the site, where two different "sub" problems occur.
SCENARIO 2 A
The External List is broken and cannot be viewed or updated to show the new column name. I have to delete the list and recreate it. This obviously kills any views and removes it from every page where it was, etc., or anything referencing it. This is a nightmare. How to avoid this? I thought of one way, leading to....
SCENARIO 2 B
Instead of creating an External List, I edited a web page, added a Business Data List (BDL) web part and added my ECT to it. Everything was fine. I then purposely renamed a column in the proc again, opened SPD and (this time) was able to open the ECT, updating the field name. I pushed to CA. All permissions were removed (sigh). I re-added them. Then I went to my web page with my BDL, which was broken. I edited the web part and was able to update it so that data appeared onscreen.
BUT, the old "Vender Name" field was missing (no surprise as I'd renamed it). But the new "Vendor" field was also missing. In the BDL web part, I edited the view, discovering to my surprise that NEITHER field was in the list of fields that could be added to the view. In SPD, I opened the ECT to verify the new field was there (it was). No amount of pushing the ECT to CA, redoing permissions, and editing the BDL resulted in the new field appearing. Then, finally, somehow, the new field appeared onscreen without me ever adding it to the BDL view - caching issue?
THE QUESTION
So now I'm left with two questions:
1. Can you use a External List and avoid the problem above?
2. Why do permissions disappear every time the ECT is updated and how to prevent this?
Thanks.
for Scenario 1: Sharepoint is not cool with the "GUID" datatype. Before committing the change to your ECT, breadcrumb back one level to the ECT (sharepoint will alert you if you're going "too far back" and might lose your changes) and check the datatypes that sharepoint has assigned to each field, if you notice any GUID datatypes, you may have to manually coerce them to varchar in your view/proc and close/reopen the ECT.
Scenario 2: This is likely a timing issue and has happened to me before. What happened is that you created you ECT in designer and saved it, then went to CA to set permissions. if you had no reason to re-update your ECT you would have been all good. But the problem was that you needed to make a change AFTER setting the permissions but probably had left the newly created ECT open in designer. So what you have to do is this - after setting the permissions in CA, DO NOT SAVE ANY CHANGES TO THAT ECT UNTIL YOU VERIFY THAT YOU SEE THE PERMISSIONS YOU SET IN CA IN DESIGNER (this is the box in the upper right). This is the problem : SP designer doesnt let you SET permissions but will HAPPILY override them when saving, so if you see no permissions in designer, then saving that ECT will "reset" the permissions to empty. After setting permissions in designer, you have to wait/refresh (sometimes close and re-open the ECT) the ECT in designer until you see the permissiosn there as well.
Scenario 2B: often making changes to ECTs have to let them "propagate" through to the site (this is just how I envision it, i didnt read this). After making changes I've seen my ECTs break completely (you'll get a correlation ID error that wont be useful) or just not seeing my changes. The solution is "Smoke if ya got em". I usually wait at least 10 minutes after making an update until I start being concerned if the ECT is broken, not displaying my change, etc.
Hope this helps!
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.
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.
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)
"