我目前正在开发一个产品管理系统,我有一个文章版本页面,这里是我文章的简短定义:
Article : Id, name, List<Keywords>
Keyword : Name, List<Article>
这意味着当我生成上下文时,它会创建一个新表KeywordArticle
。这里没什么奇怪的,现在我的问题是我有一个带有网格的版本页面,其中包含链接到文章的关键字,我可以编辑它以添加新的,删除一个等等。
为了解决这个问题,我目前有一个包含最终网格的ViewModel,并且我将它传递给我的控制器。
我的第一个想法就是将ViewModel替换为关键字实体的上下文实体关键字属性(entity.Keywords)。但是当联络人已经存在时会产生错误(逻辑,不能创建具有相同ID的新行)。
我的同事想要修复它是删除所有内容并每次重新添加实体,但它似乎非常沉重,可能不是最好的主意。像这样:
foreach (var keyword in existingArticle.Keywords)
{
existingArticle.Keywords.Remove(keyword);
}
existingArticle.Keywords = article.Keywords;
(其中article.Keywords是我的viewmodel属性,映射到新的关键字实体的集合,而现有的文章是从上下文中检索的实体)
我怎么能处理这个?有没有任何魔术方法,或者我应该遍历我的列表来检索已经存在的联络人,添加它们并删除其余的?这些方面的东西:
var newKeywordsList = new List<Keyword>();
foreach (var keyword in article.Keywords)
{
if (existingArticle.Keywords.Any(m => m.Id == keyword.Id))
{
newKeywordsList.Add(existingArticle.Keywords.First(m => m.Id == keyword.Id));
}
else
{
newKeywordsList.Add(keyword);
}
}
existingArticle.Keywords = newKeywordsList;
老实说,两种解决方案似乎都很糟糕,但我不知道如何正确处理它。也许通过重新处理所有内容,只列出要在列表中执行的操作列表。
答案 0 :(得分:1)
为了解决这个问题,我目前有一个包含最终网格的ViewModel,并且我将它传递给我的控制器。
糟糕的主意。仅将ViewModel传递给控制器,其中没有任何UI类(元素)。
没有任何魔术方法。做手动。
有3组变化。
新关键字。你可以找到它们:
var newKeywords = article.Keywords.Except(existingArticle.Keywords, new KeywordComparer()).ToList();
您必须在dbContext
中添加这些新实体&#34;可能修改&#34;关键字。你可以找到它们:
var possibleModified = article.Keywords.Intersect(existingArticle.Keywords, new KeywordComparer()).ToList();
需要检查这些实体是否有任何更新,如果是,则在dbContext中更新
已删除的关键字。你可以找到它们:
var deletedKeywords = existingArticle.Keywords.Except(article.Keywords, new KeywordComparer()).ToList();
必须从dbContext中删除这些实体。
<强> UPD 强>
感谢grek40对Equals
方法的建议。
对于Except
和Intersect
的正确工作,还需要Keyword
类的比较。简单的是:
class KeywordComparer : IEqualityComparer<Keyword>
{
/// <summary>
/// Determines whether the specified objects are equal.
/// </summary>
/// <returns>
/// true if the specified objects are equal; otherwise, false.
/// </returns>
/// <param name="x">The first object of type <paramref name="T"/> to compare.</param><param name="y">The second object of type <paramref name="T"/> to compare.</param>
public bool Equals(Keyword x, Keyword y)
{
return x != null && y != null && x.Id == y.Id;
}
/// <summary>
/// Returns a hash code for the specified object.
/// </summary>
/// <returns>
/// A hash code for the specified object.
/// </returns>
/// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param><exception cref="T:System.ArgumentNullException">The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.</exception>
public int GetHashCode(Keyword obj)
{
return obj.Id.GetHashCode();
}
}