在此代码中,我有一个Entity Framework 4模型,其中包含一个具有Id和Name(字符串)列的“Thing”实体。我想确保当我从多个线程调用FindOrCreateThing(name)时,将只使用给定名称创建Things表中的一行。
目前,我正在使用锁来实现这一目标,而且似乎有效......但是,有哪些更好的方法?如何在其他项目中处理这种常见情况?
谢谢!
class Program
{
private static string[] names = new string[] { "Alpha", "Beta", "Delta", "Gamma", "Zeta" };
static void Main(string[] args)
{
// Multiple threads trying to create things, often with the same name,
// but only allow one thread to actually create the record if it doesn't
// exist.
for (int i = 0; i < 100; i++)
{
Thread thread = new Thread(new ThreadStart(MakeThings));
thread.Start();
}
}
static void MakeThings()
{
try
{
foreach (var name in names)
{
Thing t = FindOrCreateThing(name);
Console.WriteLine("Thing record returned: id={0}; name={1}", t.Id, t.Name);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private static object createLock = new object();
private static Thing FindOrCreateThing(string name)
{
using (EFModel context = new EFModel())
{
// Find the record. If it already exists, return it--we're done.
var thing = (from t in context.Things
where t.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase)
select t).SingleOrDefault();
if (thing == null)
{
// The record does not exist, so wait for lock.
// This will prevent multiple threads from trying to
// create the same record simultaneously.
lock (createLock)
{
// Single thread is here... check if a thread before us
// has already created the record. (I hate having to do this
// same query twice!)
thing = (from t in context.Things
where t.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase)
select t).SingleOrDefault();
if (thing == null)
{
// We're the first thread here, so create the record.
// This should mean that the record is unique in the table.
thing = new Thing { Name = name };
context.Things.AddObject(thing);
context.SaveChanges();
}
}
}
return thing;
}
}
}
答案 0 :(得分:1)
只需在DB列上添加一个唯一约束即可。然后你可以摆脱所有的锁定,并捕获(如果你搜索,找不到任何东西,并创建)你将获得的(不太可能,但可能)异常,而另一个线程做同样的事情。如果你抓住了,只需重试整个过程。
答案 1 :(得分:0)
如果实体后面的商店是某个RDBMS,那么在列上创建唯一索引可能会更有效。它会减少到服务器的往返,你不需要在客户端进行锁定。