避免在MVC中使用Id数组的过多控制流
本文关键字:数组 控制流 Id MVC | 更新日期: 2023-09-27 18:13:41
MVC中的多选择列表似乎不绑定到复杂的模型。相反,它们返回一个选定Id号的数组。
我在页面上有这样一个控件,我对必须部署的条件逻辑的数量感到恼火,以使其工作。所讨论的对象是一个Staff对象,它可以具有一个或多个团队的TeamMember成员资格。
我的对象来自实体框架。我将这个添加到Staff对象中:
public int[] SelectedTeamMembers
{
get; set;
}
我现在可以在我的视图中绑定这个属性,并且用户可以编辑多选列表。在发回编辑表单时,我必须这样做(为了清晰起见添加了注释):
//user.TeamMembers not bound, so get existing memberships
IEnumerable<TeamMember> existingTeamMembers = rep.TeamMembers_Get().Where(t => t.UserId == user.UserID);
//if array is empty, remove all team memberships & avoid null checks in else
if(user.SelectedTeamMembers == null)
{
foreach(TeamMember tm in existingTeamMembers)
{
rep.TeamMembers_Remove(tm);
}
}
else
{
// if team members have been deleted, delete them
foreach (TeamMember tm in existingTeamMembers)
{
if (!user.SelectedTeamMembers.Contains(tm.TeamId))
{
rep.TeamMembers_Remove(tm);
}
}
// if there are new team memberships, add them
foreach (int i in user.SelectedTeamMembers)
{
if (!existingTeamMembers.Select(t => t.TeamId).Contains(i))
{
TeamMember tm = new TeamMember { TeamId = i, UserId = user.UserID };
rep.TeamMembers_Change(tm);
}
}
}
当然,我可以通过将每个比特分配给一个函数来整理一下,但它仍然感觉像大锤敲开坚果。
是否有更简洁的方法来实现这一点?
作为简化代码的第一步,您应该评估将for
和foreach
循环合并为单个循环的可能性。
此外,您知道如何使用LINQ(正如您初始的Where()
语句所证明的那样),因此也可以使用LINQ和它的一些助手扩展来简化null
条件操作:
//user.TeamMembers not bound, so get existing memberships
IEnumerable<TeamMember> existingTeamMembers = rep.TeamMembers_Get().Where(t => t.UserId == user.UserID);
//if array is empty, remove all team memberships & avoid null checks in else
if(user.SelectedTeamMembers == null)
{
existingTeamMembers.ToList().ForEach(tm => rep.TeamMembers_Remove(tm));
}
else
{
// if team members have been deleted, delete them
existingTeamMembers.Where(tm => !user.SelectedTeamMembers.Contains(tm.TeamId)).ToList().ForEach(tm => rep.TeamMembers_Remove(tm));
// if there are new team memberships, add them
user.SelectedTeamMembers.Except(existingTeamMembers.Select(t=> t.TeamId)).ToList().ForEach(i =>
{
TeamMember tm = new TeamMember { TeamId = i, UserId = user.UserID };
rep.TeamMembers_Change(tm);
});
}
虽然这并没有降低条件的复杂性(因为所有的条件仍然存在),但语法的可读性大大提高了。
你可以这样做…它依赖于RemoveRange
方法。
实体-我使用我自己的演示目的
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public String Name { get; set; }
}
public ActionResult Action(Guid[] selectedTeamMembers)
{
using (var ctx = new DatabaseContext())
{
//
// Start by targeting all users!
//
var usersToRemove = ctx.Users.AsQueryable();
//
// if we have specified a selection then select the inverse.
//
if (selectedTeamMembers != null)
{
usersToRemove = usersToRemove.Where(x => !selectedTeamMembers.Contains(x.Id));
}
//
// Use the Set Generic as this gives us access to the Remove Range method
//
ctx.Set<User>().RemoveRange(usersToRemove);
ctx.SaveChanges();
}
return View();
}