增加(1):其中一份回复说它应该有效。所以我在这篇文章末尾添加了完整的例外
简化:我有一系列对象,每个对象都有一组其他对象。这方面的一个例子是一个包含帖子集的博客。 MSDN经常使用它作为示例
MSDN Code First to a new DataBase
我看到的是,如果我创建一个博客,我可以添加一些帖子,将博客添加到数据库并调用SaveChanges。实体框架认识到帖子应该在与博客表的外键不同的表中。
如果实体框架不存在,这正是人们创建数据库的方式。
从博客获取所有帖子并添加帖子可以在不知道单独的Post表和Blog表的外键的情况下完成。
然而,当我尝试从博客中删除帖子时突然发现外键错误。
注意:以下内容与效率无关
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; }
}
public class BloggingContext : DbContext
{
public BloggingContext(string nameOrConnectionString)
: base(nameOrConnectionString){}
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
用法如下:
class Program
{
static void Main(string[] args)
{
const string dbName = "MyTestDb";
Database.SetInitializer(new DropCreateDatabaseAlways <BloggingContext> ());
using (var context = new BloggingContext(this.DbName))
{
// create a blog:
var blog = new Blog()
{
Name = "First Blog",
Posts = new List<Post>()
{
new Post() { Title = "My 1st Post", Content = "Hello World!" },
new Post() { Title = "My 2nd Post", Content = "All animals are equal but pigs are more equal"},
new Post() { Title = "My 3rd Post", Content = "Shall I compare thee to a summer's day" },
},
};
context.Blogs.Add(blog);
context.SaveChanges();
好消息是,客户端不必知道数据库的实际组织方式。客户端不必知道Blog和Post位于不同的表中。对于客户来说,博客有一系列帖子。
同样,如果客户要求博客并访问博客中的帖子,则实体框架知道在哪里获取帖子。客户端不必知道帖子与外键一起保存在不同的表中。
blog = context.Blogs.First();
var lastPost = blog.Posts.Last();
实体框架因此很聪明,它不会选择不需要的项目。如果我不使用Post集合,则不会从数据库中检索帖子
因此,我原以为以下方法可行:
blog.Posts.Remove(lastPost);
context.AddOrUpdate(blog);
context.SaveChanges();
我曾预料到实体框架会知道最后一个帖子已被删除,因此会命令从帖子表中删除该项目。但它并没有这样做。我得到一个例外,“关系无法更改,因为一个或多个外键属性是不可为空的.bla bla”,这意味着Post应该从Posts表中删除。
问题:除非要删除数据,否则客户端不必知道实体框架创建的数据库模型是否正确?
添加:当然我可以从DbSet中删除该项,但我的问题是:如果Entity Framework足够智能,我不必将帖子添加到DbSet,为什么我必须删除它? / p>
有人要求提供例外文字
System.InvalidOperationException未处理
_message =操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。
的HResult = -2146233079
堆栈跟踪: 在System.Data.Entity.Core.Objects.ObjectContext.PrepareToSaveChanges(SaveOptions选项) at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options,Boolean executeInExistingTransaction) 在System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions选项) 在System.Data.Entity.Internal.InternalContext.SaveChanges() 在System.Data.Entity.Internal.LazyInternalContext.SaveChanges() 在System.Data.Entity.DbContext.SaveChanges() at c:\ Users \ Harald \ Documents \ Visual Studio 2013 \ Projects \ EntityFramework \ TryInMemoryDbSet \ TryInMemoryDbSet \ TestDirectDbContext.cs中的TryInMemoryDbSet.TestDirectDbContext.Test2():第75行 在TryInMemoryDbSet.Program.Main(String [] args)中的c:\ Users \ Harald \ Documents \ Visual Studio 2013 \ Projects \ EntityFramework \ TryInMemoryDbSet \ TryInMemoryDbSet \ Program.cs:第19行 InnerException:
答案 0 :(得分:1)
问题:客户不必知道该问题是否正确 创建数据库模型实体框架,除非是数据 去掉?
添加:当然我可以从DbSet中删除该项目,但是我的 问题是:如果实体框架足够聪明,我不必这样做 将帖子添加到DbSet,我为什么要删除它?
Anwser:
您应该从DbSet
中删除它,因为当您从集合中删除它时,实际上是删除了&#34;关系&#34;它们之间。但是,关系(在您的情况下)是强制性的,Post的BlogId
属性不是NULL,这意味着所有帖子必须属于博客。当您从集合中删除时,EF会尝试将FK设置为空值,这就是您获得异常的原因。
这是从Post
Blog
时EF执行的生成的SQL
UPDATE [dbo].[Posts]
SET [BlogId] = NULL
WHERE ([Id] = @0)
如果BlogId
可以为空,那就可以了。
答案 1 :(得分:0)
blog.Posts.Remove(lastPost);
从lastPost
集合中删除blog.Posts
,而不是从数据库中删除。
正如我想象的那样,帖子需要博客,帖子不能存在,PostId的值为null。
至少2个解决方案: