Improved tag processing code with fewer round trips to db
This commit is contained in:
@@ -73,56 +73,77 @@ namespace AyaNova.Biz
|
||||
public static async Task ProcessDeleteTagsInRepositoryAsync(AyContext ct, List<string> 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
|
||||
{
|
||||
//Decrement the refcount
|
||||
ExistingTag.RefCount -= 1;
|
||||
t.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);
|
||||
}
|
||||
|
||||
#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<string> newTags, List<string> 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<string>();
|
||||
@@ -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
|
||||
// {
|
||||
|
||||
// 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 });
|
||||
t.RefCount += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Update the refcount
|
||||
ExistingTag.RefCount += 1;
|
||||
ct.Tag.Add(new Tag() { Name = s, 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//DELETE TAGS
|
||||
await ProcessDeleteTagsInRepositoryAsync(ct, deleteTags);
|
||||
|
||||
Reference in New Issue
Block a user