Issue with Entity Framework/db relations

2019-08-22 05:53发布

问题:

I have a class Article:

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

}

And Title:

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

Before you can write an Article, you have to choose your Title from a list, so your StringLength for Article.Text can be determined. Meaning, this article can only have a certain amount of chars, deppending on what 'Title' the writer has. Example: Title.Name "Title1" can only write an article with 1000 chars (MaxChar), and Title.Name "Title2" can write an article with 3000 chars. So. Thats means the the string length for Article.Text has to come from Title.MaxChar.

The Title entity is prefixed data that will be stored in the db.

Here's what ive done sone far: The titles from the db are listed in a view, with a link to create action of the ArticleController with a "title" querystring:

    @Models.Title

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

        }

You fill the form, and post it. The HttpPost Create action:

    [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);
    }

Here's the issue. The controller also adds a new Title entity. So the next time I navigate to the view where I have to choose Title, there's a duplicate of the last entity I used to write an article.

Should I do this in an entirly new way, or is there a small tweak. Only other thing I can think of, is just sending the MaxChar as a querystring, and have no relations between the models at all. Just seems a bit silly/webforms kindda.

Cheers

UPDATE #1: Maybe im doing this the wrong way? Get Create action

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

Or maybe its in the Model? Like, do I have to set foreign keys? Something like:

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

But im pretty sure I read some where that it isnt necesary, that EF takes care of that.

回答1:

Easiest way would probably be to attach the title to the context in your Create action:

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

Attach tells EF that article.Title already exists in the database, thereby avoiding that a new Title is inserted when you add the article to the context.



回答2:

You need to have a distinction between your MVC model and your Entities model. Your MVC Article model should look something like this (bear in mind there are some religious debates about what goes into a model):

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

In your view, you can create a dropdown based off the available titles, and bind it to the TitleID property. The list of available titles would be populated in the parameterless controller method (and the model-bound method as well).

When your model-bound method brings back the TitleID, instantiate the Title object from the Entities framework based off the ID. Create your Entities Article object using that Title object, and save your changes. This should get you where you want to be.