EF6无法插入重复键 - 我找不到此异常的原因

时间:2017-01-09 15:45:51

标签: c# entity-framework thread-safety

当我尝试在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也应该是线程安全的。 如果我总是检查记录是否存在,可能导致此问题的原因是什么?

我将不胜感激。

1 个答案:

答案 0 :(得分:1)

问题是DbSet不是ThreadSafe。你正在使用Parallel.ForEach循环运行条件。您必须锁定对两种方法的调用。 https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

希望有所帮助