веб-задание Azure не выполняется по уникальному ограничению - при условии, что это связано с другим потоком - PullRequest
1 голос
/ 19 июня 2019

У меня есть код, который проверяет, существует ли запись, если ее нет, она вставляет ее.Проблема в том, что она иногда терпит неудачу.Это вытягивает из очереди сообщений.Я сделал все, что мог придумать, но он каким-то образом создает запись в другом «потоке» (я полагаю) через некоторое время после его проверки и до того, как он создает новый.

Ошибка в попытке /поймать цикл - это работает, но я хочу знать, как избежать этого в первую очередь.Что я делаю не так, или что я могу сделать лучше?

Код начинается следующим образом:

 public class Functions
{
    // This function will get triggered/executed when a new message is written 
    // on an Azure Queue called queue.
    public static void ProcessQueueMessage([QueueTrigger("stops-to-import-to-mobile")] string message, TextWriter log)
    {

остальная часть кода здесь ... затем проблема начинается

 mobileEntities mdbPcs = new mobileEntities(); //get a new context for the below

        //now go create all the pcs for this stop.
        var stopPieces = (from sp in db.Stop_Items where sp.stop_detail_id == stop.Id select sp).ToArray();

       //get the count of the current pcs for the enxt stop
       int mobilePcCount = (from s in mdbPcs.mobile_Item_Detail where s.mobile_stops_id == mstopId select s.Id).Count();

        if (mobilePcCount != stopPieces.Count()) //if the piece count is the same already then no need to go through the loop
        {

            foreach (var item in stopPieces)//step through the items one at a time
            {
                int seek = (from s in mdbPcs.mobile_Item_Detail
                            where s.mobile_stops_id == mstopId && 
                            s.unique_scan_code == item.item_detail.unique_scan_code
                            select s.Id).FirstOrDefault();

                if (seek == 0) //if we do not already have the item create it
                {

                    mobile_Item_Detail newItem = new mobile_Item_Detail();
                    newItem.item_description = item.item_detail.item_description;
                    newItem.LOB_item_detail_id = item.item_detail.Id;
                    newItem.mobile_stops_id = mstopId;
                    newItem.dt_seq_no = item.item_detail.dt_item_seq_no;
                    newItem.unique_scan_code = item.item_detail.unique_scan_code;

                    mdbPcs.mobile_Item_Detail.Add(newItem);

                    try
                    {
                        mdbPcs.SaveChanges();

                    }
                    catch (Exception ex)
                    {
                        if (ex.InnerException.InnerException.Message.Contains("UNIQUE KEY")) //WTH -- Why does this keep happening...how do I fix this??!
                        {
                            Console.WriteLine($"{DateTime.Now}Unique Contraint {message} {newItem.unique_scan_code} for stop {newItem.mobile_stops_id}");
                            //item was already created by another thread so continue the foreach loop (I guess?!)
                            continue;
                        }
                        throw;
                    }
                }
            }
        }

1 Ответ

0 голосов
/ 21 июня 2019

Я предполагаю, что mobile_Item_Detail имеет свойство Id, которое представляет идентификатор PK, а mstopid - это отношение FK к родителю.В этом случае я бы внес все изменения в коллекцию сущностей и затем вызвал бы изменения сохранения за пределами foreach.Таким образом, DbContext может обрабатывать все идентификаторы одновременно, потому что он знает обо всех изменениях через ChangeTracker, и сохранение может быть выполнено в течение одного вызова db.Вы также можете обернуть операцию внутри транзакции, чтобы легко откатить изменения в случае возникновения ошибки.Я бы также включил эту операцию в оператор using, чтобы убедиться, что соединение с источником данных закрыто (см. здесь ).

using (var mdbPcs = new mobileEntities ()) //get a new context for the below
{
    //now go create all the pcs for this stop.
    var stopPieces = (from sp in db.Stop_Items where sp.stop_detail_id == stop.Id select sp).ToArray ();

    //get the count of the current pcs for the enxt stop
    var mobilePcQuery = (from s in mdbPcs.mobile_Item_Detail where s.mobile_stops_id == mstopId select s.Id);

    int mobilePcCount = mobilePcQuery.Count ();
    if (mobilePcCount != stopPieces.Count ()) //if the piece count is the same already then no need to go through the loop
    {
        try 
        {
            foreach (var item in stopPieces) //step through the items one at a time
            {
                int seek = mobilePcQuery.Where(s => s.unique_scan_code == item.item_detail.unique_scan_code select s.Id).FirstOrDefault ();

                if (seek == 0) //if we do not already have the item create it
                {
                    mobile_Item_Detail newItem = new mobile_Item_Detail ();
                    newItem.item_description = item.item_detail.item_description;
                    newItem.LOB_item_detail_id = item.item_detail.Id;
                    newItem.mobile_stops_id = mstopId;
                    newItem.dt_seq_no = item.item_detail.dt_item_seq_no;
                    newItem.unique_scan_code = item.item_detail.unique_scan_code;

                    mdbPcs.mobile_Item_Detail.Add (newItem);
                }
            }

            mdbPcs.SaveChanges ();
        } catch (Exception ex) {
            if (ex.InnerException.InnerException.Message.Contains ("UNIQUE KEY")) //WTH -- Why does this keep happening...how do I fix this??!
            {
                Console.WriteLine ($"{DateTime.Now}Unique Contraint {message} {newItem.unique_scan_code} for stop {newItem.mobile_stops_id}");
                //item was already created by another thread so continue the foreach loop (I guess?!)
                continue;
            }
            throw;
        }
    }
}

Дайте мне знать, если это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...