2015-04-04 53 views
0

我很努力地刪除內存中沒有推送到數據庫的實體。EF 6代碼首先,如何在引用的ICollection中保留刪除操作

博客實體在Posts集合中引用0..n個條目。

添加或更改條目公佈西港島線產生更新或插入上下文對象上調用SaveChanges之後的語句。

但是,當我刪除一篇文章,然後這個刪除操作不推送到數據庫。

爲了重現我的問題,我使用下面顯示的博客/帖子模型創建了這個小樣本。

我的方案是一個基於Web的應用程序,其中一個博客條目和所有相關的職位應在第一次請求被加載,然後帖收集應修改,應該被保存到數據庫上的其他請求。

我嘗試使用下面示例代碼中的2個不同的DbContext實例readCtx & writeCtx來模擬此場景。

添加或更改帖子條目工作正常,我得到每個帖子條目的更新語句。

但是:我刪除單篇文章的方式不會被推到數據庫中,我不知道,EF是如何打算用於此。

如果我刪除帖子的條目,如下圖所示,然後EF不會忽略它,不會發出delete語句。

的帖子收集應綁定到UI,所以我想裏面反映任何更改到數據庫中。

我在做什麼錯?

using System.Collections.Generic; 
using System.Data.Entity; 
using System.Diagnostics; 
using System.Linq; 

namespace EFDeleteTest 
{ 


    public class Blog 
    { 
     public Blog() 
     { 
      Posts = new List<Post>(); 
     } 
     public int BlogId { get; set; } 
     public string Name { get; set; } 
     public virtual ICollection<Post> Posts { get; set; } 
    } 

    public class Post 
    { 
     public int PostId { get; set; } 
     public string Title { get; set; } 
     public string Content { get; set; } 
     public virtual Blog Blog { get; set; } 
    } 

    public class BlogSystemDbContext : DbContext 
    { 
     public DbSet<Blog> Blogs { get; set; } 
     public DbSet<Post> Posts { get; set; } 

     public BlogSystemDbContext() {  } 
    } 

    class Program 
    { 
     private static void LogSql(string sqlStmt) 
     { 
      System.Diagnostics.Debug.WriteLine(sqlStmt); 
     } 
     static void Main(string[] args) 
     { 
      Blog blog = null; // Should be used in the web app for binding it to the UI 

      using (var readCtx = new BlogSystemDbContext()) 
      { 
       blog = readCtx.Blogs.Include(b1 => b1.Posts).Where(b2 => b2.Name == "Blog X").SingleOrDefault(); 
      } 

      // Simulate the next HTTP Request 
      using (var writeCtx = new BlogSystemDbContext()) 
      { 
       writeCtx.Database.Log = LogSql; 
       // delete the last post: 
       int count = blog.Posts.Count; 
       var postToDelete = blog.Posts.Skip(count - 1).Take(1).SingleOrDefault(); 
       blog.Posts.Remove((Post)postToDelete); 

       writeCtx.Blogs.Attach(blog); 
       writeCtx.Entry(blog).State = blog.BlogId == 0 ? EntityState.Added : EntityState.Modified; 


       foreach (var post in blog.Posts) 
       { 
        writeCtx.Entry(post).State = post.PostId == 0 ? EntityState.Added : EntityState.Modified; 
       } 
       writeCtx.SaveChanges(); 
      } 
     } 
    } 
} 

的web.config:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <configSections> 
     <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> 
     <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> 
    </configSections> 

    <connectionStrings> 
     <add name="BlogSystemDbContext" providerName="System.Data.SqlClient" connectionString="Data Source=.;Initial Catalog=BlogSystemDB;Integrated Security=true;MultipleActiveResultSets=true " /> 
    </connectionStrings> 

    <startup> 
     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> 
    </startup> 

    <entityFramework> 
     <providers> 
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> 
     </providers> 
    </entityFramework> 
</configuration> 

回答

0

的問題是,由...

writeCtx.Blogs.Attach(blog); 
writeCtx.Entry(blog).State = blog.BlogId == 0 ? EntityState.Added : EntityState.Modified; 

你只標記blog的修改,而不是它的Posts集合。 EF甚至沒有收集這個系列。這是一個設計事實。

有幾種方法可以解決這個問題。昂貴的解決方案是從數據庫中重新提取blog,包括其Posts,並從現在更改跟蹤的集合中刪除帖子。

更便宜的解決方案是創建一個存根實體 ...

var post = new Post { ID = blog.Posts.Skip(count - 1).Take(1).ID }; 

...它附加到上下文Deleted

我不能判斷哪個選項在真實應用程序中適用於您,但當然您應該試試便宜選項。

+0

嗨格特,感謝您的迴應,這實際上幫助我瞭解EF如何工作。 我現在知道,所有更改跟蹤都是在上下文級別完成的,如果我想要更改跟蹤機制來幫助我,我必須附加一個對象。 謝謝 – SteveR 2015-04-11 12:13:52