我正在使用LINQ to SQL,在我提交一些更改后,我想生成一个线程,查看所有更改并根据需要更新我们的lucene索引。我的代码看起来很模糊:
(new Thread(() => { UpdateIndex(context.GetChangeSet()); }).Start();
有时虽然我得到一个InvalidOperationException,我认为是因为context.GetChangeSet()不是线程安全的,所以如果在一个线程中修改了更改集而另一个线程通过它进行枚举,则会出现问题。
是否存在GetChangeSet()的“线程安全”版本?或者某种方式我可以做ChangeSet.clone()或其他什么?
答案 0 :(得分:2)
DataContext类的实例成员不是线程安全的。
为了避免竞争条件,您应该从同一个线程调用DataContext.GetChangeSet方法,该线程使DataContext实例跟踪修改。例如:
public class CustomerDao : IDisposable
{
private DataContext context;
public CustomerDao()
{
this.context = new DataContext("SomeConnectionString");
}
public void Insert(Customer instance)
{
this.context.Customers.InsertOnSubmit(instance);
this.StartUpdateIndex();
this.context.SubmitChanges();
}
public void Delete(Customer instance)
{
this.context.Customers.DeleteOnSubmit(instance);
this.StartUpdateIndex();
this.context.SubmitChanges();
}
public void Dispose()
{
if (this.context != null)
{
this.context.Dispose();
}
}
private void StartUpdateIndex()
{
ChangeSet changes = this.context.GetChangeSet();
ThreadPool.QueueUserWorkItem(
state => this.UpdateIndex((ChangeSet)state), changes);
}
}
这假设从单个线程在CustomerDao类的给定实例上调用Insert和Delete方法。
答案 1 :(得分:0)
我只需要从每个对象中提取少量数据,因此我最终只是提取文本,将其放入一个新对象,然后关闭该新对象。这让我在其他任何地方处理锁定时省去了很多麻烦,但我认为Enrico的答案可能是“真正的”,所以留下他的标记为解决方案。