我有一个名为Domain的SQL表,其中包含以下列:
我有多个代理(工作人员)同时在数据库中插入行,我想避免插入重复的域。 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();
}
}
然后我过滤那些已经存在的,最后,我通过以下代码插入non exists:
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;
}
}
问题在于,在检查域是否存在与创建之间,另一个代理可以插入相同的域,并且我在表中有重复项。
任何人都知道如何解决这个问题?
Obs:我对一个名为page的表有同样的问题,其中包含&#34; url列&#34;这是nvarchar950类型,因此只创建一个唯一索引不是解决方案...
答案 0 :(得分: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
}
}
}
}
答案 1 :(得分: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; }
}