Potrzebuję wskazówek dotyczących najlepszych praktyk.
Mam dwie tabele SQL, jedną o nazwie Osoba, którazawiera PersonId, PersonName i inną o nazwie Category, która zawiera CategoryId, CategoryName. Kategorie mogą być dość liczne i od czasu do czasu dodawane.
Chcę utworzyć widok, który pokazuje pole tekstowe PersonName, a następnie pojedyncze pole wyboru dla każdej kategorii w tabeli kategorii.
Użytkownik może wprowadzić nazwę i zaznaczyć tyle pól wyboru kategorii, ile chce, a następnie zapisać.
To poprawne podejście do wstawiania PersonNamew tabeli Person, a następnie wstaw wpis dla każdej kombinacji osoby / kategorii w nowej tabeli o nazwie PersonCategory, która zawiera pola PersonId i CategoryId?
Jeśli to zrobię, jak obsługiwać aktualizacje, jeśli kategorie zostaną zmienione w widoku edycji? To kategoria może być odznaczona przeciwko osobie. Czy rekord w PersonCategory wymaga usunięcia?
Odpowiedzi:
1 dla odpowiedzi № 1Tak to robię. Przejdę przez następujące.
- Wyświetl model
- Widok ASP.NET MVC (interfejs użytkownika)
- Metoda kontroli po akcji
- Algorytm do zapisania
Wyświetl model
public class PersonViewModel
{
public int Id { get; set; }
public string PersonName { get; set; }
// For rendering Checkboxes in the MVC View
public IList<SelectListItem> CategoryCheckboxes { get; set; }
// For data binding on Postback (HTTP POST).
// <input type="checkbox" /> will have the same `name` attribute as this.
public IList<int> AssociatedCategories { get; set; }
}
Widok ASP.NET MVC
<div>Name: <%= Html.EditorFor( m => m.PersonName ) %></div>
<fieldset>
<legend>Associatied Categories</legend>
<% foreach (SelectListItem c in Model.CategoryCheckboxes) { %>
<!-- "name" attribute is same as the C# View Model property name -->
<%= Html.CheckBox( "AssociatedCategories", c.Selected, new Dictionary<string, object> { { "value", c.Value } } ); %>
<%= Html.Encode( c.Text ) %><br />
<% } %>
</fieldset>
Metoda post akcji kontrolera
[HttpPost]
public ActionResult Edit(PersonViewModel viewModel)
{
Person p = personService.Update( viewModel ); // persist changes to DB
if (p == null) // person record doesn"t exist in DB
return RedirectToAction("NotFound");
return RedirectToAction("Edit", new { id = viewModel.Id });
}
Algorytm do zapisania
// this is in the `PersonService` class.
public void Update(PersonViewModel viewModel)
{
Person p = personRepository.GetByPrimaryKey( viewModel.Id );
if (p == null)
return null;
p.PersonName = viewModel.PersonName;
IList<int> existingAssociatedCategories = GetAssociatedCategories( p.PersonId );
foreach( int i in viewModel.AssociatedCategories )
{
if (!existingAssociatedCategories.Contains( i ))
Associate( p.PersonId, i ); // add NEW association in DB
}
foreach( int k in existingAssociatedCategories)
{
if (!viewModel.AssociatedCategories.Contains( k ))
DeleteAssociation( p.PersonId, k ); // delete existing association
}
repository.UpdatePerson( p ); // save changes to DB for Person object
return p;
}
Daj mi znać, jeśli masz jakieś pytanie.
3 dla odpowiedzi № 2
Zazwyczaj w przypadku czegoś takiego powstrzymałbym się od aktualizacji. Chciałbym usunąć wszystkie wpisy dla danej osoby z PersonCategory
, a następnie ponownie wstaw te, które są zapisywane PersonCategory
.
1 dla odpowiedzi nr 3
Odpowiedzi na twoje pytania brzmią: tak, dodaj / usuń je tam, gdzie dodano / usunięto, i tak.
Jest to relacja wiele do wielu, która jest reprezentowana relacyjnie za pomocą tabeli łączy.
1 dla odpowiedzi nr 4
Tak to robię. Przejdę przez następujące.
- Wyświetl model
- Widok ASP.NET MVC (interfejs użytkownika)
- Metoda kontroli po akcji
- Algorytm do zapisania
Wyświetl model
public class PersonViewModel
{
public int Id { get; set; }
public string PersonName { get; set; }
// For rendering Checkboxes in the MVC View
public IList<SelectListItem> CategoryCheckboxes { get; set; }
// For data binding on Postback (HTTP POST).
// <input type="checkbox" /> will have the same `name` attribute as this.
public IList<int> AssociatedCategories { get; set; }
}
Widok ASP.NET MVC
<div>Name: <%= Html.EditorFor( m => m.PersonName ) %></div>
<fieldset>
<legend>Associatied Categories</legend>
<% foreach (SelectListItem c in Model.CategoryCheckboxes) { %>
<!-- "name" attribute is same as the C# View Model property name -->
<%= Html.CheckBox( "AssociatedCategories", c.Selected, new Dictionary<string, object> { { "value", c.Value } } ); %>
<%= Html.Encode( c.Text ) %><br />
<% } %>
</fieldset>
Metoda post akcji kontrolera
[HttpPost]
public ActionResult Edit(PersonViewModel viewModel)
{
Person p = personService.Update( viewModel ); // persist changes to DB
if (p == null) // person record doesn"t exist in DB
return RedirectToAction("NotFound");
return RedirectToAction("Edit", new { id = viewModel.Id });
}
Algorytm do zapisania
// this is in the `PersonService` class.
public void Update(PersonViewModel viewModel)
{
Person p = personRepository.GetByPrimaryKey( viewModel.Id );
if (p == null)
return null;
p.PersonName = viewModel.PersonName;
IList<int> existingAssociatedCategories = GetAssociatedCategories( p.PersonId );
foreach( int i in viewModel.AssociatedCategories )
{
if (!existingAssociatedCategories.Contains( i ))
Associate( p.PersonId, i ); // add NEW association in DB
}
foreach( int k in existingAssociatedCategories)
{
if (!viewModel.AssociatedCategories.Contains( k ))
DeleteAssociation( p.PersonId, k ); // delete existing association
}
repository.UpdatePerson( p ); // save changes to DB for Person object
return p;
}
Daj mi znać, jeśli masz jakieś pytanie.
3 dla odpowiedzi № 5
Zazwyczaj w przypadku czegoś takiego powstrzymałbym się od aktualizacji. Chciałbym usunąć wszystkie wpisy dla danej osoby z PersonCategory
, a następnie ponownie wstaw te, które są zapisywane PersonCategory
.
1 dla odpowiedzi № 6
Odpowiedzi na twoje pytania brzmią: tak, dodaj / usuń je tam, gdzie dodano / usunięto, i tak.
Jest to relacja wiele do wielu, która jest reprezentowana relacyjnie za pomocą tabeli łączy.