Создание списков флажков с помощью MVC3 с использованием сложной модели представления и перекрестной таблицы с Linq to SQL - PullRequest
2 голосов
/ 18 января 2012

Я унаследовал свой первый проект MVC, и он включает использование MVC3 поверх Linq to SQL. Я пытался найти способ сгенерировать список флажков, основанный на отношении многих ко многим, включая перекрестную таблицу.

У меня есть таблица systemFailureType, которая сопоставляется с таблицей SystemFailureProblem через перекрестную таблицу.

Вот мой дизайнерский макет для таблиц:

Designer Layout А вот и мои модели:

     [MetadataType(typeof(SystemFailureProblemMetadata))]
    public partial class SystemFailureProblem
    {        
        private class SystemFailureProblemMetadata
        {
            public int ID { get; set; }

            [Required]
            [StringLength(200)]
            [DisplayName("Problem Description")]
            public String Description { get; set; }

            public IList<xSystemFailureProblemToType> FailureTypeCategories { get; set; }

        }        

}



[MetadataType(typeof(SystemFailureTypeMetaData))]
    public partial class SystemFailureType
    {
        private class SystemFailureTypeMetaData
        {
            public int ID { get; set; }

            [Required]
            [StringLength(200)]
            public String Description { get; set; }
        }
    }

Мой текущий код представления использует модель представления, которая содержит проблемный объект. Таким образом, текущий код, который у меня есть для генерации списка флажков, выглядит так:

 @for(int i=0;i < Model.problem.FailureTypeCategories.Count(); i++)
 {
       @Html.CheckBox("FailureTypeCategories["+i+"].ID", false)

 }

Моя основная проблема заключается в том, что я получаю некоторые ошибки при попытке создать список флажков, в котором говорится, что коллекция FailureTypeCategories не существует. Я подозреваю, что это может быть связано с тем, как я настроил модели в настоящее время. Мои первоначальные мысли склоняются к реализации модели для кросс-таблицы, хотя я не совсем уверен, как бы я это интегрировал. Есть ли другой способ, которым я должен идти об этом, или я на правильном пути и просто что-то упустил?

Edit:

Вот ViewModel

        public SystemFailureProblem problem { get; set; }

        public SystemFailureProblemViewModel() { }

        public SystemFailureProblemViewModel(SystemFailureProblem problem)
        {
            this.problem = problem;
        }

Метод контроллера очень прост. Он просто возвращает частичное представление формы.

 public ActionResult Edit(int id)
    {            
        try
        {
            return PartialView("Form", context.SystemFailureProblems.Single(p => p.ID == id));
        }
        catch (Exception ex)
        {
            ModelState.AddModelError("", ex.Message);
            return PartialView("Form", null);
        }
    }

1 Ответ

1 голос
/ 19 января 2012

Я придумал идею, основанную на этой статье , в которой используется Entity Framework, но его было не слишком сложно перевести на классы LinqToSql.

Сначала я настроил класс ViewModel,Вам нужно будет хранить там больше информации, кроме объекта SystemFailureProblem, например, информацию, относящуюся к коллекции SystemFailureType, назначенной для этой проблемы.

public class SystemFailureProblemTypeViewModel
{
    public int TypeID { get; set; }
    public string TypeDescription { get; set; }
    public bool Assigned { get; set; }
}

Далее я создал логику дляРедактировать действия (GET и POST).В методе GET вы узнаете, какие типы в настоящее время выбраны для проблемы (из таблицы xSystemFailureProblemToType), и создадите ViewModel, используя эти данные.Эта ViewModel передается в View вместе с объектом SystemFailureProblem.

