Har*_*lse 7 c# entity-framework entity-framework-6
补充(1):其中一个答复说它应该有效。所以我在这篇文章的末尾添加了完整的异常
简化:我有一系列对象,每个对象都有其他对象的集合。一个例子是包含帖子集合的博客。MSDN 经常使用这个作为例子
我看到的是,如果我创建一个博客,我可以添加一些帖子,将博客添加到数据库并调用 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; }
}
Run Code Online (Sandbox Code Playgroud)
用法如下:
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();
Run Code Online (Sandbox Code Playgroud)
好处是,客户端不必知道数据库的实际组织方式。客户端不必知道博客和帖子位于不同的表中。对于客户来说,博客有一系列帖子。
同样,如果客户请求博客并访问博客中的帖子,实体框架知道从哪里获取帖子。客户端不必知道帖子使用外键保存在不同的表中。
blog = context.Blogs.First();
var lastPost = blog.Posts.Last();
Run Code Online (Sandbox Code Playgroud)
实体框架非常智能,它不会选择不需要的项目。如果我不使用 Post 集合,则不会从数据库中检索 Posts
因此我预计以下内容会起作用:
blog.Posts.Remove(lastPost);
context.AddOrUpdate(blog);
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
我原以为实体框架会知道最后一个帖子已被删除,因此会命令从帖子表中删除该项目。但它并没有这样做。我收到一个异常,“该关系无法更改,因为一个或多个外键属性不可为空。bla bla”,这意味着该帖子应该已从帖子表中删除。
问题:除非要删除数据,否则客户端不必知道实体框架创建的数据库模型,这是否正确?
添加:当然,我可以从 DbSet 中删除该项目,但我的问题是:如果实体框架足够智能,我不必将帖子添加到 DbSet 中,为什么我必须删除它?
有人询问异常文本
System.InvalidOperationException 未处理
_message=操作失败:无法更改关系,因为一个或多个外键属性不可为空。当关系发生更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。
HResult=-2146233079
StackTrace:在System.Data.Entity.Core.Objects.ObjectContext.PrepareToSaveChanges(SaveOptions选项)在System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions选项,布尔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()在TryInMemoryDbSet.TestDirectDbContext.Test2()在c:\ Users \ Harald \ Documents \ Visual Studio 2013 \ Projects \ EntityFramework \ TryInMemoryDbSet \ TryInMemoryDbSet \ TestDirectDbContext.cs:第75行在TryInMemoryDbSet.Program.Main(String [] args)在c: \Users\Harald\Documents\Visual Studio 2013\Projects\EntityFramework\TryInMemoryDbSet\TryInMemoryDbSet\Program.cs:第 19 行 InnerException:
问题:除非要删除数据,否则客户端不必知道实体框架创建的数据库模型,这是否正确?
添加:当然,我可以从 DbSet 中删除该项目,但我的问题是:如果实体框架足够智能,我不必将帖子添加到 DbSet 中,为什么我必须删除它?
答:
您应该将其从集合中删除,DbSet因为当您从集合中删除它时,您实际上正在删除它们之间的“关系”。但是,关系(在您的情况下)是强制性的,帖子的BlogId属性不为空,这意味着所有帖子都必须属于博客。当您从集合中删除时,EF 尝试将 FK 设置为空值,这就是您收到异常的原因。
Post这是当您从 a 中删除 a 时 EF 执行的生成 SQLBlog
UPDATE [dbo].[Posts]
SET [BlogId] = NULL
WHERE ([Id] = @0)
Run Code Online (Sandbox Code Playgroud)
如果可以为空,它就会起作用BlogId。
| 归档时间: |
|
| 查看次数: |
5626 次 |
| 最近记录: |