我刚刚花了几个小时来解决这个问题,我希望将来能够简化它,因为我认为这是一个常见的要求。
我有一个带有导航属性的Question类,它是一个集合:
public class AnsweredQuestion : ModelBase
{
public virtual ICollection<Answer> Answers { get; set; }
}
我的所有模型都继承了一个基类:
public abstract class ModelBase
{
public int ID { get; set; }
}
现在我想从一个回答ID的集合中设置Answers集合,我在我的控制器中有这个方法 - 它确实有效
private void SetAnswers(AnsweredQuestion question,
IEnumerable<int> newAnswerIDs)
{
//First remove any answers we don't want
question.Answers.RemoveAll(a => !newAnswerIDs.Contains(a.ID));
//Then project the current ids
IEnumerable<int> currentAnswerIds = question.Answers.Select(a => a.ID);
//Now go to the database to get the answers that match the ids that
//we have to add
IQueryable<Answer> answersToAdd = _uow.AnswerRepository.All
.Where(dbAnswers => newAnswerIDs.Contains(dbAnswers.ID)
&&
!currentAnswerIds.Contains(dbAnswers.ID));
//and add them to the navigation property
question.Answers.AddRange(answersToAdd);
}
但是这段代码非常复杂,我可以看到我必须在每个具有导航属性的模型中反复编写它。
如果这是1对多的关系,我的实体中会有Answer属性和AnswerID属性,框架会为我解决问题。但是,据我所知,我不能为多对多关系做到这一点。
任何人都可以想到一种方法可以将其转换为可以在任何模型中的任何导航属性上调用的方法吗?我考虑过在模型集合上创建一个扩展方法,但我的绊脚石是我需要去数据库以获得与我将它们添加到Answers集合之前的ID匹配的答案,这将意味着我的扩展方法需要知道要使用哪个存储库
答案 0 :(得分:0)
以下是我的想法:
public static bool SetById<T>(this ICollection<T> collection,
IEnumerable<int> ids,
IRepository<T> repo)
where T : ModelBase
{
//First remove any answers we don't want
int count = collection.Count;
collection.RemoveAll(a => !ids.Contains(a.ID));
bool isAltered = count != collection.Count;
//Then project the current ids
IEnumerable<int> currentIds = collection.Select(a => a.ID);
IQueryable<T> toAdd = repo.All.Where(dbAnswers => ids.Contains(dbAnswers.ID) && !currentIds.Contains(dbAnswers.ID));
isAltered = isAltered || toAdd.Any();
//and add them to the navigation property
collection.AddRange(toAdd);
return isAltered;
}
这取决于我从具有ID的基类继承的所有实体:
public abstract class ModelBase
{
public int ID { get; set; }
}
在我的控制器中,我这样称呼它(传入我的存储库):
question.Answers.SetById(newAnswerIDs, _uow.AnswerRepository);