2009-05-23 70 views
2

我有兩個表在我的數據庫連接的外鍵:Page(PageId,其他數據)和PageTag(PageId,標籤)。我已經使用LINQ爲這些表生成類,其中父頁爲父頁,標記爲子集(一對多關係)。有沒有什麼辦法在頁面類中標記PageTag記錄以便從數據庫中刪除?如何從LINQ to SQL中的子集合中刪除記錄?

快速Clearification:

我想要當父DataContext的調用的SubmitChanges(),而不是之前被刪除的子對象。我希望TagString的行爲與Page對象的任何其他屬性完全相同。

我想能夠像下面的代碼:

Page page = mDataContext.Pages.Where(page => page.pageId = 1); 
page.TagString = "new set of tags"; 

//Changes have not been written to the database at this point. 

mDataContext.SubmitChanges(); 

//All changes should now be saved to the database. 

這裏是我的詳細情況:
爲了使與標籤的收集工作更容易,我添加了一個屬性設置即把標籤集合爲一個字符串Page對象:

public string TagString { 
    get { 
     StringBuilder output = new StringBuilder(); 
     foreach (PageTag tag in PageTags) { 
      output.Append(tag.Tag + " "); 
     } 

     if (output.Length > 0) { 
      output.Remove(output.Length - 1, 1); 
     } 

     return output.ToString(); 
    } 
    set { 
     string[] tags = value.Split(' '); 
     PageTags.Clear(); 
     foreach (string tag in tags) { 
      PageTag pageTag = new PageTag(); 
      pageTag.Tag = tag; 
      PageTags.Add(pageTag); 
     } 
    } 
} 

基本上,這個想法是,當標記的字符串被髮送到該屬性,對象的當前標籤被刪除,新的一組中產生他們的地方。

我現在遇到的問題是,這條線:

PageTags.Clear(); 

實際上不會從數據庫中刪除舊的標籤更改提交時。

環顧四周,刪除東西的「正確」方法似乎是調用數據上下文類的DeleteOnSubmit方法。但是我似乎沒有從Page類中訪問DataContext類。

有沒有人知道一種方法來標記子元素從頁面類中的數據庫中刪除?

回答

5

經過一些更多的研究,我相信我設法找到了解決方案。從集合中刪除對象時刪除標記由Association屬性的DeleteOnNull參數控制。

當兩個表格之間的關係用OnDelete Cascade標記時,此參數設置爲true。

不幸的是,無法在設計器中設置此屬性,也無法從* DataContext.cs文件中的分部類中設置該屬性。在不啓用級聯刪除的情況下設置它的唯一方法是手動編輯* DataContext.designer.cs文件。

在我而言,這意味着找到頁關聯,並添加DeleteOnNull屬性:

[Association(Name="Page_PageTag", Storage="_Page", ThisKey="PageId", OtherKey="iPageId", IsForeignKey=true)] 
public Page Page 
{ 
    ... 
} 

並添加DeleteOnNull屬性:

[Association(Name="Page_PageTag", Storage="_Page", ThisKey="PageId", OtherKey="iPageId", IsForeignKey=true, DeleteOnNull = true)] 
public Page Page 
{ 
    ... 
} 

注意,需要被添加到屬性PageTag類的Page屬性,而不是相反。

參見:
Beth Massi -- LINQ to SQL and One-To-Many Relationships
Dave Brace -- LINQ to SQL: DeleteOnNull

0

在Linq to SQL實體關係圖中,您是否有關係鏈接Page和PageTags表?如果你不這樣做,那就是爲什麼你不能從Page類中看到PageTags類。

如果PageTags數據庫表中的外鍵被設置爲Allow Nulls,即使您在SQL Server上創建了關係,Linq to SQL也不會在將表拖入設計器時創建鏈接。

+0

該協會是在地方,我可以通過編程訪問子集。問題是對集合所做的更改(特別是刪除對象)不會持久保存到數據庫。 – AaronSieb 2009-05-23 20:23:45

+0

愚蠢的問題,但你提交更改? – 2009-05-23 21:05:41

+0

是的。當我提交更改時,我得到一個重複鍵錯誤(因爲新標籤重疊舊標籤)。 – AaronSieb 2009-05-23 21:56:46

0

這是OR映射可能會變得毛茸茸的地方之一。提供這個TagString屬性使事情變得更方便一些,但是從長遠來看,它會混淆有人使用TagString屬性時真正發生的事情。通過隱藏您執行數據修改的事實,某人可以很容易地在DataContext的範圍內來訪問並設置TagString而不使用Page實體,這可能會導致一些難以發現的錯誤。

