2017-01-09 3 views
1

Я получил проблема, когда я пытаюсь использовать метод AddTimeSeriesDefinition(TimeSeries series) или AddTimeSeriesMetaData(TimeSeriesMetaData tsData) внутри Parallel.ForEach()EF6 Невозможно вставить дубликат ключа - я не могу найти причину этого исключения

Я борюсь с этим в течение нескольких часов, и я не могу поверить, что я не могу найти никакого решения или даже теоретической причины.

Внутри моего класса 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 FrameworkDBContext каждый раз для каждой операции должно быть также потокобезопасно. Что может быть причиной этой проблемы, если я всегда проверял, существует ли запись?

Буду признателен за любую помощь.

ответ

1

Проблема в том, что DbSet не является ThreadSafe. У вас есть условие выполнения, связанное с циклом Parallel.ForEach. Вы должны заблокировать свой вызов для обоих ваших методов. https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

Надеюсь, это поможет

+0

Спасибо. Я считаю, что это решение, чтобы добавить lock() {} в эти методы. Кажется, что сейчас работает без каких-либо проблем, насколько я смог проверить за 1 час. – Wiktor