0

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

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

* 电视节目 *

别名.......不匹配......添加............完成

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

兄弟乐队......不匹配......添加......

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

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

只有在 foreach 循环的下一次迭代中,当我为“Band of Brothers”创建了一个新的 TVShow 实体时,我才真正到达将 Tvshow 添加到上下文并保存的代码,此时应用程序崩溃。在视觉工作室中,我可以在崩溃点看到;

  • context.TVShows.AddObject(show) 中的“show”实体是带有唯一 ID 的“Band of Brothers”
  • 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) 代码仍然会更新数据库,因此手动添加到上下文似乎是多余的。

4

2 回答 2

0

如果您通过 foreach 循环插入对象 > 最好将主键保持在外部并使其递增!

例如: int newID= Shows.Select(d=>d.Id).Ma​​x();

foreach(…………)
{

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

context.TVShows.AddObject(show);

}
context.SaveChanges();

这个对我有用...!!

于 2013-03-16T07:10:31.183 回答
0

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

aShow.TVGenre = context.TVGenres.Where(b => b.Name.Trim() == Genre).Single();

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

于 2013-03-16T07:41:00.047 回答