更好的解決方案是使用L2S模型設計器在Page類上添加Tags屬性,並要求在DataContext的範圍內直接在Tags屬性上編輯PageTags。使TagString屬性爲只讀,因此可以進行類型化(並且仍然提供一些便利),但是可以消除設置該屬性的困惑和困難。這種改變澄清了意圖,並明確了正在發生的事情以及Page對象的消費者所需要做的事情。

由於Tags是Page對象的一個​​屬性,只要它連接到DataContext,對該集合的任何更改都會正確觸發數據庫中的刪除或插入操作,以響應Remove或Add calls。

+0

我不希望在從集合中刪除PageTag時立即刪除PageTag。我期待它在父DataContext調用SubmitChanges()時被刪除。 PageTagString屬性的更新語義不打算與對象的任何其他數據屬性不同。 – AaronSieb 2009-05-23 20:28:56

0

亞倫,

顯然,你必須循環通過你的PageTag記錄,調用DeleteOnSubmit爲每一個。當您調用SubmitChanges時,Linq to SQL應該創建一個聚合查詢來一次刪除所有記錄,因此開銷應該很小。

foreach (PageTag tag in PageTags) 
    myDataContext.DeleteOnSubmit(tag); 
+0

如何從我的Page類中訪問DataContext? – AaronSieb 2009-05-23 21:34:58

+0

將DataContext成員添加到您的PageTag部分類中。 部分類PageTag DataClassesDataContext myDataContext = new DataClassesDataContext(); public string TagString { ..等等。 – 2009-05-23 22:55:27

0

亞倫更換

PageTags.Clear(); 

一個DataContext成員添加到您的PageTag局部類。

partial class PageTag 
{ 
    DataClassesDataContext myDataContext = new DataClassesDataContext(); 

    public string TagString { 

..等等。張貼在羅伯特·哈維的要求

0

較大的代碼示例:

DataContext.cs文件:

namespace MyProject.Library.Model 
{ 
    using Tome.Library.Parsing; 
    using System.Text; 

    partial class Page 
    { 
     //Part of Robert Harvey's proposed solution. 
     MyDataContext mDataContext = new TomeDataContext(); 

     public string TagString { 
      get { 
       StringBuilder output = new StringBuilder(); 
       foreach (PageTag tag in PageTags) { 
        output.Append(tag.Tag + " "); 
       } 

       if (output.Length > 0) { 
        output.Remove(output.Length - 1, 1); 
       } 

       return output.ToString(); 
      } 
      set { 
       string[] tags = value.Split(' '); 
       //Original code, fails to mark for deletion. 
       //PageTags.Clear(); 

       //Robert Harvey's suggestion, thorws exception "Cannot remove an entity that has not been attached." 
       foreach (PageTag tag in PageTags) { 
        mDataContext.PageTags.DeleteOnSubmit(tag); 
       } 

       foreach (string tag in tags) { 
        PageTag PageTag = new PageTag(); 
        PageTag.Tag = tag; 
        PageTags.Add(PageTag); 
       } 
      } 
     } 

     private bool mIsNew; 
     public bool IsNew { 
      get { 
       return mIsNew; 
      } 
     } 

     partial void OnCreated() { 
      mIsNew = true; 
     } 

     partial void OnLoaded() { 
      mIsNew = false; 
     } 
    } 
} 

庫方法:

public void Save() { 
    mDataContext.SubmitChanges(); 
} 

public Page GetPage(string pageName) { 
    Page page = 
     (from p in mDataContext.Pages 
     where p.FileName == pageName 
     select p).SingleOrDefault(); 

    return page; 
} 

用法:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Edit(string pageName, FormCollection formValues) { 
    Page updatedPage = mRepository.GetPage(pageName); 

    //TagString is a Form value, and is set via UpdateModel. 
    UpdateModel(updatedPage, formValues.ToValueProvider()); 
    updatedPage.FileName = pageName; 

    //At this point NO changes should have been written to the database. 

    mRepository.Save(); 

    //All changes should NOW be saved to the database. 

    return RedirectToAction("Index", "Pages", new { PageName = pageName }); 
} 
1

對不起,我的錯。這是行不通的。

看起來你確實需要在你的倉庫中做這件事,而不是在你的Page類中。在那裏,您可以訪問您的原始數據上下文。

有一種方法可以「附加」原始數據上下文,但是到那時候,它已經變得相當的代碼味道。