SPListItem Save conflict while Update - c#

(1) var list1 = web.GetList("/lists/list1");
(2) var item1 = list1.GetItemById(10001);
(3) ...
take breakpoint here, open item with ID = 10001 for edit, change 'Title' fields and save it. Then run code follow:
(4)item1[SPBuiltInFieldId.Title] = "some text";
(5)item1.Update();
row (5) throws save conflict exception.
How can to lock item for edit at line (3)? Or any other approach to avoid conflict?

You have to check the SPListItem manually
try
{
var item = list.GetItemById(3);
item["MyField"] = "FooBar";
item.Update();
}
catch(SPException conflictEx)
{
// handle conflict by re-evaluating SPListItem
var item = list.GetItemById(3);
// ..
}
I don't know any other mechanism atm.

// *create a new SPWeb object for each list modification otherwise
we'll get Save Conflict*
from the following URL
http://platinumdogs.me/2010/01/21/sharepoint-calling-splist-update-causes-save-conflict-spexception/
exceptions
using (var thisWeb = featSite.OpenWeb(featWeb.ID))
{
try
{
var listUpdate = false;
var theList = thisWeb.Lists[att.Value];
// change list configuration
// .....
// commit List modifications
if (listUpate)
theList.Update();
}
catch
{
// log the event and rethrow
throw;
}
}
}
}

Another approach is using Linq to SharePoint, Linq to SharePoint offers you a conflict resolution mechanism

