使用Linq to SQL执行合并操作

8

SQL Server 2008 Ent ASP.NET MVC 2.0 Linq-to-SQL

我正在建设一个游戏网站,用于追踪特定玩家(角色)何时击败特定怪物(boss)。表格大致如下:

int ToonId
int BossId
datetime LastKillTime

我使用第三方服务获取最新的信息(toon,boss,time)。现在我想用这些新信息更新我的数据库。暴力的方法是逐行进行upsert。但是这看起来很丑陋(代码上),而且可能也很慢。
我认为更好的解决方案是插入新数据(使用临时表?),然后运行MERGE语句。
这是个好主意吗?我知道应该尽量避免使用临时表。我应该为此操作创建一个永久的“临时”表吗?还是我只需要读取整个当前集合(最多100行),执行合并并从应用程序中重新放回?
任何指针/建议都会被赞赏。
4个回答

7
如果你正在使用Linq-to-SQL,upsert并不那么丑陋。
foreach (var line in linesFromService) {
   var kill = db.Kills.FirstOrDefault(t=>t.ToonId==line.ToonId && t.BossId==line.BossId);
   if (kill == null) {
      kill = new Kills() { ToonId = line.ToonId, BossId = line.BossId };
      db.Kills.InsertOnSubmit(kill);
   }
   kill.LastKillTime = line.LastKillTime;
}
db.SubmitChanges();

虽不是艺术品,但比SQL更好看。而且,仅有100行数据,性能方面不用过于担心。


我同意,在这里性能不是问题,所以请使用 LINQ 方法而不是丑陋的 SQL。 - user76071

7

ORM并不适合执行批量操作,Linq-to-SQL也不例外。在这种情况下,我认为你选择了正确的解决方案:快速将所有条目存储到临时表中,然后使用合并(merge)进行UPSERT操作。

存储数据到临时表的最快方法是使用SqlBulkCopy将所有数据存储到所选表中。


0

如果您想在不先查询记录的情况下进行更新,可以执行以下操作。它仍将访问数据库一次以检查记录是否存在,但不会拉取记录:

var blob = new Blob { Id = "some id", Value = "some value" }; // Id is primary key (PK)

if (dbContext.Blobs.Contains(blob)) // if blob exists by PK then update
{
    // This will update all columns that are not set in 'original' object. For
    // this to work, Blob has to have UpdateCheck=Never for all properties except
    // for primary keys. This will update the record without querying it first.
    dbContext.Blobs.Attach(blob, original: new Blob { Id = blob.Id });
}
else // insert
{
    dbContext.Blobs.InsertOnSubmit(blob);
}
dbContext.Blobs.SubmitChanges();

请参见此处的扩展方法。


0

看起来是一个直接的插入。

private ToonModel _db = new ToonModel();
Toon t = new Toon();
t.ToonId = 1;
t.BossId = 2;
t.LastKillTime = DateTime.Now();
_db.Toons.InsertOnSubmit(t);
_db.SubmitChanges();

3
如果我已经有ID为1的Toon,那么这不会给我“重复的id”吗? - THX-1138

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接