实体框架3.5动态创建实体

时间:2015-10-14 15:37:44

标签: c# .net sql-server entity-framework

假设一个简单的数据模型,由两个表Book和Author组成,由外键约束“Book.AuthorId = Author.Id”相关联。

现在说你有一些平面的书籍清单:

Title                          Author
---------------------------------------------------------
The Selfish Gene               Richard Dawkins
Why Is Sex Fun                 Jared Diamond
The Ancestors Tale             Richard Dawkins

如何在不进行数以万计的数据库往返的情况下导入这些内容?

我是EF的新手,但我认为它可以让我将实体添加到对象上下文中,然后即使它们尚未保存,它们也可以在上下文中使用。事实似乎并非如此。原则上,我这样做:

void Import()
{
    ctx = new Database();
    foreach (...)
    {
        Import(bookTitle, authorName);
    }

    ctx.SaveChanges();
}

void Import(string bookTitle, string authorName)
{
    var author = ctx.Authors.Single(a => a.Name == authorName);
    if (author == null)
    {
        author = new Author();
        author.Name = authorName;
        ctx.AddToAuthors(author);
    }

    var book = new Book();
    book.Author = author;

    ctx.AddToBooks(book);
}

但EF从未找到我已添加的作者,因此每次都会创建一个新作者。因此,道金斯的两本书与图中的两个不同的作者对象有关,这当然是错误的。

接下来,在SaveChanges上,EF设法插入第一本Book和Author记录,但随后在第二次使用PRIMARY KEY VIOLATION崩溃,因为它尝试对每个对象使用Id = 0。

System.Data.UpdateException: An error occurred while updating the entries.
See the InnerException for details. ---> 
  System.Data.SqlClient.SqlException: Violation of PRIMARY KEY 
  constraint 'PK_Book'. Cannot insert duplicate key in object 'dbo.Book'.

我尝试在MSSQL中将id字段的定义更改为INT IDENTITY(1,1),然后更新模型。让数据库定义键值无论如何都比实体框架(或任何客户端)更好。但这似乎根本不受支持。当我更新模型时,EF似乎没有注意到我的键是IDENTITY列。它只是导致

System.Data.UpdateException: An error occurred while updating the entries. 
See the InnerException for details. ---> 
  System.Data.SqlClient.SqlException: Cannot insert explicit value for 
  identity column in table 'Book' when IDENTITY_INSERT is set to OFF.

无论是否更新模型,都会提供确切的症状,无论是从“Id INT PRIMARY KEY”切换到“Id INT IDENTITY(1,1)PRIMARY KEY”还是列定义,这是让我怀疑的原因微软甚至都没记得想过关于身份栏目,但我希望我对此错了!

我意识到这里潜藏着多个问题,但由于实体框架中的任何内容都没有按预期工作,我选择将这个首要问题放在“给定此数据模型并导入这些数据”,使用这些数据的好方法是什么?实体框架3.5?“

请不要建议我使用EF 4.0,因为这超出了我的控制范围。 :)

1 个答案:

答案 0 :(得分:0)

我的问题是基于误解 - 实际上将对象添加到对象上下文而不保存会使它们在对象上下文中可用。

真正发生的是:我使用Reflection.Load从powershell脚本中触发.net程序集中的逻辑。当我在.net项目中进行更改,重建它并对其进行GAC编辑,然后重新编写我的PowerShell脚本时,我仍在运行旧代码。基本上来自MyAssembly.dll的代码链接到powershell会话,所以当我重新运行脚本时,新代码的代码已部署到GAC并不重要......

然后PK违规是有道理的,因为我的代码没有为实体分配ID并且有多个作者 - 我试图用ID = 0保存两者。

当IDENTITY INSERT关闭时“无法插入显式值”现在也有意义,因为我已经修改了我的数据库但仍在运行应该插入ID的代码。

简而言之,解决问题的方法是关闭我的PowerShell会话并开始一个新的会议。