有什么方法可以让 EntityFramework 的 SaveChanges() 方法跳过一个条目(如果它已经存在)?
Any way to make EntityFramework's SaveChanges() method skip an entry if it already exists?
我的应用程序中有一个 Tag
模型:
public class Tag
{
public Tag() { }
public Tag(string t)
{
Name = t;
Pictures = new List<Picture>();
}
public int Id { get; set; }
[MaxLength(96), Index(IsUnique = true)]
public string Name { get; set; }
public virtual List<Picture> Pictures { get; set; }
}
当具有相同 Name
的记录已经存在时,是否有任何方法可以告诉框架执行 ON DUPLICATE DO NOTHING
?这总是会引发重复异常,我希望它忽略它并继续。
编辑: 我已经将许多线程中的 EF 代码更改为:
async Task SaveQueue()
{
for (;;)
{
try
{
await Task.Delay(7500);
dbUploadProgress.Visibility = Visibility.Visible;
dbUploadProgress.Value = 0;
var q = new ObservableCollection<Picture>(manager.Queue.ToList().AsEnumerable());
manager.Queue.Clear();
var imgcount = q.Count();
for (int i = 0; i < imgcount; i++)
{
using (var pc = new PicsContext())
{
var tags = q[i].GetTags();
pc.Sites.Attach(q[i].Site); // I'm actually not sure how to use this.
var curUrl = q[i].Url;
if (pc.Pictures.FirstOrDefault(o => o.Url == curUrl) != null)
continue;
foreach (var t in tags)
{
var tag = pc.Tags.Where(o => o.Name == t).FirstOrDefault();
if (tag == null)
{
tag = new ViewModel.Tag(t);
}
q[i].Tags.Add(tag);
try
{
await pc.SaveChangesAsync();
}
catch { }
}
pc.Pictures.Add(q[i]);
try
{
await pc.SaveChangesAsync();
}
catch { }
dbUploadProgress.Value = (i + 1) / (double)imgcount;
}
}
q.Clear();
MainWindow.AddLog(string.Format("Saved {0} pictures.", imgcount));
dbUploadProgress.Visibility = Visibility.Collapsed;
await Task.Delay(1500);
}
catch { }
if (isStopped)
break;
}
}
不过问题依然存在
你为什么不 运行 一个 dbContext.Get.Any(x=>x.Name==tag.Name) 并跳过添加基于它的新标签?
我认为问题在于您的队列异步处理消息,因此您可以有 2 个线程尝试插入相同的标签,因为在插入之前检查是否存在逻辑 运行。
您可以通过一次只处理 1 个队列消息(让一个 worker/thread 处理队列)来解决问题。
或者另一种解决方法可能是隔离保存在 try catch 中的标签并正确处理重复的异常(从 db 重新加载标签并在将其设置到新对象时使用该标签)。
我的应用程序中有一个 Tag
模型:
public class Tag
{
public Tag() { }
public Tag(string t)
{
Name = t;
Pictures = new List<Picture>();
}
public int Id { get; set; }
[MaxLength(96), Index(IsUnique = true)]
public string Name { get; set; }
public virtual List<Picture> Pictures { get; set; }
}
当具有相同 Name
的记录已经存在时,是否有任何方法可以告诉框架执行 ON DUPLICATE DO NOTHING
?这总是会引发重复异常,我希望它忽略它并继续。
编辑: 我已经将许多线程中的 EF 代码更改为:
async Task SaveQueue()
{
for (;;)
{
try
{
await Task.Delay(7500);
dbUploadProgress.Visibility = Visibility.Visible;
dbUploadProgress.Value = 0;
var q = new ObservableCollection<Picture>(manager.Queue.ToList().AsEnumerable());
manager.Queue.Clear();
var imgcount = q.Count();
for (int i = 0; i < imgcount; i++)
{
using (var pc = new PicsContext())
{
var tags = q[i].GetTags();
pc.Sites.Attach(q[i].Site); // I'm actually not sure how to use this.
var curUrl = q[i].Url;
if (pc.Pictures.FirstOrDefault(o => o.Url == curUrl) != null)
continue;
foreach (var t in tags)
{
var tag = pc.Tags.Where(o => o.Name == t).FirstOrDefault();
if (tag == null)
{
tag = new ViewModel.Tag(t);
}
q[i].Tags.Add(tag);
try
{
await pc.SaveChangesAsync();
}
catch { }
}
pc.Pictures.Add(q[i]);
try
{
await pc.SaveChangesAsync();
}
catch { }
dbUploadProgress.Value = (i + 1) / (double)imgcount;
}
}
q.Clear();
MainWindow.AddLog(string.Format("Saved {0} pictures.", imgcount));
dbUploadProgress.Visibility = Visibility.Collapsed;
await Task.Delay(1500);
}
catch { }
if (isStopped)
break;
}
}
不过问题依然存在
你为什么不 运行 一个 dbContext.Get.Any(x=>x.Name==tag.Name) 并跳过添加基于它的新标签?
我认为问题在于您的队列异步处理消息,因此您可以有 2 个线程尝试插入相同的标签,因为在插入之前检查是否存在逻辑 运行。
您可以通过一次只处理 1 个队列消息(让一个 worker/thread 处理队列)来解决问题。
或者另一种解决方法可能是隔离保存在 try catch 中的标签并正确处理重复的异常(从 db 重新加载标签并在将其设置到新对象时使用该标签)。