IGeometryCollection of Polylines returns Paths - arcobjects

I have an file of points which are to be converted to a set of polylines. Some of the lines are multipart and I want to convert them to singlepart.
The points are processed and the polylines added to an Interim featureclass (for backup purposes). If a line is multipart it is added to this interim featureclass as multipart.
The interim featureclass is then read and it's features copied to a base featureclass. This works fine for single part features but I keep getting the 'No support for this geometry type' error when converting the multiparts to singleparts. The problem is that to create the multipart feature from a set of points I have to use a segment collection as a Path. I've tried setting this to a polyline but then adding line segments to it causes an error (wrong geometry type).
When I add the multipart features to the interim featureclass the geometries are Polylines. When I retrieve them later (by putting thte shape into a new GeometryCollection) the geometry collection is a Polyline but the individual geometries are Paths (?).
The code is:
1. Add points to interim featureclass by putting them in a pointcollection.
pPtColl = (IPointCollection4)new Polyline();
pGeomColl = (IGeometryCollection)new Polyline();
// Fill point collection
.......
// Create a path made up of segments from the point collection
ISegment pSegment;
ISegmentCollection pSegColl = (ISegmentCollection)new ESRI.ArcGIS.Geometry.Path(); // Fails if changed to new Polyline()
// M and Z aware
if (bHasZ == true)
{
pZAware = (IZAware)pSegColl;
pZAware.ZAware = true;
}
if (bHasM == true)
{
pMAware = (IMAware)pSegColl;
pMAware.MAware = true;
}
for (int n = 1; n < pPtColl.PointCount; n++)
{
pSegment = (ISegment)new Line();
pSegment.SpatialReference = pSpRef;
pSegment.FromPoint = pPtColl.Point[n - 1];
pSegment.ToPoint = pPtColl.Point[n];
pSegColl.AddSegment(pSegment, oMissing, oMissing);
}
pGeomColl.AddGeometry(pSegColl as IGeometry, oMissing, oMissing);
pGeom = (IGeometry)pGeomColl; // pGeom has geometry type = Polyline
pGeom.SpatialReference = pSpRef;
pFeat.Shape = pGeom;
This part of the code all works fine.
When processing these features from the interim featureclass to add them to the base featureclass I get an error because the geometry type from the geometry collection is 'Path' not 'Polyline'.
// Read the geometry from the interim feature into a geometry collection
pGeomColl = (IGeometryCollection)new Polyline();
pGeomColl = (IGeometryCollection)pFromFeature.ShapeCopy;
for (int j = 0; j < pGeomColl.GeometryCount; j++)
{
// Create a new (Polyline) feature pToFeat and populate its attributes
pToFeat = pToFC.CreateFeature();
....
// pGeomColl has geometry type = Polyline
pGeom = pGeomColl.Geometry[j]; // pGeom has geometry type = Path
pToFeat.Shape = pGeom; // Fails. pToFeat is a Polyline.
}
How can I ensure that the geometry collection contains geometries with Polylines rather than Paths?
Thanks,
JM

I have found what I condsider to be a workaround for this problem but it's not very pretty.
The solution is to cast the Path geometry into a polyline and then cast it back into a geometry when assigning it to the .Shape attribute.
if (pToFeat .ShapeCopy.GeometryType == esriGeometryType.esriGeometryPolyline && pGeom.GeometryType == esriGeometryType.esriGeometryPath)
{
IPolyline pPoly = (IPolyline)new Polyline();
pPoly = geometryToPolyline(pGeom, bHasZ, bHasM, ref sError);
if (sError.Length > 0)
{
sError = "processAdds; ID = " + sID + " OID = " + iOID.ToString() + sNL + sError;
clsMain.write_log(sError, clsMain.m_eLogType.FATAL);
iErrorCount++;
}
else
{
pToFeat.Shape = (IGeometry)pPoly;
}
}
private static IPolyline geometryToPolyline(IGeometry pInputGeom, bool bHasZ, bool bHasM, ref string sError)
{
IPolyline pPoly = null;
IGeometryCollection pPolyColl = null;
IZAware pZAware;
IMAware pMAware;
double dZ;
ISpatialReference pSpRef;
bool bIsMulti;
esriGeometryType pType;
try
{
sError = "";
pSpRef = pInputGeom.SpatialReference;
// Create a new polyline
pPoly = (IPolyline)new Polyline();
if (bHasZ == true)
{
pZAware = (IZAware)pPoly;
pZAware.ZAware = true;
}
if (bHasM == true)
{
pMAware = (IMAware)pPoly;
pMAware.MAware = true;
}
// Create the geometry collection
pPolyColl = (IGeometryCollection)new Polyline();
if (bHasZ == true)
{
pZAware = (IZAware)pPolyColl;
pZAware.ZAware = true;
}
if (bHasM == true)
{
pMAware = (IMAware)pPolyColl;
pMAware.MAware = true;
}
// Set the polyline as the geometry collection
pPoly = (IPolyline)pPolyColl;
pPoly.SpatialReference = pSpRef;
pPolyColl.AddGeometry(pInputGeom);
return pPoly;
}
catch (Exception ex)
{
System.Diagnostics.StackTrace pStack = new System.Diagnostics.StackTrace(ex, true);
System.Diagnostics.StackFrame pFrame = pStack.GetFrame(pStack.FrameCount - 1);
int iLineNo = pFrame.GetFileLineNumber();
sError = "ERROR: geometryToPolyline; Line: " + iLineNo + "\n" + ex.ToString();
return pPoly;
}
}

