2016-04-28 39 views
1

下面的方法将一些分离的节点作为输入参数。目标是从数据库加载任何现有的别名,将缺失的节点插入数据库,并且如果分离的节点的别名实体已经在数据库中,只需将其设置为数据库中的一个。实体框架6 - 分离的实体防止保存重复的导航属性

但是,在SaveChanges()上,数据库中已经存在的别名似乎又被插入了。我如何解决这个问题?

internal async Task InsertMissingNodesToDb(INWatchNode[] nodes) 
{ 
    if (nodes.Any(x => x == null)) { 
     Trace.TraceError("Some null element in nodes array in InsertMissingNodesToDb()."); 
     nodes = nodes.Where(x => x != null).ToArray(); 
    } 

    // De-dup nodes based on ID 
    nodes = nodes.GroupBy(x => x.Id).Select(y => y.FirstOrDefault()).ToArray(); 
    List<string> aliasNames = new List<string>(); 

    foreach (var node in nodes) { 
     foreach (var alias in node.Aliases) { 
      if (!aliasNames.Contains(alias)) { 
       aliasNames.Add(alias); 
      } 
     } 
    } 

    using (var dbContext = Application.GetDbContext()) { 
     dbContext.Aliases.Where(x => aliasNames.Contains(x.Alias)).Load(); 

     foreach (var node in nodes) { 
      var entityNode = await dbContext.Nodes.FindAsync(node.Id); 

      if (entityNode == null) { 
       entityNode = node is NWatchNode ? (NWatchNode)node : new NWatchNode(node); 

       for (int i = 0; i < entityNode.AliasEntities.Count; i++) { 
        var currentElement = entityNode.AliasEntities.ElementAt(i); 
        var loadedAlias = dbContext.Aliases.Local. 
         FirstOrDefault(x => x.Alias == currentElement.Alias); 
        if (loadedAlias != null) { 
         currentElement.Id = loadedAlias.Id; 
         currentElement = loadedAlias; 
         dbContext.Entry(loadedAlias).State = EntityState.Unchanged; 
        } 
       } 

       dbContext.Nodes.Add(entityNode); 
      } 
     } 
     await dbContext.SaveChangesAsync(); 
    } 
} 

回答

0

我对这段代码感到怀疑。

currentElement.Id = loadedAlias.Id; 
currentElement = loadedAlias; // this seems pointless 
dbContext.Entry(loadedAlias).State = EntityState.Unchanged; 

如果你想在这个行做一些事情,我想你需要设置entityNode.AliasEntities.ElementAt(i)loadedAlias - 设置currentElementloadedAlias只是重写本地实例变量在loadedAlias点,因此看起来毫无意义代码 - 你没有通知实体,它的一个有意的孩子应该用这一行指向这个实例。类似以下内容可能会阻止该问题?

for (int i = 0; i < entityNode.AliasEntities.Count; i++) { 
    var currentElement = entityNode.AliasEntities.ElementAt(i); 
    var loadedAlias = dbContext.Aliases.Local. 
     FirstOrDefault(x => x.Alias == currentElement.Alias); 
    if (loadedAlias != null) { 
     currentElement.Id = loadedAlias.Id; 
     entityNode.AliasEntities.ElementAt(i) = loadedAlias; 
     dbContext.Entry(loadedAlias).State = EntityState.Unchanged; 
    } 
} 
+0

'entityNode.AliasEntities.ElementAt(ⅰ)= loadedAlias;'不编译:( AliasEntites是ICollection的,所以我得到的信息,即左手必须是一个属性或索引 – blgrnboy

+0

我或许你需要删除'currentElement',然后添加'loadedAlias'而不是? –

+0

你说得对,我必须做一个'entityNode.AliasEntities.Remove(currentElement);'insetad,然后'entityNode.AliasEntities。添加(loadedAlias);' 偶然的,你知道如果Remove()去掉哈希以找到一个要移除的元素,或者它会使用Id吗? – blgrnboy