SharePoint's LINQ provider is querying for concurrent changes when you try to save changes you've made using the SubmitChanges method.
When a conflict has been found, a ChangeConflictException will be thrown.
foreach(var notebook in spSite.Notebooks)
{
notebook.IsTopNotebook = true;
}
try
{
spSite.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch(ChangeConflictException ex)
{
foreach(ObjectChangeConflict occ in spSite.ChangeConflicts)
{
if (((Notebook)occ.Object).Memory > 16)
{
foreach (MemberChangeConflict field in occ.MemberConflicts)
{
if (field.Member.Name == "IsTopNotebook")
{
field.Resolve(RefreshMode.KeepCurrentValues);
}
else
{
field.Resolve(RefreshMode.OverwriteCurrentValues);
}
}
}
else
{
occ.Resolve(RefreshMode.KeepCurrentValues);
}
}
spSite.SubmitChanges();
}

Related

Fetching Custom Document Properties in Excel using C# is slow

I am fetching custom properties from woorkbook using this method:
var wb = Globals.ThisAddIn.Application.Workbooks.Open(file.FullName);
wb.Windows[1].Visible = false;
if (wb != null)
{
foreach (var prop in wb.CustomDocumentProperties)
{
try
{
Console.WriteLine(prop.Name.ToString());
Console.WriteLine(prop.Value.ToString());
Properties.Add(new CustomDocumentProperty { Key = prop.Name.ToString(), Value = prop.Value.ToString() });
}
catch (Exception)
{
Console.WriteLine();
}
}
wb.Close(false);
}
This method works, but the problem is that it is really slow in fetching the properties before executing the loop. So is there any way to speed this up? I have tried to look at other posts on this site, but I havent seen anyone mention this issue. Please let me know if I need to post anymore code. (Properties is a list of a custom class)

How to efficiently edit data in a database?

The method is supposed to receive data from a server, check if new tokens have been added, and if there are, add them to the database. If the token already exists, update its status but don't add a new row in the table. This is the code I've written so far.
IEnumerable<Token> serverTokens = JsonConvert.DeserializeObject<IEnumerable<Token>>
(server.GetTokens().Content);
IEnumerable<Token> dbTokens = _tokenService.GetAllTokens();
foreach (var token in serverTokens)
{
var dbToken = dbTokens.Where(x => x.Symbol == token.Symbol).FirstOrDefault();
if (dbToken != null)
{
Token editedToken = dbToken;
editedToken.UpdatedOn = DateTime.Now;
editedToken.Active = token.Active;
_tokenService.AddToken(editedToken);
}
else
{
token.UpdatedOn = DateTime.Now;
_tokenService.AddToken(token);
}
}
dbContext.SaveChanges();
The AddToken method is just a simple AddOrUpdate operation.
public void AddToken(Token token)
{
_dbContext.Tokens.AddOrUpdate(token);
//_dbContext.SaveChanges();
}
Now, this code does what it's supposed to, however it's extremely slow. How would I go about optimizing it?
dbTokens.Where(x => x.Symbol == token.Symbol) is IEnumerable
So he will load it each time you call it on the loop.
Store in in a list before the loop
List<Token> dbTokens = _tokenService.GetAllTokens().ToList()

SubmitChanges not updating, but inserts new record. LINQ to SQL

I am having difficulties UPDATING the databes via LINQ to SQL, inserting a new record works fine.
The code correctly inserts a new row and adds a primary key, the issue I am having is when I go to update (chnage a value that is already in the database) that same row the database is not updating, it is the else part of the code that does not work correctly. This is strange b/c the DB is properly connected and functioning through the fact that the DataContext inserts a new row with no issues. Checking the database confirms this.
This is the code,
using System;
using System.Collections.Generic;
using System.Linq;
using Cost = Invoices.Tenant_Cost_TBL;
namespace Invoices
{
class CollectionGridEvents
{
static string conn = Settings.Default.Invoice_DbConnectionString;
public static void CostDataGridCellEditing(DataGridRowEditEndingEventArgs e)
{
using (DatabaseDataContext DataContext = new DatabaseDataContext(conn))
{
var sDselectedRow = e.Row.Item as Cost;
if (sDselectedRow == null) return;
if (sDselectedRow.ID == 0)
{
sDselectedRow.ID = DateTime.UtcNow.Ticks;
DataContext.Tenant_Cost_TBLs.InsertOnSubmit(sDselectedRow);
}
else
{
// these two lines are just for debuging
long lineToUpdateID = 636154619329526649; // this is the line to be updated primary key
long id = sDselectedRow.ID; // this is to check the primary key on selected line is same
// these 3 lines are to ensure I am entering actual data into the DB
int? amount = sDselectedRow.Cost_Amount;
string name = sDselectedRow.Cost_Name;
int? quantity = sDselectedRow.Cost_Quantity;
sDselectedRow.Cost_Amount = amount;
sDselectedRow.Cost_Name = name;
sDselectedRow.Cost_Quantity = quantity;
}
try
{
DataContext.SubmitChanges();
}
catch (Exception ex)
{
Alert.Error("Did not save", "Error", ex);
}
}
}
}
}
And I am calling the method from this,
private void CostDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
CollectionGridEvents.CostDataGridCellEditing(e);
}
The lineToUpdateID is copied dirrectly from the database and is just there to check against the currently selected rows primary key is the same, so I know I am trying to update the same row.
I have looked through as many of the same type of issues here on SO , such as this one Linq-to-Sql SubmitChanges not updating fields … why?. But still no closer to finding out what is going wrong.
Any ideas would be much appreciated.
EDIT: Cost is just short hand of this using Cost = Invoices.Tenant_Cost_TBL;
You cannot do that. You need to get the record out of the database and then update that record. Then save it back. Like this:
else
{
// first get it
var query =
from ord in DataContext.Tenant_Cost_TBLs
where ord.lineToUpdateID = 636154619329526649
select ord;
// then update it
// Most likely you will have one record here
foreach (Tenant_Cost_TBLs ord in query)
{
ord.Cost_Amount = sDselectedRow.Cost_Amount;
// ... and the rest
// Insert any additional changes to column values.
}
}
try
{
DataContext.SubmitChanges();
}
catch (Exception ex)
{
Alert.Error("Did not save", "Error", ex);
}
Here is an example you can follow.
Or you can use a direct query if you do not want to select first.
DataContext.ExecuteCommand("update Tenant_Cost_TBLs set Cost_Amount =0 where ...", null);
Your object (Cost) is not attached to DB context. You should attach it then save changes. Check solution here

EF Change Tracker: Collection was modified; enumeration operation may not execute

I'm getting an error when I loop through a collection. I'm not changing the list at any point, but it gives me the following "Collection was modified; enumeration operation may not execute. Following code shows the method that I have this Parallel.Foreach.
public void DownloadImages()
{
IList<Vehicle> vehicles = _repository.Retrieve().ToList();
Parallel.ForEach(vehicles, vehicle =>
{
IList<VehiclePhoto> vehiclePhotos =
vehicle.VehiclePhotos.Where(x => x.ImageStatus == ImageStatus.Inactive).ToList();
if (vehiclePhotos.Count > 0)
{
Parallel.ForEach(vehiclePhotos, photo =>
{
using (var client = new WebClient())
{
try
{
string fileName = Guid.NewGuid() + ".png";
string filePath = _imagePath + "\\" + fileName;
client.DownloadFile(photo.ImageUrl, filePath);
photo.FileName = fileName;
photo.ImageStatus = ImageStatus.Active;
}
catch (Exception)
{
}
}
});
_repository.Save(vehicle);
}
});
}
This happens when _repository.Save(vehicle) is called. Following code will show the save changes method. base.SaveChanges(); is the place where error get raised.
public override int SaveChanges()
{
DateTime nowAuditDate = DateTime.Now;
IEnumerable<System.Data.Entity.Infrastructure.DbEntityEntry<DomainEntity>> changeSet = ChangeTracker.Entries<DomainEntity>();
if (changeSet != null)
{
foreach (System.Data.Entity.Infrastructure.DbEntityEntry<DomainEntity> entry in changeSet)
{
switch (entry.State)
{
case EntityState.Added:
entry.Entity.Created = nowAuditDate;
entry.Entity.Modified = nowAuditDate;
break;
case EntityState.Modified:
entry.Entity.Modified = nowAuditDate;
break;
}
}
}
return base.SaveChanges();
}
Any ideas on this?
EDITED:
I was trying to fix this above mentioned error and changed few code lines in DownloadImages method. Those changes are as follows:
Instead of
IList<Vehicle> vehicles = _repository.Retrieve().ToList();
I used var
var vehicles = _repository.Retrieve().AsParallel();
Instead of
IList<VehiclePhoto> vehiclePhotos =
vehicle.VehiclePhotos.Where(x => x.ImageStatus == ImageStatus.Inactive).ToList();
I used var
var vehiclePhotos =
vehicle.VehiclePhotos.Where(x => x.ImageStatus == ImageStatus.Inactive).AsParallel();
When I tried to run the code again. It gave me a different error: Error is as follows:
In the header it says
System.Data.Entity.Infrastructure.DbUpdateException
But in the innerException
System.Data.Entity.Core.UpdateException
ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.
This happens because you are iterating over vehicles and the code inside the loop is changing the elements of the enumeration vehicles. Also, looping through vehiclePhotos and changing the elements of it.
I usually solve this by using an explicit for loop, i.e.:
for(var i = 0; i < vehicles.Count; i++)
{
var vehicle = vehicles.ElementAt(i);
// process vehicle
}
However, if you need to use Parallel.ForEach, you could try creating an array of integers with length of vehicles.Count, iterate over that and use it as index for vehicles.

Looping rows of entitydatasource

First off.. I am new to asp.net and EF.
I have an EntityDatsource on my page I would like to loop through each row in the result set.
My goal is to dynamically build a page based on the values in the result set. Then to post the information back after it is edited by the user. My plan was to iterate each row on the page_load event. Currently I just have p-code in the area I would like to make this happen. The p-code is as follows
// foreach (DataRow row in AvailableDeviceConfigDataSource.enti Rows)
// {
// if sectionHeading <> lastSectionHeading
// {
// lastSectionHeading = sectionHeading
// AddSettingsSection(sectionHeading)
// }
// AddRowObjects
// }
Any guidance would be much appreciated.
In case anybody comes across this and is interested, I did solve my issue a while ago and figured I should post my answer for the benefit of others....
using (var context = new MyEntities())
{
string lastSectionHeading = "";
bool isFirstHeading = true;
var dynamicPageItems = context.view_dynamicPageItems;
foreach (var item in dynamicPageItems)
{
if (item.IsActive == 1)
{
if (!lastSectionHeading.Equals(item.CategoryId))
{
if (!isFirstHeading)
CloseSection();
lastSectionHeading = item.CategoryId;
AddSettingsSection(item.CategoryDescription);
isFirstHeading = false;
}
AddControl( item.DataType );
}
}
}

Categories

Resources