diff --git a/server/AyaNova/biz/TagBiz.cs b/server/AyaNova/biz/TagBiz.cs index 6c5430d3..da0a73fa 100644 --- a/server/AyaNova/biz/TagBiz.cs +++ b/server/AyaNova/biz/TagBiz.cs @@ -73,56 +73,77 @@ namespace AyaNova.Biz public static async Task ProcessDeleteTagsInRepositoryAsync(AyContext ct, List deleteTags) { if (deleteTags.Count == 0) return; + + var existing = await ct.Tag.Where(x => deleteTags.Contains(x.Name)).ToListAsync(); foreach (string s in deleteTags) { - bool bDone = false; - //Keep on trying until there is success - //this allows for concurrency issues - //I considered a circuit breaker / timeout here, but theoretically it should not be an issue - //at some point it should not be a concurrency issue anymore - //And this is not critical functionality requiring a transaction and locking - - //TODO: Move this into a stored procedure just like search keyword processing for efficiency - //it's likely not going to be an issue but still, it's not right to do it this way - do + var t = existing.FirstOrDefault(x => x.Name == s); + if (t != null) { - //START: Get tag word and concurrency token and count - var ExistingTag = await ct.Tag.FirstOrDefaultAsync(z => z.Name == s); - //if not present, then nothing to do - if (ExistingTag != null) - { - //No longer needed? - if (ExistingTag.RefCount == 1) - { - ct.Remove(ExistingTag); + if (t.RefCount < 2)//catch any that fell through the cracks and are maybe zero or negative event + ct.Remove(t); + else + t.RefCount -= 1; + } - } - else - { - //Decrement the refcount - ExistingTag.RefCount -= 1; - } - - try - { - await ct.SaveChangesAsync(); - bDone = true; - } - catch (Exception ex) when (ex is DbUpdateConcurrencyException)//allow for possible other types - { - //allow others to flow past - // string sss = ex.ToString(); - } - }else{ - bDone=true; - } - } while (bDone == false); } + await ct.SaveChangesAsync(); + + #region OLD SLOW METHOD FOR REFERENCE IN CASE CONCURRENCY EXCEPTIONS + // foreach (string s in deleteTags) + // { + // bool bDone = false; + // //Keep on trying until there is success + // //this allows for concurrency issues + // //I considered a circuit breaker / timeout here, but theoretically it should not be an issue + // //at some point it should not be a concurrency issue anymore + // //And this is not critical functionality requiring a transaction and locking + // do + // { + // //START: Get tag word and concurrency token and count + // var ExistingTag = await ct.Tag.FirstOrDefaultAsync(z => z.Name == s); + // //if not present, then nothing to do + // if (ExistingTag != null) + // { + // //No longer needed? + // if (ExistingTag.RefCount == 1) + // { + // ct.Remove(ExistingTag); + + // } + // else + // { + // //Decrement the refcount + // ExistingTag.RefCount -= 1; + // } + + // try + // { + // await ct.SaveChangesAsync(); + // bDone = true; + // } + // catch (Exception ex) when (ex is DbUpdateConcurrencyException)//allow for possible other types + // { + // //allow others to flow past + // // string sss = ex.ToString(); + // } + // } + // else + // { + // bDone = true; + // } + // } while (bDone == false); + // } + #endregion old slow method + + } public static async Task ProcessUpdateTagsInRepositoryAsync(AyContext ct, List newTags, List originalTags = null) { //todo: Recode this as a procedure like search indexing or at least a direct sql call + + //just in case no new tags are present which could mean a user removed all tags from a record so this //needs to proceed with the code below even if newTags is null as long as originalTags isn't also null if (newTags == null) newTags = new List(); @@ -147,41 +168,64 @@ namespace AyaNova.Biz addTags = newTags; } + #region OLD SLOW METHOD FOR REFERENCE IN CASE CONCURRENCY EXCEPTIONS + // //ADD / INCREMENT TAGS + // //one by one method + // foreach (string s in addTags) + // { + // bool bDone = false; + // //Keep on trying until there is success + // //this allows for concurrency issues + // //I considered a circuit breaker / timeout here, but theoretically it should not be an issue + // //at some point it should not be a concurrency issue anymore + // do + // { + // //START: Get tag word and concurrency token and count + // var ExistingTag = await ct.Tag.FirstOrDefaultAsync(z => z.Name == s); + // //if not present, then add it with a count of 0 + // if (ExistingTag == null) + // { + // await ct.Tag.AddAsync(new Tag() { Name = s, RefCount = 1 }); + // } + // else + // { + // //Update the refcount + // ExistingTag.RefCount += 1; + // } + // try + // { + // await ct.SaveChangesAsync(); + // bDone = true; + // } + // catch (Exception ex) when (ex is DbUpdateConcurrencyException)//this allows for other types + // { - //ADD / INCREMENT TAGS + // Console.WriteLine("TagBiz::Exception udring update tags"); + // //allow others to flow past + // //string sss = ex.ToString(); + // } + // } while (bDone == false); + // } + + #endregion old slow method + + //ADD / INCREMENT TAGS + var existing = await ct.Tag.Where(x => addTags.Contains(x.Name)).ToListAsync(); foreach (string s in addTags) { - bool bDone = false; - //Keep on trying until there is success - //this allows for concurrency issues - //I considered a circuit breaker / timeout here, but theoretically it should not be an issue - //at some point it should not be a concurrency issue anymore - do + var t = existing.FirstOrDefault(x => x.Name == s); + if (t != null) { - //START: Get tag word and concurrency token and count - var ExistingTag = await ct.Tag.FirstOrDefaultAsync(z => z.Name == s); - //if not present, then add it with a count of 0 - if (ExistingTag == null) - { - await ct.Tag.AddAsync(new Tag() { Name = s, RefCount = 1 }); - } - else - { - //Update the refcount - ExistingTag.RefCount += 1; - } - try - { - await ct.SaveChangesAsync(); - bDone = true; - } - catch (Exception ex) when (ex is DbUpdateConcurrencyException)//this allows for other types - { - //allow others to flow past - //string sss = ex.ToString(); - } - } while (bDone == false); + t.RefCount += 1; + } + else + { + ct.Tag.Add(new Tag() { Name = s, RefCount = 1 }); + } } + await ct.SaveChangesAsync(); + + //DELETE TAGS await ProcessDeleteTagsInRepositoryAsync(ct, deleteTags);