簡體   English   中英

更新僅適用於調試模式

[英]Update only works in debug mode

我是新手使用實體作為MVC和SQL Server之間的數據層,所以如果我正在做的是不好的做法,我會在前面道歉。

首先,讓我分享處理更新的代碼。

更新交貨:

public bool One(Delivery toUpdate)
{
    using (var dbContext = new FDb())
    {
        try
        {
            var deliveryInDb = this.dbTable(dbContext).Single(x => x.DeliveryId == toUpdate.DeliveryId);

            dbContext.Entry(deliveryInDb).CurrentValues.SetValues(toUpdate);

            //removal first
            List<DeliveryDay> currentDays = FEngineCore.DeliveryDay.Get.ForValue((x => x.DeliveryId), toUpdate.DeliveryId);
            List<DeliveryTime> currentTimes = FEngineCore.DeliveryTime.Get.ForValue((x => x.DeliveryId), toUpdate.DeliveryId);

            //remove delivery days that are not needed
            foreach (var curDay in currentDays)
            {
                if (!toUpdate.DeliveryDays.Select(x => x.DeliveryDayId).Contains(curDay.DeliveryDayId))
                {
                    FEngineCore.DeliveryDay.Delete.One((x => x.DeliveryDayId), curDay.DeliveryDayId);
                    deliveryInDb.DeliveryDays.Remove(curDay);
                }
            }

            //remove delivery times that are not needed
            foreach (var curTime in currentTimes)
            {
                if (!toUpdate.DeliveryTimes.Select(x => x.DeliveryTimeId).Contains(curTime.DeliveryTimeId))
                {
                    FEngineCore.DeliveryTime.Delete.One((x => x.DeliveryTimeId), curTime.DeliveryTimeId);
                    deliveryInDb.DeliveryTimes.Remove(curTime);
                }
            }

            foreach (var day in toUpdate.DeliveryDays)
            {
                if (day.DeliveryDayId == 0)
                {
                    dbContext.DeliveryDays.Add(day);
                }
                else
                {
                    if (dbContext.DeliveryDays.Local.Any(e => e.DeliveryDayId == day.DeliveryDayId))
                    {
                        dbContext.Entry(dbContext.DeliveryDays.Local.First(e => e.DeliveryDayId == day.DeliveryDayId)).CurrentValues.SetValues(day);
                        dbContext.Entry(dbContext.DeliveryDays.Local.First(e => e.DeliveryDayId == day.DeliveryDayId)).State = EntityState.Modified;
                    }
                    else
                    {
                        DeliveryDay modDay = new DeliveryDay
                        {
                            DayOfWeek = day.DayOfWeek,
                            DeliveryDayId = day.DeliveryDayId,
                            DeliveryId = day.DeliveryId,
                            Interval = day.Interval
                        };

                        dbContext.DeliveryDays.Attach(modDay);
                        dbContext.Entry(modDay).State = EntityState.Modified;
                    }

                    deliveryInDb.DeliveryDays.Add(day);
                }
            }

            foreach (var time in toUpdate.DeliveryTimes)
            {
                if (time.DeliveryTimeId == 0)
                {
                    dbContext.DeliveryTimes.Add(time);
                }
                else
                {
                    if (dbContext.DeliveryTimes.Local.Any(e => e.DeliveryTimeId == time.DeliveryTimeId))
                    {
                        dbContext.Entry(dbContext.DeliveryTimes.Local.First(e => e.DeliveryTimeId == time.DeliveryTimeId)).CurrentValues.SetValues(time);
                        dbContext.Entry(dbContext.DeliveryTimes.Local.First(e => e.DeliveryTimeId == time.DeliveryTimeId)).State = EntityState.Modified;
                    }
                    else
                    {
                        DeliveryTime modTime = new DeliveryTime
                        {
                            DeliveryId = time.DeliveryId,
                            DeliveryLocationId = time.DeliveryLocationId,
                            DeliveryTimeId = time.DeliveryTimeId,
                            DropoffTime = time.DropoffTime
                        };

                        dbContext.DeliveryTimes.Attach(modTime);
                        dbContext.Entry(modTime).State = EntityState.Modified;
                    }

                    deliveryInDb.DeliveryTimes.Add(time);
                }
            }

            dbContext.SaveChanges();
            dbContext.Entry(deliveryInDb).State = EntityState.Detached;

            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.InnerException);
            return false;
        }
    }
}

