当我尝试在AddTimeSeriesDefinition(TimeSeries series)
内使用方法AddTimeSeriesMetaData(TimeSeriesMetaData tsData)
或Parallel.ForEach()
我正在努力解决这个问题几个小时,我无法相信我找不到任何解决方案甚至是理论上的原因。
在我的班级Data
里面,其中包含我的数据库上下文DBEntity db = new DBEntity()
我有AddTimeSeriesDefinition(TimeSeries series)
和AddTimeSeriesMetaData()
方法:
public class Data : IDisposable
{
private DBEntity db;
public Data()
{
db = new DBEntity();
}
public TimeSeries AddTimeSeriesDefinition(TimeSeries series)
{
var timeSeries = db.TimeSeries.Where(ts => ts.Key1 == series.Key1 )
.Where(ts => ts.Key2 == series.Key2 )
.Where(ts => ts.Key3 == series.Key3 )
.FirstOrDefault();
if ( timeSeries == null )
{
timeSeries = db.TimeSeries.Add(series);
db.SaveChanges();
}
return timeSeries;
}
public void AddTimeSeriesMetaData(TimeSeriesMetaData tsData)
{
var tsd = db.TimeSeriesMetaData.Where(ts => ts.Key1 == tsData.Key1 )
.Where(ts => ts.Key2== tsData.Key2)
.FirstOrDefault();
if (tsd == null)
db.TimeSeriesMetaData.Add(tsData);
else
tsd.Value = tsData.Value;
try
{
db.SaveChanges();
}
catch (Exception ex)
{
Log.Error($"Error occurred (...) Key1:{tsData.Key1} Key2:{tsData.Key2}", ex);
}
}
Dispose()
{...}
}
但是当我在我的主要课程中使用它们时,例如:
private MainClass
{
Data DB { get { value = new Data() } }
...
Parallel.ForEach( // arguments )
{
...
using( var db = DB )
{
db.AddTimeSeriesDefinition(timeSeries);
}
...
}
}
它有时会完全随机地崩溃
db.SaveChanges();
,例外:
Violation of PRIMARY KEY constraint 'PK_TimeSeriesMetaDatas'. Cannot insert duplicate key in object 'dbo.TimeSeriesMetaData'. The duplicate key value is ("Key1", "Key2"). The statement has been terminated.
例如我的TimeSeriesMetaData
EF类:
[Table("TimeSeriesMetaData")]
public partial class TimeSeriesMetaData
{
[Key]
[Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Key1 { get; set; }
[Key]
[Column(Order = 1)]
public string Key2 { get; set; }
[Required]
public string Key3 { get; set; }
}
我已经读过每次为每个操作创建Entity Framework
DBContext
也应该是线程安全的。
如果我总是检查记录是否存在,可能导致此问题的原因是什么?
我将不胜感激。
答案 0 :(得分:1)
问题是DbSet不是ThreadSafe。你正在使用Parallel.ForEach循环运行条件。您必须锁定对两种方法的调用。 https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx
希望有所帮助