附加内容(1):其中一条回复说它应该可行。因此,我在本文末尾添加了完整的异常信息
简述:我有一个对象序列,每个对象都有其他对象的集合。这个集合的一个例子是带有文章集合的博客。MSDN经常将其用作示例。
我发现,如果我创建一个博客,可以添加一些文章,将博客添加到数据库并调用SaveChanges。实体框架会识别出这些文章应该在不同的表中,并与博客表相关联的外键。
这正是如果没有Entity Framework,我们将如何创建数据库。
从博客中获取所有文章并添加文章可以在不了解单独的文章表和外键到博客表的情况下完成。
然而,当我尝试从博客中删除文章时,突然出现有关外键的错误。
注意:以下内容与效率无关
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();
客户端无需知道数据库的实际组织方式,这是件好事。客户端无需知道博客和帖子存储在不同的表中。对于客户端而言,博客拥有一系列的帖子。
同样地,如果客户端请求博客并访问其中的帖子,Entity Framework 就知道如何获取这些帖子。客户端无需知道这些帖子存储在另一个带有外键的表中。
blog = context.Blogs.First();
var lastPost = blog.Posts.Last();
Entity Framework非常智能,不会选择不需要的项。如果我不使用Post集合,则不会从数据库中检索到帖子
因此,我原以为以下代码可以工作:
blog.Posts.Remove(lastPost);
context.AddOrUpdate(blog);
context.SaveChanges();
我原本以为实体框架会知道最后一个帖子已被删除,因此会将该项从“帖子”表中删除。但它并没有这样做。我会得到一个异常,“无法更改关系,因为一个或多个外键属性是非空的。bla bla”,这意味着帖子应该已经从“帖子”表中删除了。
问题:客户端是否不需要了解实体框架创建的数据库模型,除非要删除数据?
补充说明:当然,我可以从DbSet中删除该项,但我的问题是:如果实体框架足够聪明,我不必将帖子添加到DbSet中,那么我为什么要将其删除?
有人要求提供异常文本:
System.InvalidOperationException未处理
_HResult=-2146233079 _message=操作失败:无法更改关系,因为一个或多个外键属性是非空的。当更改关系时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,将外键属性分配给另一个非空值,或删除无关对象。 HResult=-2146233079 IsTransient=false Message=操作失败:无法更改关系,因为一个或多个外键属性是非空的。当更改关系时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,将外键属性分配给另一个非空值,或删除无关对象。 Source=EntityFramework
StackTrace: at System.Data.Entity.Core.Objects.ObjectContext.PrepareToSaveChanges(SaveOptions options) at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction) at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options) at System.Data.Entity.Internal.InternalContext.SaveChanges() at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() at System.Data.Entity.DbContext.SaveChanges() at TryInMemoryDbSet.TestDirectDbContext.Test2() in c:\Users\Harald\Documents\Visual Studio 2013\Projects\EntityFramework\TryInMemoryDbSet\TryInMemoryDbSet\TestDirectDbContext.cs:line 75 at TryInMemoryDbSet.Program.Main(String[] args) in c:\Users\Harald\Documents\Visual Studio 2013\Projects\EntityFramework\TryInMemoryDbSet\TryInMemoryDbSet\Program.cs:line 19 InnerException:
blog.Posts.Remove(lastPost)
,然后调用context.SaveChanges()
吗? - rexcfnghkAddOrUpdate()
调用?如果您的实体由DbContext
跟踪,则 EF 足够智能,可以将实体检测为EntityState.Modified
。 - rexcfnghk