Сохранение сущностей с внешним ключом в ASP.NET MVC - PullRequest
2 голосов
/ 15 февраля 2011

Мне нужна помощь, чтобы сделать что-то, что я считаю простым.Я использую ASP.net MVC 3 с CodeFirst (CTP5)

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

public class Company
{    
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    public virtual ICollection<Location> Locations { get; set; }
}

public class Location
{
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public virtual Company Company { get; set; }

}

Теперь в моем контроллере я разрешаю создавать Местоположение только в контексте Компании, поэтому Идентификатор Компании всегда передается в (ВПредставьте, я показываю название компании в поле только для чтения, но не позволяю пользователю изменять / редактировать это.

    public ActionResult Create(int companyId)
    {
        Company company = _session.Single<Company>(c => c.Id == companyId);
        Location newLocation = new Location {Company = company};
        return View(newLocation);
    } 

    [HttpPost]
    public ActionResult Create(Location location)
    {
        if (ModelState.IsValid)
        {
            _session.Add<Location>(location);
            _session.CommitChanges();                
            return RedirectToAction("Index");
        } else {
            return View(location);
        }
    }

Теперь, когда я пытаюсь создать новое местоположение, ModelState.IsValidвсегда ложно из-за того, что location.Company.Name не указано и является обязательным полем для Company. Я никогда не пытаюсь создать новую компанию здесь, я просто пытаюсь создать местоположение со ссылкой на правильную компанию.Я не хочу добавлять свойство Name к представлению только для проверки ModelState. Как это можно сделать легко? Должен ли я передавать что-то отличное от представления? Или представлению?

Ответы [ 2 ]

2 голосов
/ 16 февраля 2011

Как я объяснял в своем комментарии, я наткнулся на небольшое изменение, которое делает эту работу, все еще думаю, что это клочок, так как я не понимаю, почему мне нужно дублировать параметр-идентификатор child Id, но самый лучший / самый простой, который я могобнаружите, что в будущем это будет легко обновить, и я буду первым, кто признает, что не знаю всего (или большинства) того, что есть в CodeFirst.

Я изменил класс местоположения с:

public class Location  
{      
    public int Id { get; set; }        

    [Required]      
    public string Name { get; set; }        

    [Required]      
    public virtual Company Company { get; set; }    
}

Кому:

public class Location  
{      
    public int Id { get; set; }        

    [Required]      
    public string Name { get; set; }        

    [Required]      
    public int CompanyId { get; set; }
    public virtual Company Company { get; set; }    
}

Теперь, насколько я могу судить, это вообще не изменило схему базы данных, но теперь единственное, что требуется для Location (при проверке), это то, чтов поле CompanyId указан идентификатор, свойство Company можно оставить пустым (раньше он пытался проверить правильность Company, поскольку требовался класс Company).

Итак, теперь при создании Location единственное, что необходимо передать представлению в CompanyId.

Кто-нибудь видит какие-либо недостатки?или лучше?

1 голос
/ 15 февраля 2011

Вы можете легко добавить скрытое поле с названием компании на form.Его данные будут собраны и отправлены вашему действию POST, как и ожидалось.

Если вы вообще не используете название компании на стороне сервера, вы можете заполнить это скрытое поле любым фиктивным текстом, еслиИдентификатор компании правильный (потому что вы его используете).Но если вам нужно правильное название компании с вашим идентификатором, вам нужно будет ввести фактическое имя в скрытое поле вместо какого-то фиктивного текста.

В любом случае.Это добавит скрытое поле для названия вашей компании

<%= Html.HiddenFor(m => m.Company.Name) %>

, и если у вас не установлено свойство вашей компании, тогда вы также можете использовать это:

<%= Html.Hidden("Company.Name", "Super duper company") %>

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

Обычная обратная передача или Ajax?

Я полагаю, вы используете обычную обратную передачу, а не обратную передачу Ajax.Если вы используете Ajax one и используете jQuery и вызываете $.post() или $.ajax() или что-то подобное, вы всегда можете предоставить любой объект, который вам нравится.Вы можете заполнить любое значение для названия компании в своем коде JavaScript.

Если у вас есть сложные объекты в JavaScript и вы хотите отправить их в действие вашего контроллера с параметрами строгого типа (чтобы они были проверены), вы можетеиспользуйте мой маленький плагин jQuery , который подготавливает любой объект JSON для правильной отправки в действие Asp.net MVC, чтобы данные автоматически связывались с вашими сильными типами для проверки.У JavaScript тоже есть даты.:)

Дополнительная информация

Поскольку вы указали (в комментарии), что ваши сущности очень много работают, и вы можете добавлять / удалять обязательные поля, это может быть очень утомительно длятакже измените все связанные представления.

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

  1. Имеют отдельные модели представления для процесса создания, которые также включают функции автоматического преобразования в класс модели приложения:

    public class LocationCreate
    {
        public int Id { get; set; }
    
        [Required]
        public string Name { get; set; }
    
        [Required]
        public int CompanyId { get; set; }
    
        public Location ToModelInstance()
        {
            return new Location {
                Id = this.Id,
                Name = this.Name,
                Company = new Company {
                    Id = this.CompanyId,
                    Name = "Super duper company Ltd." // you can as well omit this line
                }
            };
        }
    }
    
  2. Использование наследования:

    public class CompanyBase
    {
        public int Id { get; set; }
    }
    
    public class Company : CompanyBase
    {
        [Required]
        public string Name { get; set; }
    
        public virtual ICollection<Location> Locations { get; set; }
    }
    
    public class Location
    {
        public int Id { get; set; }
    
        [Required]
        public string Name { get; set; }
    
        [Required]
        public virtual CompanyBase Company { get; set; }
    
    }
    
...