我的数据库中有两个表由外键连接:Page(PageId,其他数据)和PageTag(PageId,Tag)。我已经使用LINQ为这些表生成类,其中页面作为父级,Tag作为子集合(一对多关系)。有没有办法在Page类中标记PageTag记录以便从数据库中删除?
快速清除:
我希望在父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对象中添加了一个属性,用于将Tag集合视为字符串:
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类。
是否有人知道如何在Page类中标记要从数据库中删除的子元素?
答案 0 :(得分:6)
经过一些研究,我相信我已经设法找到了解决方案。将对象从集合中删除时标记要删除的对象由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
答案 1 :(得分:1)
对不起,我的不好。那不行。
看起来您需要在存储库中执行此操作,而不是在Page类中执行此操作。在那里,您可以访问原始数据上下文。
有一种方法可以“附加”原始数据上下文,但是当你这样做时,它就变成了代码味道。
答案 2 :(得分:0)
你的Linq to SQL实体图中是否有关系,链接Page和PageTags表?如果不这样做,那就是为什么你无法从Page类中看到PageTags类。
如果PageTags数据库表中的外键设置为Allow Nulls,则将表拖到设计器中时,Linq to SQL将不会创建链接,即使您在SQL Server上创建了关系。
答案 3 :(得分:0)
这是OR映射可以变得多毛的区域之一。提供这个TagString属性可以使事情更方便,但从长远来看,它会混淆当有人使用TagString属性时真正发生的事情。通过隐藏执行数据修改的事实,有人可以很容易地在DataContext的范围内使用PageString并设置TagString,这可能导致一些难以发现的错误。
更好的解决方案是使用L2S模型设计器在Page类上添加Tags属性,并要求在DataContext范围内直接在Tags属性上编辑PageTags。使TagString属性只读,因此它可以进行生成处理(并且仍然提供一些便利),但消除了设置该属性的困惑和困难。这种变化澄清了意图,并且明确了正在发生的事情以及Page对象的消费者为实现这一目标所需要的内容。
由于Tags是Page对象的属性,只要它附加到DataContext,对该集合的任何更改都将正确触发数据库中的删除或插入,以响应“删除”或“添加”调用。
答案 4 :(得分:0)
亚伦
显然你必须通过你的PageTag记录循环,为每个记录调用DeleteOnSubmit。 Linq to SQL应该创建一个聚合查询,以便在调用SubmitChanges时立即删除所有记录,因此开销应该是最小的。
替换
PageTags.Clear();
与
foreach (PageTag tag in PageTags)
myDataContext.DeleteOnSubmit(tag);
答案 5 :(得分:0)
亚伦:
将DataContext成员添加到PageTag分部类。
partial class PageTag
{
DataClassesDataContext myDataContext = new DataClassesDataContext();
public string TagString {
...等。
答案 6 :(得分:0)
Robert Harvey的要求发布了更大的代码示例:
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 });
}