简体   繁体   English

问题多次遍历数据表行

[英]Issue looping through a DataTable Rows multiple times

::EDIT:: ::编辑::

Ok folks, it seems that I'm an idiot after all. 好的,伙计们,看来我毕竟是个白痴。 The problem had nothing at all to do with my code, and everything to do with Visual Studio having overwritten my SQLite Database with a previous (and empty) version. 这个问题与我的代码完全无关,而与Visual Studio有关的所有事情都与我的SQLite数据库用以前的(空的)版本覆盖了。 It does seem that there is a great discussion about thread safety going on, so I will stick around to read more! 似乎确实有很多关于线程安全性的讨论,所以我将继续阅读更多内容!

::/EDIT:: ::/编辑::

I am attempting to use multiple background workers to loop through the rows of a database 100 records at a time while avoiding duplication, but I seem to be having some issues. 我试图使用多个后台工作程序一次遍历数据库100条记录的行,同时避免重复,但是我似乎遇到了一些问题。 Basically, I start off by creating 10 background workers in a loop, and adding them to a List. 基本上,我首先在一个循环中创建10个后台工作程序,然后将它们添加到列表中。 Then I loop through the background workers in the List, and for each one I do RunWorkerAsync(), and then sleep the main thread for 5 seconds. 然后,我遍历List中的后台工作程序,并为每个工作程序执行RunWorkerAsync(),然后使主线程休眠5秒钟。 Inside the DoWork method of each background worker, I have the worker select 100 rows from the database where a particular field is set to its default value. 在每个后台工作程序的DoWork方法中,我让工作程序从数据库中选择100行,其中将特定字段设置为其默认值。 From here, I want to first loop through every returned row and change that default value to an "In Progress" value, and then loop through the values again and actually do the processing required to find correct values for those fields. 从这里开始,我想首先遍历返回的每一行,并将默认值更改为“ In Progress”值,然后再次遍历这些值,并实际进行所需的处理以找到这些字段的正确值。 The problem I seem to be having is that I seem to be have an empty DataTable after the first iteration through the results, and I suspect that my issues stem from shallow copying. 我似乎遇到的问题是,在对结果进行第一次迭代后,我似乎有一个空的DataTable,并且我怀疑我的问题源自浅拷贝。 Here is the code: 这是代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Text;
using DBFill.GeoCodeService;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;

namespace DBFill {
    class Program {
        public static int completedGeocodes = 0;
        static void Main(string[] args) {
            SQLiteDatabase db = new SQLiteDatabase("zipCodes.s3db");
            List<BackgroundWorker> workers = new List<BackgroundWorker>();
            for (int i = 0; i < 10; i++) {
                BackgroundWorker b = new BackgroundWorker();
                b.DoWork += new DoWorkEventHandler(worker_DoWork);
                b.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
                b.WorkerReportsProgress = true;
                b.ProgressChanged += new ProgressChangedEventHandler(b_ProgressChanged);
                workers.Add(b);
            }
            int counter = 0;
            foreach (BackgroundWorker b in workers) {
                Debug.WriteLine("Worker {0} is starting.", counter);
                b.RunWorkerAsync(b);
                counter++;
                System.Threading.Thread.Sleep(5000);
            }
            Boolean running = true;
            while (running) {
                running = false;
                foreach (BackgroundWorker b in workers) {
                    Debug.WriteLine("Checking background Worker");
                    if (b.IsBusy) {
                        running = true;
                    }
                }
                System.Threading.Thread.Sleep(5000);
            }

        }

        static void b_ProgressChanged(object sender, ProgressChangedEventArgs e) {
            Console.WriteLine(".");
        }

        static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {

        }

        static void worker_DoWork(object sender, DoWorkEventArgs e) {
            BackgroundWorker b = (BackgroundWorker)e.Argument;
            SQLiteDatabase db = new SQLiteDatabase("zipCodes.s3db");
            DataTable results = get100Records();
            DataTable temp = DeepClone<DataTable>(results);//results;
            Dictionary<String, String> marker = new Dictionary<string, string>();
            marker["LATITUDE"] = "In Progress";
            foreach (DataRow row in temp.Rows) {
                Debug.WriteLine("Working with zip {0}", row["ZIP_CODE"]);
                db.Update("ZIP_CODES", marker, String.Format("ZIP_CODE = '{0}'", row["ZIP_CODE"]));
            }
            foreach (DataRow row in results.Rows) {
                String geoCodeResponse = GeoCodeZip(row["ZIP_CODE"].ToString());
                Debug.WriteLine(String.Format("Attempting Zip: {0}", row["ZIP_CODE"].ToString()));
                if (geoCodeResponse != "There was an error") {
                    marker["LATITUDE"] = geoCodeResponse.Split(',')[0];
                    marker["LONGITUDE"] = geoCodeResponse.Split(',')[1];
                    Console.WriteLine(String.Format("#{0} updated successfully", completedGeocodes));
                }
                else {
                    marker["LATITUDE"] = "Not Set";
                    Console.WriteLine(String.Format("#{0} failed", completedGeocodes));
                }
                db.Update("ZIP_CODES", marker, String.Format("ZIP_CODE = '{0}'", row["ZIP_CODE"]));
                db.ExecuteNonQuery("commit");
                b.ReportProgress(1);
                completedGeocodes++;
            }
        }

        private static DataTable get100Records() {
            SQLiteDatabase db = new SQLiteDatabase("zipCodes.s3db");
            DataTable results = db.GetDataTable("select ZIP_CODE from ZIP_CODES where LATITUDE = 'Not Set' LIMIT 100");
            return results;
        }

        private static String GeoCodeZip(String zip) {
            try {
                GeocodeRequest request = new GeocodeRequest();
                request.Credentials = new GeoCodeService.Credentials();
                request.Credentials.ApplicationId = "API_KEY";
                request.Query = zip;
                ConfidenceFilter[] filters = new ConfidenceFilter[1];
                filters[0] = new ConfidenceFilter();
                filters[0].MinimumConfidence = Confidence.High;
                GeocodeOptions opts = new GeocodeOptions();
                opts.Filters = filters;
                request.Options = opts;
                GeocodeServiceClient service = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
                GeocodeResponse response = service.Geocode(request);
                if (response.Results.Length > 0) {
                    return String.Format("{0},{1}", response.Results[0].Locations[0].Latitude, response.Results[0].Locations[0].Longitude);
                }
                else {
                    Debug.WriteLine(String.Format("{0}", response.ResponseSummary.FaultReason));
                    return "There was an error";
                }
            }
            catch (Exception e) {
                Debug.WriteLine(e.Message);
                return "There was an error";
            }
        }

        public static T DeepClone<T>(T obj) {
            using (var ms = new MemoryStream()) {
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, obj);
                ms.Position = 0;

                return (T)formatter.Deserialize(ms);
            }
        }

    }
}

Any Ideas? 有任何想法吗?

It seems that your delay and why you want to multi-thread it, is not to read records from the database, but rather calling out to the GeocodeServiceClient . 似乎您的延迟以及为什么要对其进行多线程处理,不是从数据库中读取记录,而是调用GeocodeServiceClient

You could try reworking your main method to fetch all the records from the DB sequentially and parse them. 您可以尝试重新设计main方法,以按顺序从数据库中获取所有记录并进行解析。 You then split that list into even chunks and spin up background workers to run them through the Geocode service. 然后,您可以将该列表分为几部分,并启动后台工作人员以通过Geocode服务运行它们。

Another option would be to put the records into a queue and have each background worker pop one off the queue work on it, then go back to the queue while there are still unprocessed records. 另一种选择是将记录放入队列中,并让每个后台工作人员从队列中弹出一个工作,然后在仍有未处理记录的情况下返回队列。 You will need to be careful of locking In C# would it be better to use Queue.Synchronized or lock() for thread safety? 您将需要谨慎地锁定C#,使用Queue.Synchronized或lock()来保证线程安全会更好吗? .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM