2017-01-10 36 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