0

我有一个设备、地址和公司的数据集,需要导入到我们的数据库中,并发现我们的数据库可能已经包含新数据集中包含的特定设备/地址/公司。如果是这种情况,我需要使用数据集中的新信息更新该条目,不包括地址。我们检查该地址的精确副本是否存在,否则我们创建一个新条目。

我的问题是尝试在 EF 中获取设备/公司非常慢,如果存在则更新它,否则插入它。为了解决这个问题,我尝试获取所有公司、设备和地址,并将它们插入到各自的 hashmap 中,并检查新数据的标识符是否存在于 hashmap 中。这并没有导致任何性能提升。我在下面包含了我的代码。通常我会进行批量插入,但我不确定我会为批量更新做什么。有人可以建议不同的路线吗?

            var context = ObjectContextHelper.CurrentObjectContext;
            var oldDevices = context.Devices;
            var companies = context.Companies;
            var addresses = context.Addresses;

            Dictionary<string, Company> companyMap = new Dictionary<string, Company>(StringComparer.OrdinalIgnoreCase);
            Dictionary<string, Device> deviceMap = new Dictionary<string, Device>(StringComparer.OrdinalIgnoreCase);
            Dictionary<string, Address> addressMap = new Dictionary<string, Address>(StringComparer.OrdinalIgnoreCase);
            foreach (Company c in companies)
            {
                if (c.CompanyAccountID != null && !companyMap.ContainsKey(c.CompanyAccountID))
                    companyMap.Add(c.CompanyAccountID, c);
            }
            foreach (Device d in oldDevices)
            {
                if (d.SerialNumber != null && !deviceMap.ContainsKey(d.SerialNumber))
                    deviceMap.Add(d.SerialNumber, d);
            }
            foreach (Address a in addresses)
            {
                string identifier = GetAddressIdentifier(a);
                if (!addressMap.ContainsKey(identifier))
                    addressMap.Add(identifier, a);
            }

            foreach (DeviceData.TabsDevice device in devices)
            {
                // update a device
                Company tempCompany;
                Address tempAddress;
                Device currentDevice;
                if (deviceMap.ContainsKey(device.SerialNumber)) //update a device
                    deviceMap.TryGetValue(device.SerialNumber, out currentDevice);
                else // insert a new device
                    currentDevice = new Device();
                currentDevice.SerialNumber = device.SerialNumber;
                currentDevice.SerialNumberTABS = device.SerialNumberTabs;
                currentDevice.Model = device.Model;
                if (device.CustomerAccountID != null && device.CustomerAccountID != "")
                {
                    companyMap.TryGetValue(device.CustomerAccountID, out tempCompany);
                    currentDevice.CustomerID = tempCompany.CompanyID;
                    currentDevice.CustomerName = tempCompany.CompanyName;

                }
                if (companyMap.TryGetValue(device.ServicingDealerAccountID, out tempCompany))
                    currentDevice.CompanyID = tempCompany.CompanyID;
                currentDevice.StatusID = 1;
                currentDevice.Retries = 0;
                currentDevice.ControllerFamilyID = 1;
                if (currentDevice.EWBFrontPanelMsgOption == null) // set the Panel option to the default if it isn't set already
                    currentDevice.EWBFrontPanelMsgOption = context.EWBFrontPanelMsgOptions.Where( i => i.OptionDescription.Contains("default")).Single();
                // link the device to the existing address as long as it is actually an address
                if (addressMap.TryGetValue(GetAddressIdentifier(device.address), out tempAddress))
                {
                    if (GetAddressIdentifier(device.address) != "")
                        currentDevice.Address = tempAddress;
                    else
                        currentDevice.Address = null;
                }
                else // insert a new Address and link the device to it (if not null)
                {
                    if (GetAddressIdentifier(device.address) == "")
                        currentDevice.Address = null;
                    else
                    {
                        tempAddress = new Address();
                        tempAddress.Address1 = device.address.Address1;
                        tempAddress.Address2 = device.address.Address2;
                        tempAddress.Address3 = device.address.Address3;
                        tempAddress.Address4 = device.address.Address4;
                        tempAddress.City = device.address.City;
                        tempAddress.Country = device.address.Country;
                        tempAddress.PostalCode = device.address.PostalCode;
                        tempAddress.State = device.address.State;
                        addresses.AddObject(tempAddress);
                        addressMap.Add(GetAddressIdentifier(tempAddress), tempAddress);
                        currentDevice.Address = tempAddress;
                    }
                }
                if (!deviceMap.ContainsKey(device.SerialNumber)) // if inserting, add to context
                {
                    oldDevices.AddObject(currentDevice);
                    deviceMap.Add(device.SerialNumber, currentDevice);
                }
            }
            context.SaveChanges();
4

1 回答 1

0

尽管它没有涵盖您的确切问题,但该线程已帮助我极大地提高了数据库导入的性能,我建议您阅读它。

如果你有很多散列,使用任务并行库可能会有所帮助。我们还使用哈希映射来映射 ID,这很有帮助。但我建议您将 {} 锁定在 SaveChanges() 上,这样您就不会遇到并发问题(因此,TPL 仅在您进行大量散列和转换时才有帮助 - 在我们的例子中,它有很大帮助,因为我们不得不做相当多的解析)。

于 2012-10-25T23:26:47.187 回答