DataContext无法加载更新实体的问题

时间:2014-03-04 21:11:18

标签: c# entity-framework

我偶然发现了一个我无法解决的奇怪问题。

我有两种不同形式的DataContexts。我以一种形式创建了两个“客户”实体(客户A和客户Z),并通过表单的上下文保存它们。然后我回到另一个表格,在那里我管理订单。在这种形式下,我可以创建订单并搜索客户(或他的地址)。

        public void CustomerAddressSearched()
    {
        // Get all delivery addresses matching keyword            
        List<Address> addressList = customerModel.GetMatchingDeliveryAddresses(view.OrderSearchKeyword);

        // If there is no matching address
        if (addressList.Count == 0)
        {
            MessageBox.Show(Properties.Resources.SearchNoResult);
        }
        // If there is a single matching address
        else if (addressList.Count == 1)
        {
            activeOrder.Address = addressList[0];
            PopulateOrderAddressControls(addressList[0]);
            activeOrderIsSaved = false;
        }
        // If there is more than one matching address, open search result view for user to pick address
        else
        {
            using (var form = new CustomerSearchView(addressList))
            {
                if (form.ShowDialog() == DialogResult.OK)
                {
                    CustomerViewObject selectedCustomer = (CustomerViewObject)form.selectedCustomer;
                    activeOrder.Address = addressList.Where(a => a.Id == selectedCustomer.AddressId).FirstOrDefault();
                    activeOrder.AddressId = selectedCustomer.AddressId;
                    PopulateOrderAddressControls(activeOrder.Address);
                    activeOrderIsSaved = false;
                }
            }
        }

        EnableOrDisableControls();
    }

我搜索了客户,并获得了两位客户的清单。我回到客户表单并将客户A的名称更改为客户B,保存,然后又返回并再次搜索。不幸的是,我得到了客户A和Z,而不是客户B.检查了数据库,客户B就在其中。然后我选择客户A作为我创建的订单并保存。创建了一个新的,再次搜索,这次我得到了客户B而不是A.我不知何故需要使用“旧”版本一次,否则新版本不显示。如果这是有道理的。

所以我检查了

List<Address> addressList = customerModel.GetMatchingDeliveryAddresses(view.OrderSearchKeyword);

查看我检索最新客户数据的方式是否有问题。

        public List<Address> GetMatchingDeliveryAddresses(string keyword)
    {
        List<Address> addressList = new List<Address>();

        foreach (var c in context.Customers)
        {
            if (c.DateDeleted == null)
            {
                var result = c.Address.Where(a => (a.LastName.Contains(keyword) || a.Company.Contains(keyword)) && a.IsDeliveryAddress == true)
                                                    .OrderByDescending(a => a.DateEffective)
                                                    .FirstOrDefault();

                if (result != null)
                {
                    addressList.Add(result);
                }
            }
        }

        return addressList;
    }

果然,在foreach循环中调试和停止时,我注意到最新版本(客户B)未加载(如果我没有使用它至少一次或重新启动程序/创建了新的上下文)。

我把

            var list = context.Addresses.ToList();

在foreach循环之前,只是为了检查他是否根本不加载新的客户地址,但突然之间它起作用了,foreach循环加载了最新的客户版本。我再次删除了该行,它停止了工作。把它放回去,再次工作。我想我的问题是,为什么上面的那条线以某种方式刷新我的背景,或者发生了什么?

干杯!

修改

我开始访问我有两个客户的客户目录(客户E和客户3)。我将它们重命名为客户ASD和客户666.返回订单并搜索客户。它运行以下代码:

        public List<Address> GetMatchingDeliveryAddresses(string keyword)
    {
        List<Address> addressList = new List<Address>();

        foreach (var c in context.Customers)
        {
            var result = c.Address.Where(a => (a.LastName.Contains(keyword) || a.Company.Contains(keyword)) && a.IsDeliveryAddress == true)
                                                    .OrderByDescending(a => a.DateEffective)
                                                    .FirstOrDefault();
            System.Console.WriteLine("PRE Name: " + result.LastName);
        }

        var list = context.Addresses.ToList();

        foreach (var c in context.Customers)
        {
            var result = c.Address.Where(a => (a.LastName.Contains(keyword) || a.Company.Contains(keyword)) && a.IsDeliveryAddress == true)
                                                    .OrderByDescending(a => a.DateEffective)
                                                    .FirstOrDefault();
            System.Console.WriteLine("POST Name: " + result.LastName);
        }

使用以下输出:

PRE Name: Customer E
PRE Name: Customer 3
POST Name: Customer ASD
POST Name: Customer 666

我不明白。

1 个答案:

答案 0 :(得分:0)

问题是收到太多评论,所以我要在这里发布答案,因为我很确定这就是你有这个问题的原因。

根据您在评论中所写的内容:The context used to retrieve the customers is created when the form is initialized. I'm doing a context per form.很明显您正在创建上下文以及表单本身(可能在构造函数中),这很多原因很多。有很多文章为什么你不应该这样做,但在这里我们正在讨论一个特定的问题,而且显然事实是你的上下文在你关闭表单之前不会改变。

现在是您的最后评论 - Turns out you were right, the code never made it to the dispose call for the customer directory context. But I still don't understand why it triggers such strange behaviour and how the line I added "fixed" it.

原因是DbContext跟踪您在当前上下文处于活动状态之前所做的所有更改,但它只是一个表达式树(您可以根据需要查看表达式树)以及为了获得一些你需要执行某些调用的实际数据。其中一个是ToList(),它强制执行更改,但引号在这里确实存在,因为它不是你应该怎么做的。

保持简短。如果您不打算使用任何类型的数据访问层,并且只是直接在表单中使用DbContext,您应该从构造函数(或现在的位置)中删除上下文创建并创建新的上下文需要使用的时间(最可能是每种方法)。为了摆脱这个问题,你应该在using语句中包含游览代码,如下所示:

public List<Address> GetMatchingDeliveryAddresses(string keyword)
{
  using( var context = new MyEntitiesContext())
  {
    List<Address> addressList = new List<Address>();

    foreach (var c in context.Customers)
    {
        var result = c.Address.Where(a => (a.LastName.Contains(keyword) || a.Company.Contains(keyword)) && a.IsDeliveryAddress == true)
                                                .OrderByDescending(a => a.DateEffective)
                                                .FirstOrDefault();
        System.Console.WriteLine("PRE Name: " + result.LastName);
    }

    foreach (var c in context.Customers)
    {
        var result = c.Address.Where(a => (a.LastName.Contains(keyword) || a.Company.Contains(keyword)) && a.IsDeliveryAddress == true)
                                                .OrderByDescending(a => a.DateEffective)
                                                .FirstOrDefault();
        System.Console.WriteLine("POST Name: " + result.LastName);
    }
}

这应该是全部。