public ActionResult Edit(int id)
    {
        SystemFailureProblem problem = (from p in context.SystemFailureProblems
                                        where p.ID == id
                                        select p).Single();

        PopulateSystemFailureProblemData(problem);

        return View(problem);
    }

    public void PopulateSystemFailureProblemData(SystemFailureProblem problem)
    {
        // get all failure types
        var allTypes = from t in context.SystemFailureTypes select t;

        // get al types joined with this problem using cross table
        var problemTypes = from x in context.xSystemFailureProblemToTypes
                           join t in context.SystemFailureTypes on x.SystemFailureTypeID equals t.ID
                           where x.SystemFailureProblemID == problem.ID
                           select t;

        // construct view model collection
        List<SystemFailureProblemTypeViewModel> viewModel = new List<SystemFailureProblemTypeViewModel>();
        foreach (var type in allTypes)
        {
            viewModel.Add(new SystemFailureProblemTypeViewModel
            {
                TypeID = type.ID,
                TypeDescription = type.Description,
                Assigned = problemTypes.Contains(type)
            });
        }

        ViewBag.Types = viewModel;
    }

В методе POST мы получаем параметр string [], который сообщает нам, какие флажки были отмечены.Это список SystemFailureType идентификаторов.Просмотрите все SystemFailureType в базе данных, определите, какие из них выбраны / не выбраны, и соответствующим образом обновите таблицу xSystemFailureProblemToType.

[HttpPost]
    public ActionResult Edit(int id, FormCollection collection, string[] selectedTypes)
    {
        SystemFailureProblem problem = (from p in context.SystemFailureProblems
                                        where p.ID == id
                                        select p).Single();

        // get all types joined with this problem using cross table
        var problemTypes = from x in context.xSystemFailureProblemToTypes
                           join t in context.SystemFailureTypes on x.SystemFailureTypeID equals t.ID
                           where x.SystemFailureProblemID == problem.ID
                           select t;

        problem.FailureTypes = problemTypes.ToList<SystemFailureType>();

        if (TryUpdateModel(problem, "", null, new string[] { "Types" }))
        {
            try
            {
                // loop through all types in the system
                foreach (var failureType in context.SystemFailureTypes)
                {
                    // determine if checkbox for current type was checked
                    if (selectedTypes.Contains(failureType.ID.ToString()))
                    {
                        // if no joining record exists (type not previously selected), create a joining record
                        if (!problemTypes.Contains(failureType))
                        {
                            context.xSystemFailureProblemToTypes.InsertOnSubmit(
                                new xSystemFailureProblemToType
                                {
                                    SystemFailureProblemID = problem.ID,
                                    SystemFailureTypeID = failureType.ID
                                });
                        }
                    }
                    else
                    {
                        // if type was unchecked but joining record exists, delete it
                        if (problemTypes.Contains(failureType))
                        {
                            xSystemFailureProblemToType toDelete = (from x in context.xSystemFailureProblemToTypes
                                                                    where x.SystemFailureProblemID == problem.ID &&
                                                                    x.SystemFailureTypeID == failureType.ID
                                                                    select x).SingleOrDefault();
                            context.xSystemFailureProblemToTypes.DeleteOnSubmit(toDelete);

                        }
                    }
                }
                context.SubmitChanges();
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        PopulateSystemFailureProblemData(problem);
        return View(problem);
    }

Наконец, я настроил View.Этот код создаст 3 столбца флажков, каждый из которых имеет значение SystemFailureType ID, которое он представляет.

<div class="editor-field">
        <table>
            <tr>
                @{
                    int cnt = 0;
                    List<SystemFailures.Data.SystemFailureProblemTypeViewModel> types = ViewBag.Types;

                    foreach (var type in types) {
                        if (cnt++ % 3 == 0) {
                            @:  </tr> <tr> 
                        }
                        @: <td> 
                            <input type="checkbox" 
                                   name="selectedTypes" 
                                   value="@type.TypeID" 
                                   @(Html.Raw(type.Assigned ? "checked=\"checked\"" : "")) /> 
                            @type.TypeDescription
                        @:</td>
                    }
                    @: </tr>
                }
        </table>
    </div>

Возможно, он не самый эффективный, но я думаю, что он эффективно решает самые сложные части вашей проблемы.Дайте мне знать, если я что-то пропустил!

...