我有一个WinForms应用程序,它从Sqlite数据库文件中获取Car数据,该文件由WebService的CSV文件生成,以及每个Car的相关部件。实例化时,Car类填充数据库中的所有属性,并从WebService获取大量数据,大约需要30秒才能完成,所以我只需在填充数据库属性后调用异步任务,然后让它以异步方式运行。在Web服务返回所有数据并完成所有工作后,实例将保存在类似于内部缓存的List中。
一切正常,直到用户对部件进行操作,该部件需要在WebService方法仍在运行时返回属性ParentCar,从而导致新的Car被实例化并重新轮询Web服务多次属性是在缓存列表中不存在Car时请求。一旦第一个实例完成处理,它就会停止,但每次下一个实例完成时,所有更改都将被覆盖。
我很难找到一种方法来确保Car在实际应用期间没有阻止UI一次实例化,任何想法?
这是我目前的代码:
public class Car
{
private List<Part> _parts = new List<Part>();
public string Id { get; private set; }
public int DbIndex
{
get { return DbClass.GetCarIndexById(Id); }
}
public ReadOnlyCollection<Part> Parts { get => _parts.AsReadOnly(); }
public Car(System.Data.SQLite.SQLiteDataReader sQLiteDataReader)
{
// Code to Load all properties from sQLiteDataReader
Task.Run(() => LongRuningWebServiceTask());
}
private async Task LongRuningWebServiceTask
{
// Long running code that will populate even more properties
SaveToInternalDb();
}
private void SaveToInternalDb()
{
if (DbIndex > -1)
DbClass.UpdateCarData(this);
else
DbClass.AddCar(this);
}
public void RelateParts(IEnumerable<Part> parts)
{
_parts.AddRange(parts);
}
~Car()
{
SaveToInternalDb();
}
}
public class Part
{
public string ParentCarId { get; private set; }
public Car ParentCar
{
get
{
Task getCar = DbClass.GetCarById(ParentCarId);
getCar.Wait();
return getCar.Result;
}
}
}
public static class DbClass
{
private static SQLiteConnection sqlConn;
private readonly string sqlFile = "pathToDbFile";
private static List<Car> CarCache = new List<Car>();
public static async Task<Car> GetCarById(string> carId, bool ignoreCache = false)
{
Car foundCar = null;
if (!ignoreCache)
foundCar = CarCache.Find(s => s.Id == carId);
if (foundCar == null)
{
try
{
string sql = string.Format("SELECT * FROM all_Cars WHERE Car = '{0}';", carId);
using (SQLiteCommand command = new SQLiteCommand(sql, sqlConn))
{
using (SQLiteDataReader reader = (SQLiteDataReader)await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
foundCar = new Car(reader));
}
}
}
catch (Exception e)
{
string m = e.Message;
}
if (foundCar != null)
{
var partsList = await GetPartsByCarId(carId);
if (partsList.Count > 0)
Car.RelateParts(partsList);
if (!ignoreCache)
{
if (foundCar.DbIndex == -1)
CarCache.Add(foundCar);
}
}
}
return foundCar;
}
public static async Task<List<Part>> GetPartsByCarId(string carId)
{
List<Part> foundParts = new List<Part>();
int index = GeCarIndexById(carId);
Car foundCar = index > -1 ? CarCache[index] : null;
if (foundCar != null)
foundParts = await GetPartsByCarId(carId);
return foundParts;
}
public static void InitiateSqlConnection()
{
if (sqlConn == null)
{
sqlConn = new SQLiteConnection("Data Source=" + sqlFile.FullName + ";Version=3;");
try
{
sqlConn.Open();
}
catch (Exception e)
{
var m = e.Message;
}
}
else
{
if(sqlConn.State == System.Data.ConnectionState.Broken || sqlConn.State == System.Data.ConnectionState.Closed)
sqlConn.Open();
}
}
public static int GetCarIndexById(string carId)
{
int index = -1;
for(int c = 0; c < CarCache.Count;c++)
{
if(CarCache[c].Id == carId)
{
index = c;
break;
}
}
return index;
}
public static void AddCar(Car car)
{
CarCache.Add(car);
}
public static void UpdateCarData(Car car)
{
if(car != null)
{
int index = car.DbIndex;
if(index > -1)
CarCache[index] = car;
}
}
}