Related

get_value of a feature in IFeatureCursor

I'm trying to read the attribute "POSTCODE" of the features in IFeatureCursor. The FID was successful read but the "POSTCODE" was failed. The runtime error 'An expected Field was not found or could not be retrieved properly. Appreciate your advise. Paul
private void test2(IFeatureCursor pFeatc1)
{
IFeature feature = null;
IFields pFields;
int ctcur = 0;
while ((feature = pFeatc1.NextFeature()) != null)
{
pFields = feature.Fields;
int indxid = pFields.FindField("FID");
int indxpost = pFields.FindField("POSTCODE");
object valu = feature.get_Value(indxid);
string valupost = feature.get_Value(indxpost);
string aValu = Convert.ToString(valu);
Debug.WriteLine("FID: " + aValu + " Postcode: " + valupost);
ctcur++;
feature = pFeatc1.NextFeature();
}
MessageBox.Show("count cursor = " + ctcur);
}
I have modified the program and successfully read the feature attribute 'POSTCODE'. I have added IFeatureClass.Search(queryFilter, true) to search the feature again by FID and save in a cursor then use the 'feature.get_Value' to read the attribute. Please see my updated code below. Thanks.
private void test2(IFeatureCursor pFeatc1)
{
IMxDocument mxdoc = ArcMap.Application.Document as IMxDocument;
IMap map = mxdoc.FocusMap;
IFeatureLayer flayer;
IMaps pMaps = mxdoc.Maps;
for (int i = 0; i <= pMaps.Count - 1; i++)
{
map = pMaps.get_Item(i);
IEnumLayer pEnumLayer = map.get_Layers(null, true);
pEnumLayer.Reset();
ILayer pLayer = pEnumLayer.Next();
while (pLayer != null)
{
if (pLayer.Name == "AddrKey")
{
Debug.WriteLine("Layer: " + pLayer.Name);
flayer = (IFeatureLayer)pLayer;
IFeatureLayer pFeatureLayer = (IFeatureLayer)pLayer;
IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
IFeature feature = null;
IFields pFields;
while ((feature = pFeatc1.NextFeature()) != null)
{
pFields = feature.Fields;
int indx = pFields.FindField("FID");
object valu = feature.get_Value(indx);
string sFID = Convert.ToString(valu);
IQueryFilter queryFilter = new QueryFilter();
queryFilter.WhereClause = ("FID = " + sFID);
Debug.WriteLine("FID: " + sFID);
queryFilter.SubFields = "POSTCODE";
int fieldPosition = pFeatureClass.FindField("POSTCODE");
IFeatureCursor featureCursor = pFeatureClass.Search(queryFilter, true);
while ((feature = featureCursor.NextFeature()) != null)
{
MessageBox.Show(feature.get_Value(fieldPosition));
}
feature = pFeatc1.NextFeature();
}
}
pLayer = pEnumLayer.Next();
}
}
}

VSCode language extension with hierarchical Outline, DocumentSymbol

I'm trying to get outline working with a custom language in VScode. I have the below code but I feel like it is slow because of the way I find a range in class. Are there better ways to find the range and assign children. I've thought about just keeping track of the depth of the brackets and assigning all functions/methods/classes in higher depths into the last item of previous depth.
It was based off of this answer.
class JSLDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
public provideDocumentSymbols(document: vscode.TextDocument,
token: vscode.CancellationToken): Thenable<vscode.DocumentSymbol[]> {
return new Promise((resolve, reject) => {
var symbols: vscode.DocumentSymbol[] = [];
var depth = 0;
for (var i = 0; i < document.lineCount; i++) {
var line = document.lineAt(i);
var txt = line.text;
var ltxt = txt.toLowerCase();
let open_brackets = ltxt.match(/\(/g) || [];
let close_brackets = ltxt.match(/\)/g) || [];
// console.log(ltxt)
// console.log(open_brackets, close_brackets)
//console.log(i, open_brackets.length, close_brackets.length)
depth += open_brackets.length - close_brackets.length;
//console.log(depth);
if (ltxt.includes("define class(")) {
let sname = txt.trim().substr(14, txt.trim().length - 16); //this is hard coded right now but it's kind of working
let detail = "ARGS:x, y returns z";
let start_pos = new vscode.Position(i, 0);
let n_bracket = 1;
let i_char = 0;
//let children: vscode.DocumentSymbol[] = []
let ds = new vscode.DocumentSymbol(sname, detail, vscode.SymbolKind.Class, line.range, line.range);
for(var i_line = i; n_bracket > 0; i_line++){
let class_line = document.lineAt(i_line);
let mtxt = class_line.text;
let ic;
if(i == i_line) ic = 16;
else ic = 0;
for(i_char = ic; i_char < mtxt.length; i_char++){
if(mtxt[i_char] === "(") n_bracket++;
else if(mtxt[i_char] === ")") n_bracket--;
if(n_bracket === 0) break
}
if (/(\w[\w\d\s]*)=\s*method\({((?:\s*(?:\w[\w\d\s]*)(?:=[^,]*)?,?\s*)*)},/i.test(mtxt)) {
let result = mtxt.match(/(\w[\w\d\s]*)=\s*method\({((?:\s*(?:\w[\w\d\s]*)(?:=[^,]*)?,?\s*)*)},/i)!;
let mname = result[1].trim();
let m_details = ""
if(result.length == 3){
m_details = result[2].trim();
}
ds.children.push(new vscode.DocumentSymbol(mname, m_details, vscode.SymbolKind.Method, class_line.range, class_line.range));
}
if(n_bracket === 0) break
}
let end_pos = new vscode.Position(i_line, i_char);
let rng = new vscode.Range(start_pos, end_pos);
ds.range = rng;
//ds.children = children;
symbols.push(ds);
}
else if (/(\w[\w\d\s]*)=\s*function\({((?:\s*(?:\w[\w\d\s]*)(?:=[^,]*)?,?\s*)*)},/.test(ltxt)) {
let result = txt.match(/(\w[\w\d\s]*)=\s*function\({((?:\s*(?:\w[\w\d\s]*)(?:=[^,]*)?,?\s*)*)},/i)!;
let sname = result[1].trim();
let detail = "";
if(result.length == 3){
detail = "(" + result[2].trim() + ")";
}
symbols.push(new vscode.DocumentSymbol(sname, detail, vscode.SymbolKind.Function, line.range, line.range));
}
}
resolve(symbols);
});
}
}

Arcobjects: set measures based on the polyline length

I am currently linear referencing a set of roads. Using IMSegmatation2.SetMsAsDistance2 works fine for single-part polylines but for multi-part polylines I want to set the M values as the length along the polyline to the point, not the shortest distance between the point and the start point of the polyline. The SetMsAsDistance2 function sets the Measures on parallel lines as equal. I want them to be different.
Apart from setting an M value for each polyline vertex does anyone know of a method that sets the M as the length along the polyline?
The solution is to use the IMSegmentation3.SetAndInterpolateMsBetween function.
Note that the solution assumes that the geometries that make up the feature are in the right order. It assigns measures geometry-by-geometry.
The code for this is:
public static void measuresAdd_NonDuplicating(ref IFeature pFeat, bool bHasZ, bool bIgnoreGaps, out string sError)
{
// Add non-duplicating measures to the feature
sError = "";
IMSegmentation3 pSeg;
IGeometryCollection pGeomColl;
//IGeometryCollection pNewGeomColl; // Use if geometries are to be re-ordered.
IGeometry pGeom;
IPolyline4 pPoly;
IQueryFilter pQ;
IMAware pMAware;
IZAware pZAware;
double dStartMeasure;
double dToMeasure;
double dMeasure;
double dLen;
try
{
if (pFeat.ShapeCopy.IsEmpty == false)
{
pGeomColl = (IGeometryCollection)new PolylineClass();
pGeomColl = (IGeometryCollection)pFeat.ShapeCopy;
if (pGeomColl.GeometryCount == 1)
{
// Single line geometry. Duplication not an issue.
pMAware = (IMAware)pFeat.ShapeCopy;
pMAware.MAware = true;
pSeg = (IMSegmentation3)pMAware;
pPoly = geometryToPolyline((IGeometry)pFeat.ShapeCopy, out sError);
if (sError.Length > 0)
{
sError = "measuresAdd_NonDuplicating\r\n" + sError;
return;
}
pSeg.SetMsAsDistance2(pPoly.FromPoint, 1, 0, bIgnoreGaps);
pFeat.Shape = (IGeometry)pSeg;
pFeat.Store();
}
else
{
// For re-ordering geometries. Not currently used.
//pNewGeomColl = (IGeometryCollection)new Polyline();
//IZAware pZawareNew = (IZAware)pNewGeomColl;
//pZawareNew.ZAware = bHasZ;
//IMAware pMAwareNew = (IMAware)pNewGeomColl;
//pMAwareNew.MAware = true;
dStartMeasure = 0;
dMeasure = 0;
// MultiGeometry. Place them in order and set the measures on each part increasing.
// Currently assumes the existing order is correct.
for (int i = 0; i < pGeomColl.GeometryCount; i++)
{
pGeom = pGeomColl.Geometry[i];
pPoly = geometryToPolyline(pGeom, out sError);
if (sError.Length > 0)
{
sError = "measuresAdd_NonDuplicating\r\n" + sError;
return;
}
// Measure Values
dStartMeasure = dMeasure;
if (i > 0) dStartMeasure += 0.01;
dLen = pPoly.Length;
dToMeasure = dMeasure + dLen;
// Set Measures
pMAware = (IMAware)pPoly;
pMAware.MAware = true;
pZAware = (IZAware)pPoly;
pZAware.ZAware = bHasZ;
pSeg = (IMSegmentation3)pPoly;
pSeg.SetAndInterpolateMsBetween(dStartMeasure, dToMeasure);
// If geometries are re-ordered into a connecting network
//IGeometryCollection pXGeomColl = new PolylineClass();
//pMAware = (IMAware)pXGeomColl;
//pMAware.MAware = true;
//pZAware = (IZAware)pXGeomColl;
//pZAware.ZAware = bHasZ;
//pXGeomColl = (IGeometryCollection)pPoly;
//for (int j = 0; j < pXGeomColl.GeometryCount; j++)
// pNewGeomColl.AddGeometry(pXGeomColl.Geometry[j]);
dMeasure += dLen;
}
pFeat.Shape = (IGeometry)pGeomColl;
}
}
}
catch (Exception ex)
{
System.Diagnostics.StackTrace pStack = new System.Diagnostics.StackTrace(ex, true);
System.Diagnostics.StackFrame pFrame = pStack.GetFrame(pStack.FrameCount - 1);
int iLineNo = pFrame.GetFileLineNumber();
sError = "ERROR: measuresAdd_NonDuplicating; Line: " + iLineNo + "\n" + ex.ToString();
}
}

itextsharp: words are broken when splitting textchunk into words

I want to highlight several keywords in a set of PDF files. Firstly, we have to identify the single words and match them with my keywords. I found an example:
class MyLocationTextExtractionStrategy : LocationTextExtractionStrategy
{
//Hold each coordinate
public List<RectAndText> myPoints = new List<RectAndText>();
List<string> topicTerms;
public MyLocationTextExtractionStrategy(List<string> topicTerms)
{
this.topicTerms = topicTerms;
}
//Automatically called for each chunk of text in the PDF
public override void RenderText(TextRenderInfo renderInfo)
{
base.RenderText(renderInfo);
//Get the bounding box for the chunk of text
var bottomLeft = renderInfo.GetDescentLine().GetStartPoint();
var topRight = renderInfo.GetAscentLine().GetEndPoint();
//Create a rectangle from it
var rect = new iTextSharp.text.Rectangle(
bottomLeft[Vector.I1],
bottomLeft[Vector.I2],
topRight[Vector.I1],
topRight[Vector.I2]
);
//Add this to our main collection
//filter the meaingless words
string text = renderInfo.GetText();
this.myPoints.Add(new RectAndText(rect, renderInfo.GetText()));
However, I found so many words are broken. For example, "stop" will be "st" and "op". Are there any other method to identify a single word and its position?
When you want to collect single words and their coordination, the better way is to override the existing LocationTextExtractionStrategy. Here is my code:
public virtual String GetResultantText(ITextChunkFilter chunkFilter){
if (DUMP_STATE) {
DumpState();
}
List<TextChunk> filteredTextChunks = filterTextChunks(locationalResult, chunkFilter);
filteredTextChunks.Sort();
List<RectAndText> tmpList = new List<RectAndText>();
StringBuilder sb = new StringBuilder();
TextChunk lastChunk = null;
foreach (TextChunk chunk in filteredTextChunks) {
if (lastChunk == null){
sb.Append(chunk.Text);
var startLocation = chunk.StartLocation;
var endLocation = chunk.EndLocation;
var rect = new iTextSharp.text.Rectangle(startLocation[0], startLocation[1], endLocation[0], endLocation[1]);
tmpList.Add(new RectAndText(rect, chunk.Text));
} else {
if (chunk.SameLine(lastChunk)){
// we only insert a blank space if the trailing character of the previous string wasn't a space, and the leading character of the current string isn't a space
if (IsChunkAtWordBoundary(chunk, lastChunk) && !StartsWithSpace(chunk.Text) && !EndsWithSpace(lastChunk.Text))
{
sb.Append(' ');
if (tmpList.Count > 0)
{
mergeAndStoreChunk(tmpList);
tmpList.Clear();
}
}
sb.Append(chunk.Text);
var startLocation = chunk.StartLocation;
var endLocation = chunk.EndLocation;
var rect = new iTextSharp.text.Rectangle(startLocation[0], startLocation[1], endLocation[0], endLocation[1]);
////var topRight = renderInfo.GetAscentLine().GetEndPoint();
tmpList.Add(new RectAndText(rect,chunk.Text));
} else {
sb.Append('\n');
sb.Append(chunk.Text);
}
}
lastChunk = chunk;
}
return sb.ToString();
}
private void mergeAndStoreChunk(List<RectAndText> tmpList)
{
RectAndText mergedChunk = tmpList[0];
int tmpListCount = tmpList.Count();
for (int i = 1; i < tmpListCount; i++)
{
RectAndText nowChunk = tmpList[i];
mergedChunk.Rect.Right = nowChunk.Rect.Right;
mergedChunk.Text += nowChunk.Text;
}
this.myPoints.Add(mergedChunk);
}
myPoints is a list, which will return all we want.

Entity Framework overwrites data when 2 two people save data simultaneously

In a function I pass a list of related values and loop over them to save changes in the database. All works well until 2 or more people use the same page to update different entities .Then only that data gets saved for which the changes were made more recently.
public bool UpdatePermanentDifferenceBL(List<PermanentDifferenceProperties> permDiffDetails)
{
try
{
int permanentDifferenceID=0;
int taxEntityID = 0;
int mapid = 0;
//using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
//{
Topaz.DAL.PermanentDifference permDiff;
for (int i = 0; i < permDiffDetails.Count; i++)
{
if ((bool)(HttpContext.Current.Session[GlobalConstant.currentDataSet]) == true && (int)(HttpContext.Current.Session[GlobalConstant.snapShotID]) == 0)
{
using (var ctx = new TopazDbContainer())
{
try
{
permanentDifferenceID = permDiffDetails[i].PermanentDifferenceID;
taxEntityID = permDiffDetails[i].TaxEntityID;
mapid = permDiffDetails[i].MapID;
permDiff = new Topaz.DAL.PermanentDifference();
permDiff = ctx.PermanentDifference.Where(p => p.PermanentDifferenceID == permanentDifferenceID && p.TaxEntityID == taxEntityID && p.MapID == mapid).SingleOrDefault();
permDiff.Business = permDiffDetails[i].Business;
permDiff.Interest = permDiffDetails[i].Interest;
permDiff.Corporate = permDiffDetails[i].Corporate;
permDiff.UnallocatedTax = permDiffDetails[i].UnallocatedTax;
permDiff.Total = permDiffDetails[i].Total;
permDiff.ModifiedBy = permDiffDetails[i].ModifiedBy;
permDiff.ModifiedDate = DateTime.Now;
ctx.SaveChanges();
}
catch (System.Data.OptimisticConcurrencyException ex)
{
permanentDifferenceID = permDiffDetails[i].PermanentDifferenceID;
taxEntityID = permDiffDetails[i].TaxEntityID;
mapid = permDiffDetails[i].MapID;
permDiff = new Topaz.DAL.PermanentDifference();
ctx.Refresh(System.Data.Objects.RefreshMode.StoreWins, permDiff);
permDiff = ctx.PermanentDifference.Where(p => p.PermanentDifferenceID == permanentDifferenceID && p.TaxEntityID == taxEntityID && p.MapID == mapid).SingleOrDefault();
permDiff.Business = permDiffDetails[i].Business;
permDiff.Interest = permDiffDetails[i].Interest;
permDiff.Corporate = permDiffDetails[i].Corporate;
permDiff.UnallocatedTax = permDiffDetails[i].UnallocatedTax;
permDiff.Total = permDiffDetails[i].Total;
permDiff.ModifiedBy = permDiffDetails[i].ModifiedBy;
permDiff.ModifiedDate = DateTime.Now;
ctx.SaveChanges();
}
}
}
//ctx.ContextOptions.UseLegacyPreserveChangesBehavior = true;
}
//}
//using (UnitOfWork uow = new UnitOfWork())
//{
// for (int i = 0; i < permDiffDetails.Count; i++)
// {
// if ((bool)(HttpContext.Current.Session[GlobalConstant.currentDataSet]) == true && (int)(HttpContext.Current.Session[GlobalConstant.snapShotID]) == 0)
// {
// Repository.PermanentDifferenceRepository pDiffRepo = new Repository.PermanentDifferenceRepository(uow);
// Topaz.DAL.PermanentDifference permDiff = pDiffRepo.GetByEntityId(permDiffDetails[i].PermanentDifferenceID, permDiffDetails[i].TaxEntityID, permDiffDetails[i].MapID);
// permDiff.Business = permDiffDetails[i].Business;
// permDiff.Interest = permDiffDetails[i].Interest;
// permDiff.Corporate = permDiffDetails[i].Corporate;
// permDiff.UnallocatedTax = permDiffDetails[i].UnallocatedTax;
// permDiff.Total = permDiffDetails[i].Total;
// permDiff.ModifiedBy = permDiffDetails[i].ModifiedBy;
// permDiff.ModifiedDate = DateTime.Now;
// pDiffRepo.ApplyChanges(permDiff);
// }
// else
// {
// int snapshotID = (int)(HttpContext.Current.Session[GlobalConstant.snapShotID]);
// SnapShotPermanentDifferenceRepository pDiffRepo = new SnapShotPermanentDifferenceRepository(uow);
// SnapShotPermanentDifference permDiff = pDiffRepo.GetByEntityId(permDiffDetails[i].PermanentDifferenceID, permDiffDetails[i].TaxEntityID, permDiffDetails[i].MapID,snapshotID);
// permDiff.SnapshotID = snapshotID;
// permDiff.Business = permDiffDetails[i].Business;
// permDiff.Interest = permDiffDetails[i].Interest;
// permDiff.Corporate = permDiffDetails[i].Corporate;
// permDiff.UnallocatedTax = permDiffDetails[i].UnallocatedTax;
// permDiff.Total = permDiffDetails[i].Total;
// permDiff.ModifiedBy = permDiffDetails[i].ModifiedBy;
// permDiff.ModifiedDate = DateTime.Now;
// pDiffRepo.ApplyChanges(permDiff);
// }
// }
// uow.SaveChanges();
return true;
}
catch (Exception ex)
{
TopazErrorLogs.AddTopazErrorLogBL(ex, 1, 1);
throw new TopazCustomException(GlobalConstant.errorMessage);
}
}
Any urgent assistance is much appreciated.
The common way to solve this is adding additional column to every table where you want to handle concurrency. This column will have ROWVERSION or TIMESTAMP data type. Once you map tables in EDMX you will get a new computed property of type byte[] and set its Concurrency mode to fixed. This setting will force EF to add additional WHERE condition to every UPDATE or DELETE statement validating that row version is the same as it was when the record was loaded from the database. If the row version is not the same (another thread updated the record) the record from modification is not found and you will get exception.
Database will change the value every time you update the record automatically. You just need to ensure that your entity uses the value which was retrieved when the entity was loaded from the database.
Apologies all the viewstate and to some extent session was the culprit and not EntityFramework.