2017-01-10 51 views
0

我有一個SQL表稱爲域包含以下幾列:避免因實體框架中插入SQL表重複多工人

SQL Table

我有多個代理(工人)將行插入到數據庫中同一時間,我想避免插入重複的域名。 Id是主鍵,我不願意改變它。

同時林首先檢查是否域這個存在:

public async Task<List<DomainApiModel>> GetListOfExistingDomainsAsync(List<string> domains) 
{ 
    using (eTrafficBacklinks_V2Entities EMME_Context = new eTrafficBacklinks_V2Entities()) 
    { 
     var rec = await EMME_Context.Domains.Where(p => domains.Contains(p.DomainName)).ToListAsync(); 
     return rec.Select(p => new DomainApiModel(p)).ToList(); 
    } 
} 

然後我過濾那些已經存在的,最後,我插入通過下面的代碼不存在的:

public int Create(List<DomainApiModel> domainApiList, out List<DomainApiModel> domainApiListWithId, int chunkSizeLimit = 500) 
{ 
    using (eTrafficBacklinks_V2Entities EMME_Context = new eTrafficBacklinks_V2Entities()) 
    { 
     EMME_Context.Configuration.AutoDetectChangesEnabled = false; 
     EMME_Context.Configuration.ValidateOnSaveEnabled = false; 

     int totalChanges = 0; 

     var listOfLists = domainApiList.ChunkSplit(chunkSizeLimit).ToList(); 
     var listOfDomainData = new List<Domain>(); 
     foreach (var list in listOfLists) 
     { 
      foreach (var apiModel in list) 
      { 
       var objectData = apiModel.GetDataObject(); 
       EMME_Context.Domains.Add(objectData); 
       listOfDomainData.Add(objectData); 
      } 

      totalChanges += EMME_Context.SaveChanges(); 
     } 

     domainApiListWithId = listOfDomainData.Select(d => new DomainApiModel(d)).ToList(); 

     return totalChanges; 
    } 
} 

問題是,在檢查域是否存在和創建之間的同時,另一個代理可以插入相同的域,並且我的表中有重複項。

任何人都有如何解決這個問題的光?

觀測值:我有一個名爲的「URL欄」,這是nvarchar950類型頁表同樣的問題,所以只創建唯一索引是沒有辦法了......

回答

1

在需要唯一的所有列上添加額外索引。要被編入索引的列可以通過計算出的哈希索引。

這裏創造了許多實體和如何一個概念來追蹤例外:

class MyService 
{ 

    public async Task<OperationResult<string, SomeEntity>> CreateManyAsync(IList<string> data, int chunkSize) 
    { 
     var succeded = new List<SomeEntity>(); 
     var failed = new List<FailedOperation<string>>(); 

     foreach (var chunk in data.Select((dataItem, index) => new { data = dataItem, chunk = index % chunkSize }).GroupBy(c => c.chunk, c => c.data)) 
     { 
      try 
      { 
       succeded.AddRange(await InternalCreateManyAsync(chunk)); 
       continue; 
      } 
      catch (Exception) 
      { 
       // we just eat this exception 
      } 

      foreach (var singleItem in chunk) 
      { 
       try 
       { 
        succeded.Add(await InternalCreateSingleAsync(singleItem)); 
       } 
       catch (Exception ex) 
       { 
        failed.Add(new FailedOperation<string>(singleItem, ex)); 
       } 
      } 
     } 

     return new OperationResult<string, SomeEntity> { 
      Succeded = succeded, 
      Failed = failed, 
     }; 
    } 

    private async Task<IList<SomeEntity>> InternalCreateManyAsync(IEnumerable<string> data) 
    { 
     var result = new List<SomeEntity>(); 

     using (var db = new MyCOntext()) 
     { 
      foreach (var item in data) 
      { 
       result.Add(AddSingleToContext(item, db)); 
      } 
      await db.SaveChangesAsync(); 
     } 

     return result; 
    } 

    private async Task<SomeEntity> InternalCreateSingleAsync(string data) 
    { 
     using (var db = new MyContext()) 
     { 
      var e = AddSingleToContext(data, db); 
      await db.SaveChangesAsync(); 
      return e; 
     } 
    } 

    private SomeEntity AddSingleToContext(string data, MyContext context) 
    { 
     var entity = new SomeEntity { Data = data, }; 
     context.SomeEntities.Add(entity); 
     return entity; 
    } 

} 

一些實用類

class SomeEntity 
{ 
    public int Id { get; set; } 
    public string Data { get; set; } 
} 

class FailedOperation<T> 
{ 
    public FailedOperation(T data, Exception error) 
    { 
     Data = data; 
     Error = error; 
    } 

    public T Data { get; } 
    public Exception Error { get; } 
} 

class OperationResult<TSource, TResult> 
{ 
    public IList<TResult> Succeded { get; set; } 
    public IList<FailedOperation<TSource>> Failed { get; set; } 
} 
2

這個問題就可以輕鬆解決在表中添加一個唯一索引。任何添加重複值的嘗試都會引發異常。

CREATE UNIQUE INDEX UX_DOMAIN_NAME 
ON DOMAIN (DOMAIN_NAME) 

要小心,它會要求您單獨添加每個新值,否則整個事務將失敗,即使對於那些非重複的值。

foreach (var list in listOfLists) 
     { 
      foreach (var apiModel in list) 
      { 
       var objectData = apiModel.GetDataObject(); 
       EMME_Context.Domains.Add(objectData); 
       listOfDomainData.Add(objectData); 
       try{ 
        totalChanges += EMME_Context.SaveChanges(); 
       } 
       catch(SqlException se){ 
        if(se.Number != 2601) // Unique key violation 
        { 
         // Handle other errors 
        } 
       } 
      } 
} 
+0

如何處理異常?如果我在調用SaveChanges()之前添加多個域,則該異常將取消之前添加的所有域。 – juanora

+0

Okk ...謝謝...但像這樣添加會殺死性能... – juanora

+0

@ juanora「像這樣添加會殺死性能」你不能擁有這一切;-) – Oscar