Проблема с отношениями Entity Framework / db

У меня есть статья класса:

    public class Article
{
    public int Id { get; set; }
    public string Text { get; set; }
    public Title Title { get; set; }

}

И название:

    public class Title
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int MaxChar { get; set; }   
}

Прежде чем вы сможете написать Article, вы должны выбрать свой Title из списка, чтобы можно было определить вашу StringLength для Article.Text. Это означает, что эта статья может иметь только определенное количество символов, в зависимости от того, какой «Заголовок» имеет писатель. Пример: Title.Name «Title1» может написать статью только с 1000 символов (MaxChar), а Title.Name «Title2» может написать статью с 3000 символов. Так. Это означает, что длина строки для Article.Text должна быть от Title.MaxChar.

Сущность Title - это данные с префиксом, которые будут храниться в базе данных.

Вот что я сделал раньше: заголовки из базы данных перечислены в представлении со ссылкой для создания действия ArticleController со строкой запроса «title»:

    @Models.Title

@foreach (var item in Model) {
         @Html.ActionLink(item.Name, "Create", "Article", new { title = item.Id}, new FormMethod())

        }

Вы заполняете форму и отправляете ее. Действие создания HttpPost:

    [HttpPost]
    public ActionResult Create(Article article)
    {
        if (article.Text.Length > article.Title.MaxChar)
        {
            ModelState.AddModelError("Text",
                                     string.Format("The text must be less than {0} chars bla bla", article.Title.MaxChar));
        }
        if (ModelState.IsValid)
            {
                db.Article.Add(article);
                db.SaveChanges();
                return RedirectToAction("Index");
            }


        return View(hb);
    }

Вот в чем проблема. Контроллер также добавляет новую сущность Title. Поэтому в следующий раз, когда я перейду к представлению, где мне нужно выбрать заголовок, будет копия последней сущности, которую я использовал для написания статьи.

Должен ли я сделать это совершенно по-новому, или есть небольшая поправка. Единственное, что я могу придумать, - это просто отправить MaxChar как строку запроса и вообще не иметь никаких отношений между моделями. Просто кажется немного глупым / webforms kindda.

Ваше здоровье

ОБНОВЛЕНИЕ №1: Может, я делаю это неправильно? Получить действие "Создать"

        public ActionResult Create(int title)
    {
        var model = new Article
        {
            Title = db.Title.Find(title)
        };
        return View(model);
    } 

Или, может быть, дело в Модели? Мол, нужно ли устанавливать внешние ключи? Что-то вроде:

        [ForeignKey("Title")]
    public int MaxChar { get; set; }
    public virtual Title Title { get; set; }

Но я почти уверен, что читал кое-где, что это не обязательно, что EF позаботится об этом.


person Kasper Skov    schedule 13.09.2011    source источник
comment
Похоже, что атрибут Id заголовка не является первичным ключом (или уникальным)?   -  person Rune    schedule 13.09.2011
comment
код @counsellorben сначала да   -  person Kasper Skov    schedule 13.09.2011
comment
Пожалуйста, опубликуйте Create представление. Вы включаете Title.Id в качестве скрытого поля в вашем представлении? В противном случае Title.Id не будет отправлен обратно в действие Create POST, что приведет к добавлению новой записи Title.   -  person counsellorben    schedule 14.09.2011
comment
@counsellorben Конечно, я это вижу. Но я должен включить Title.MaxChar, чтобы контролировать длину Article.Text. Но затем, как вы сказали, он создает дублирующую запись с Title.Id и Title.Name = null, как только я создаю статью.   -  person Kasper Skov    schedule 14.09.2011
comment
@counsellorben Я обновил вопрос с помощью некоторого кода. Я подозреваю, что причина в этом.   -  person Kasper Skov    schedule 14.09.2011


Ответы (2)


Самый простой способ - это прикрепить заголовок к контексту в вашем Create действии:

// ...
if (ModelState.IsValid)
{
    db.Titles.Attach(article.Title);
    db.Article.Add(article);
    db.SaveChanges();
    return RedirectToAction("Index");
}
// ...

Attach сообщает EF, что article.Title уже существует в базе данных, что позволяет избежать вставки нового Title при добавлении статьи в контекст.

person Slauma    schedule 14.09.2011

Вам необходимо различать вашу модель MVC и модель Entities. Ваша модель статьи MVC должна выглядеть примерно так (имейте в виду, что есть некоторые религиозные споры о том, что входит в модель):

public class Article
{
    public int Id { get; set; }
    public string Text { get; set; }
    public int TitleID { get; set; }
    public IEnumerable<Title> AvailableTitles {get;set;}
}

На ваш взгляд, вы можете создать раскрывающийся список на основе доступных заголовков и привязать его к свойству TitleID. Список доступных заголовков будет заполнен в методе контроллера без параметров (а также в методе, привязанном к модели).

Когда привязанный к модели метод возвращает TitleID, создайте экземпляр объекта Title из инфраструктуры Entities на основе идентификатора. Создайте объект Entities Article, используя этот объект Title, и сохраните изменения. Это должно привести вас туда, где вы хотите быть.

person Jeremy Holovacs    schedule 14.09.2011
comment
Элегантное решение. Сделаем это в будущем проекте. Но я не пойду с решением Slaumas, так как мне нужно добавить одну строку, чтобы все работало :) - person Kasper Skov; 15.09.2011