讓我繼續解釋,交付對象有2個孩子; DeliveryTimeDeliveryDay 當我嘗試刪除一個deliveryTime並且不修改任何其他內容時,會出現問題。 正常運行代碼(不在調試中)的最終結果是, deliveryTime實際上並未刪除。 這是有趣的事情,當我調試它並通過斷點時,一切都按預期工作!

讓我繼續發布在deliveryTime的remove方法后面運行的代碼(實際上是我系統中的所有實體對象)。

public bool One<V>(Expression<Func<T, V>> property, V value) where V : IComparable
{
    using (var dbContext = new FoodsbyDb())
    {
        try
        {
            T toDelete; 

            //get the body as a property that represents the property of the entity object
            MemberExpression entityPropertyExpression = property.Body as MemberExpression;

            //get the parameter that is representing the entity object
            ParameterExpression entityObjectExpression = (ParameterExpression)entityPropertyExpression.Expression;

            //represent the value being checked against as an expression constant
            Expression valueAsExpression = Expression.Constant(value);

            //check the equality of the property and the value
            Expression equalsExpression = Expression.Equal(entityPropertyExpression, valueAsExpression);

            //create an expression that takes the entity object as a parameter, and checks the equality using the equalsExpression variable
            Expression<Func<T, bool>> filterLambda = Expression.Lambda<Func<T, bool>>(equalsExpression, entityObjectExpression);

            toDelete = this.dbTable(dbContext)
                .SingleOrDefault(filterLambda);

            if (toDelete != null)
            {
                this.dbTable(dbContext)
                .Remove(toDelete);

                dbContext.SaveChanges();

                return true;
            }

            return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.InnerException);
            return false;
        }
    }
}

上面的代碼顯然是通用的,它處理我的所有實體對象。 我已經進出了測試,並確定問題不存在於那里。 我認為發布它會很有幫助,所以你們都可以充分了解正在發生的事情。

這是我最好的猜測:

保存數據庫上下文時,對已刪除的deliveryTime的引用仍然存在, 但是當我調試時,系統有足夠的時間來刪除上下文。

這是我嘗試過的解決方案之一:

在設置currentDayscurrentTimes之后立即刪除對children對象的所有引用,然后在枚舉時繼續將它們添加回deliveryInDb

因為我是所有這一切的新手,如果你看到一些不好的做法和解決方案,我不介意建設性的批評來改進我的編程方法。

我實際上在工作中遇到了這個問題。 該項目是使用EF 6.1的較舊的MVC4項目。

在我們的情況下,嘗試將相關實體屬性設置為null的簡單更新未能在正常運行Web應用程序時(在調試模式下)將其實際設置為null。 在將屬性設置為null的代碼行上設置斷點時,數據庫將按預期更新。 因此,更新在斷點到位時正在工作,但在允許正常運行時不起作用。

使用EF攔截器,我們可以看到,在斷點到位的情況下,更新查詢按預期進行。

現在,在我們的情況下,相關實體使用virtual關鍵字來允許延遲加載。 我認為這是問題的根源。 當存在斷點時,EF有足夠的時間來懶惰地加載相關實體並評估它需要評估的任何內容並最終將其設置為null。 當沒有斷點運行時,我認為EF會陷入困境,試圖懶洋洋地加載該實體,因此無法認為它需要更新。 為了清楚起見,我第一次訪問相關的實體屬性, 使用一行代碼將其設置為null。

foo.Bar = null;

在我們的場景中,我通過在將其設置為null之前至少訪問該屬性一次來解決此問題,以便強制EF加載它。 加載它后,將其設置為null似乎現在按預期工作。 再說一次,要清楚,我認為問題是延遲加載的組合和第一次訪問該屬性並將其賦值為null的一行代碼。

您似乎正在使用DbContext的多個實例,這些實例未同步。

解決方案是使用單個實例,並在您的方法之間傳遞該實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM