Хорошо, я сделаю попытку.
MVC не сложно, но вы должны немного изменить свой образ мыслей.В MVC у вас есть Модели (ваш слой данных [s]), Представления и Контроллеры.
Прежде чем мы продолжим, я сделаю предположение с моими примерами ниже, что вы используете LINQ to SQL для доступа к данным.слой (модель), и я пометил его как dc
.
Контроллеры извлекают и форматируют данные из моделей и передают их в представления для отображения.Итак, давайте начнем с вашего первого представления, которое будет представлением для создания TimeSegment.
[HttpGet]
public ActionResult CreateTimeSegment() {
return View(new TimeSegmentView {
Consultants = dc.Consultants.ToList(),
Projects = dc.Projects.ToList(),
Tasks = dc.Tasks.ToList()
});
}
Это действие создаст объект TimeSegmentView
и передаст его View
как Model
.Имейте в виду, что это действие украшено [HttpGet]
.TimeSegmentView` - это контейнерный класс для объектов, которые необходимо передать в представление для создания пользовательского интерфейса, и он выглядит следующим образом:
public class TimeSegmentView {
public IList<Consultant> Consultants { get; set; }
public IList<Project> Projects { get; set; }
public IList<Task> Tasks { get; set; }
public TimeSegment TimeSegment { get; set; }
}
ПРИМЕЧАНИЕ: Я не использую TimeSegmentсвойство еще ниже, оно еще ниже ...
В представлении убедитесь, что оно наследуется от TimeSegmentView.Предполагая, что вы следуете структуре проекта MVC по умолчанию, и я позволю себе добавить папку Views
в папку Models
, ваша полная ссылка будет выглядеть следующим образом:
<%@ Page Inherits="System.Web.Mvc.ViewPage<PROJECTNAME.Models.Views.TimeSegmentView>" %>
Теперь вы 'Вы ввели представление для этого объекта, и теперь вы можете взаимодействовать с его свойствами.Таким образом, вы можете построить форму, такую как:
<form action="/" method="post">
<p>
<label>Hours</label>
<input name="TimeSegment.Hours" />
</p>
<p>
<label>Date</label>
<input name="TimeSegment.Date" />
</p>
<p>
<label>Consultant</label>
<select name="TimeSegment.ConsultantID">
<% foreach (Consultant C in Model.Consultants) { %>
<option value="<%=C.ConsultantID%>"><%=C.ConsultantName%></option>
<% }; %>
</select>
</p>
<p>
<label>Project</label>
<select name="TimeSegment.ProjectID">
<% foreach (Project P in Model.Projects) { %>
<option value="<%=P.ProjectID%>"><%=P.ProjectName%></option>
<% }; %>
</select>
</p>
<p>
<label>Task</label>
<select name="TimeSegment.TaskID">
<% foreach (Task T in Model.Tasks) { %>
<option value="<%=T.TaskID%>"><%=T.TaskName%></option>
<% }; %>
</select>
</p>
</form>
Как вы можете видеть, она создала 3 выбранных поля и только что выполнила циклы в каждом из них, чтобы построить свои значения на основе модели.
Теперь, принимая эту форму, нам нужно получить данные и добавить их в нашу базу данных с помощью:
[HttpPost]
public RedirectToRouteResult CreateTimeSegment(
[Bind(Prefix = "TimeSegment", Include = "Hours,Date,ConsultantID,ProjectID,TaskID")] TimeSegment TimeSegment) {
dc.TimeSegments.InsertOnSubmit(TimeSegment);
dc.SubmitChanges();
return RedirectToAction("EditTimeSegment", new {
TimeSegmentID = TimeSegment.TimeSegmentID
});
}
Хорошо, сначала обратите внимание, что я назвал действие тем же, но у этого есть [HttpPost]
украшение.Я говорю действию, что отправляю ему объект TimeSegment
и хочу, чтобы он связывал свойства в предложении Include (это в основном для безопасности и проверки).Затем я беру переданный объект TimeSegment
, добавляю его в контекст данных, отправляю изменения и перенаправляю.В этом случае я перенаправляю на другое действие для редактирования только что созданного объекта, передавая новый TimeSegmentID
.Вы можете перенаправить на что угодно, это мне показалось уместным ...
[HttpGet]
public ActionResult EditTimeSegment(
int TimeSegmentID) {
return View(new TimeSegmentView {
Consultants = dc.Consultants.ToList(),
Projects = dc.Projects.ToList(),
Tasks = dc.Tasks.ToList(),
TimeSegment = dc.TimeSegments.Single(t => t.TimeSegmentID == TimeSegmentID)
});
}
В действии редактирования вы делаете то же самое, что и в действии создания, создавая новый объект TimeSegmentView
и передавая егона вид.Ключевое отличие здесь заключается в том, что вы сейчас заполняете свойство TimeSegment
.Ваша форма будет выглядеть примерно так (сокращенно сверху):
<form action="/<%=Model.TimeSegment.TimeSegmentID%>" method="post">
<p>
<label>Hours</label>
<input name="TimeSegment.Hours" value="<%=Model.TimeSegment.Hours%>" />
</p>
</form>
И ваше действие получения на контроллере будет выглядеть так:
[HttpPost]
public RedirectToRouteResult EditTimeSegment(
int TimeSegmentID) {
TimeSegment TS = dc.TimeSegments.Single(t => t.TimeSegmentID == TimeSegmentID);
TryUpdateModel<TimeSegment>(TS, "TimeSegment", new string[5] {
"Hours", "Date", "ConsultantID", "ProjectID", "TaskID"
});
dc.SubmitChanges();
return RedirectToAction("EditTimeSegment", new {
TimeSegmentID = TimeSegment.TimeSegmentID
});
}
Наконец, если вы хотите отобразитьсписок временных сегментов, вы можете сделать что-то вроде этого:
[HttpGet]
public ActionResult ListTimeSegments() {
return View(new TimeSegmentsView {
TimeSegments = dc.TimeSegments.ToList()
});
}
и TimeSegmentsView
выглядит так:
public class TimeSegmentsView {
public IList<TimeSegment> TimeSegments { get; set; }
}
И в View
вы хотели бы сделать это:
<table>
<% foreach (TimeSegment TS in Model.TimeSegments) { %>
<tr>
<td><%=TS.Hours%></td>
<td><%=TS.Date%></td>
<td><%=TS.Project.ProjectName%></td>
<td><%=TS.Consultant.ConsultantName%></td>
<td><%=TS.Task.TaskName%></td>
</tr>
<% }; %>
</table>
Надеюсь, этого достаточно, чтобы дать вам старт.Это ни в коем случае не завершено, но сейчас 5 часов утра, и я еще не спал, так что это придется сделать сейчас (от меня).Не стесняйтесь называть свои действия тем, что вы хотите, вам не нужно придерживаться моих соглашений об именах.
Однако я бы посоветовал вам изменить наименование свойств ваших таблиц.Например, когда вы пишете выражения, как в таблице выше, вам нужно будет сделать TS.Project.ProjectName
, и это излишне.Вы уже получаете доступ к Project
свойству TS
через их отношения, так что вы знаете, что собираетесь работать только с Project
.Это тогда делает ProjectName
бессмысленным сгустком текста, заново описывающим объект, с которым вы работаете.Вместо этого просто используйте Name
и измените выражение на TS.Project.Name
.
В любом случае, просто предложение, делайте то, что вам больше нравится.Я теряю сознание, так что спокойной ночи и счастливого Дня Благодарения!
ОБНОВЛЕНИЕ
Процесс с коллекциями по сути такой же, как и со стороны контроллера.Сложнее запустить клиентскую часть и JavaScript, поэтому я предполагаю, что у вас уже есть что-то установленное.
Итак, вот как будет работать контроллер. Вы передаете массив TimeSegment, и механизм связывания достаточно умен, чтобы вычислить его через Префикс элементов формы.
<form action="/<%=Model.TimeSegment.TimeSegmentID%>" method="post">
<p>
<label>Hours</label>
<input name="TimeSegment[0].Hours" />
<!-- Notice the array in the prefix -->
</p>
<p>
<label>Hours</label>
<input name="TimeSegment[1].Hours" />
<!-- Notice the array in the prefix -->
</p>
</form>
и контроллер:
[HttpPost]
public RedirectToRouteResult CreateTimeSegments(
[Bind(Prefix = "TimeSegment", Include = "Hours,Date,ConsultantID,ProjectID,TaskID")] TimeSegment[] TimeSegments) {
dc.TimeSegments.InsertAllOnSubmit(TimeSegments);
dc.SubmitChanges();
return RedirectToAction("ListTimeSegments");
}
И это все. Конечно, вы захотите проверить или выполнить другие действия перед отправкой в базу данных, но это примерно все, что нужно.
ОБНОВЛЕНИЕ 2
Я полагаю, что вы можете сделать IList<TimeSegment>
вместо TimeSegment[]
без проблем, но, насколько это лучше, это для обсуждения. На мой взгляд, браузер по-прежнему отправляет на сервер массив virtual , поэтому действие, получающее массив, выглядит естественным, но вам решать, что вы хотите использовать.
Итак, общее действие списка будет выглядеть так:
[HttpPost]
public RedirectToRouteResult CreateTimeSegments(
[Bind(Prefix = "TimeSegment", Include = "Hours,Date,ConsultantID,ProjectID,TaskID")] IList<TimeSegment> TimeSegments) {
dc.TimeSegments.InsertAllOnSubmit(TimeSegments);
dc.SubmitChanges();
return RedirectToAction("ListTimeSegments");
}
Имейте в виду, что я раньше не использовал это (имеется в виду IList), поэтому я не могу гарантировать, что это сработает, просто размышляя ...
ОБНОВЛЕНИЕ 3
То, что вы хотите сделать с Consultant
, очень похоже на то, что я делаю с Cookies. У меня есть BaseView
класс, который является типом, используемым Site.Master, и тогда все другие представления расширяются от него. В BaseView
у меня есть свойство Cookie, которое всегда заполняется каждым действием контроллера. Затем я использую это свойство, чтобы получить идентификатор авторизованного пользователя.
Итак, в коде это выглядит так (на примерах из одного из моих приложений):
public class BaseView {
// Don't confuse with an HttpCookie, this is an object in my database...
public Cookie Cookie { get; set;}
}
public class EmployeeView : BaseView {
public Employee Employee { get; set; }
}
И с этим, скажем, я хочу добавить заметку сотруднику, моя форма будет выглядеть так, где я прохожу в скрытом поле, где ваше ConsultantID
входит в игру.
<form>
<input type="hidden" name="Note.AuthorId" value="<%=Model.Cookie.EmployeeId%>" />
<!-- other fields -->
</form>
Надеюсь, это поможет.