简体   繁体   English

避免过多的控制流与MVC中的ID数组一起使用

[英]Avoiding excessive control flow working with Id arrays in MVC

Multi-select lists in MVC don't seem to bind to complex models. MVC中的多选列表似乎没有绑定到复杂的模型。 Instead, they return an array of selected Id numbers. 相反,它们返回选定ID号的数组。

I have such a control on a page, and I'm annoyed by the amount of conditional logic I've had to deploy to get it to work. 我在页面上有这样的控件,而让我不得不部署大量条件逻辑才能使我感到烦恼。 The objects in question are a Staff object who can have TeamMember membership of none or more teams. 有问题的对象是一个Staff对象,可以拥有一个或多个团队的TeamMember成员身份。

My objects are from entity framework. 我的对象来自实体框架。 I added this to the Staff object: 我将此添加到Staff对象:

public int[] SelectedTeamMembers
{
    get; set;
} 

I can now bind to this property in my View, and users can edit the multiselect list. 现在,我可以在视图中绑定到该属性,用户可以编辑多选列表。 On posting back the edit form, I have to do this (comments added for clarity): 在发回编辑表单时,我必须这样做(为清楚起见添加了注释):

//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);
        }
    }
}

I can tidy this up a bit by farming out each bit to a function, of course, but it still feels like a sledgehammer to crack a nut. 当然,我可以通过将一点点耕种到某个功能上来整理一下,但是仍然感觉像是敲碎坚果的大锤。

Is there a neater way of achieving this? 有没有更整洁的方法来实现这一目标?

You should evaluate the possibility of combining your for and foreach loops into a single loop as the first step of simplifying this code. 您应该评估将forforeach循环合并为一个循环的可能性,以此作为简化此代码的第一步。

Also, you know how to use LINQ (as evidenced by you initial Where() statement) so simplify the null conditional action as well, using LINQ and some of its helper extensions: 另外,您知道如何使用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);
    });

}

While this has not decreased the conditional complexity (as in all the conditionals are still there) the syntax is a lot more readable. 尽管这并没有降低条件的复杂性(因为所有条件仍然存在),但语法更具可读性。

You could do it this way...It relies on using the RemoveRange method. 您可以通过这种方式进行操作...它依赖于使用RemoveRange方法。

Entity - I'm using my own for demo purposes 实体-我将自己用于演示目的

public class User
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
    public String Name { get; set; }

}

Action 行动

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();
}

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM