Azure Web作业在唯一约束下失败-假定由于其他线程

时间:2019-06-19 15:47:15

标签: c# entity-framework azure-webjobs

我有用于检查记录是否存在的代码,如果不存在,它将插入该记录。 问题是它有时会失败。 它是从消息队列中提取的。 我已经做了我能想到的所有事情,但是在某种程度上,它是在检查之后,在创建新的“线程”(我假设)上创建记录的。

错误在try / catch循环中-可以工作,但我想知道如何避免它首先发生。 我在做什么错,或者我能做得更好?

代码从这样开始:

 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 :(得分:0)

我假设mobile_Item_Detail具有代表身份PK的Id属性,并且mstopid是与父代的FK关系。在那种情况下,我将对实体集合进行所有更改,然后在foreach之外调用save更改。这样,DbContext可以一次处理所有ID,因为它可以通过ChangeTracker知道所有更改,并且可以在单个db调用中执行保存。您还可以将操作包装在事务中,以在发生错误时轻松回滚更改。我还将操作包含在using语句中,以确保关闭数据源的连接(请参见here)。

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;
        }
    }
}

让我知道这是否有帮助。