实体框架在savechanges上将错误的实体插入到db中

时间:2013-03-16 06:30:18

标签: c# entity-framework-5

我正在尝试编写程序来扫描包含tv show文件夹的目录,使用tvrage API查找有关节目的一些详细信息,然后使用实体框架将详细信息保存到数据库中。

我的TVShow表pkey与从tvrage数据库show id获取的值相同,当重复或类似的文件夹名称返回相同的Show info时,我遇到了问题。在我有一个包含三个文件夹的目录的情况下,“Alias”,“Alias 1”,“Band of Brothers”我从我的代码中得到以下输出

  

* 电视节目 *

     

Alias .......没有比赛......添加........ DONE

     

别名1 ......没有匹配.....添加....无法添加,ID已存在于数据库中

     

兄弟乐队......没有比赛.....ADING ....

在context.SaveChanges()上获取UpdateException之前;线 违反PRIMARY KEY约束'PK_TVShows'。

我可以看到使用SQL分析器,问题是我的应用程序尝试使用重复键第二次在别名显示上执行插入,但我看不出原因。当我在foreach循环的第二次交互(第二个“别名”文件夹)上单步执行代码时,会绕过将show实体保存到数据库的代码。

当我为“兄弟乐队”创建一个新的TVShow实体时,它只在foreach循环的下一次迭代中进行 实际上达到了将Tvshow添加到上下文并保存的代码,此时应用程序崩溃了。在视觉工作室,我可以看到 在崩溃的那一点;

  • 在上下文中“显示”实体.TVShows.AddObject(show)是带有唯一ID的“兄弟带”
  • context.TVShows只包含一条记录,即第一个Alias Entity

但SQL分析器显示EntityFramework是第二次插入Alias,我很难理解为什么

    private void ScanForTVShowFolders( GenreDirectoryInfo drive ) {
        IEnumerable<DirectoryInfo> shows = drive.DirInfo.EnumerateDirectories();

        foreach (DirectoryInfo d in shows) {
        //showList contains a list of existing TV show names previously queried out of DB
            if (showList.Contains(d.Name)) {
                System.Console.WriteLine(d.Name + ".....MATCH");

            } else {
                System.Console.Write(d.Name + "......NO MATCH..ADDING....");
                TVShow show = LookUpShowOnline(d.Name, drive.GenreName);

                if (show.Id == -1) {   // id of -1 means online search failed
                    System.Console.Write("..........CANT FIND SHOW" + Environment.NewLine);

                } else if (context.TVShows.Any(a => a.Id == show.Id)) {  //catch duplicate primary key insert
                    System.Console.Write(".......CANT ADD, ID ALREADY EXISTS IN DB" + Environment.NewLine);

                } else {
                    context.TVShows.AddObject(show);
                    context.SaveChanges();
                    System.Console.Write("....DONE" + Environment.NewLine);
                }

            }

        }

        private TVShow LookUpShowOnline( string name, string genre ) {

        string xmlPath = String.Format("http://services.tvrage.com/feeds/search.php?show='{0}'", name);

        TVShow aShow = new TVShow();
        aShow.Id = -1; // -1 = Can't find

        XmlDocument xmlResp = new XmlDocument();
        try { xmlResp.Load(xmlPath); } catch (WebException e) { System.Console.WriteLine(e); }

        XmlNode root = xmlResp.FirstChild;
        if (root.NodeType == XmlNodeType.XmlDeclaration) { root = root.NextSibling; }

        XmlNode tvShowXML;
        //if (showXML["episode"] == null)
        //    return false;

        tvShowXML = root["show"];

        if (tvShowXML != null) {

            aShow.Id = System.Convert.ToInt16(tvShowXML["showid"].InnerText);
            aShow.Name = tvShowXML["name"].InnerText.Trim();
            aShow.StartYear = tvShowXML["started"].InnerText.Trim();
            aShow.Status = tvShowXML["status"].InnerText.Trim();
            aShow.TVGenre = context.TVGenres.Where(b => b.Name.Trim() == genre).Single();
        }

        return aShow;
    }


}

修改的 做了一些阅读我将context.ObjectStateManager添加到我的调试监视列表中,每次我创建一个新的TVShow实体时都会看到一条新记录被添加到_addedEntityStore。实际上,如果我删除context.TVShows.AddObject(show),代码仍会更新数据库,因此手动添加到上下文似乎是多余的。

2 个答案:

答案 0 :(得分:0)

如果您通过foreach循环插入对象&gt;最好将主键保持在外面并使其增加!

例如:int newID = Shows.Select(d =&gt; d.Id).Max();

的foreach(............)
{

show.Id = newID++;  
.  
.  
.  //remaining fields
.   

context.TVShows.AddObject(显示);

}
context.SaveChanges();

它对我有用...... !!

答案 1 :(得分:0)

结果是context.TVShows.AddObject(show)在我的情况下是不必要的,当这个查询运行时,我无意中将所有创建的show实体添加到上下文

aShow.TVGenre = context.TVGenres.Where(b =&gt; b.Name.Trim()== genre).Single();

这不是我想要的,我只想创建对象,然后决定是否添加它。现在很容易解决,我知道它为什么会发生。