3

I have created a blog site where users can Post a blog, in my model and database using Entity Framework there is a many-to-many relationship between Posts and Tags.

In my database I also have PostTagMap, however I don't see this in my EF Model. Not sure if I need to. The PostTagMap just contains the unique identifier for both Post and Tag nothing else.

(should be noted I created the database from the model)

On my Create Post View (and controller) I want the users to have the option to create tags (along with there post) making sure that they are identified with one another. However I cant find a way to do this.

Post Model:

public partial class Post
{
    public Post()
    {
        this.Tags = new HashSet<Tag>();
    }

    public int Id { get; set; }
    public string BlogUserEmail { get; set; }
    public int CategoryId { get; set; }
    public string Title { get; set; }
    public string ShortDescription { get; set; }

    [AllowHtml]
    public string Description { get; set; }
    public string Meta { get; set; }
    public string UrlSlug { get; set; }
    public bool Published { get; set; }
    public System.DateTime PostedOn { get; set; }
    public Nullable<System.DateTime> Modified { get; set; }

    public virtual BlogUser BlogUser { get; set; }
    public virtual Category Category { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
}


<h2>Create</h2>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Post</legend>

        <div class="editor-label">
            @Html.HiddenFor(model => model.BlogUserEmail, User.Identity.Name)
        </div>
        <div class="editor-field">
            @Html.ValidationMessageFor(model => model.BlogUserEmail)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.CategoryId, "Category")
        </div>
        <div class="editor-field">
            @Html.DropDownList("CategoryId", String.Empty)
            @Html.ValidationMessageFor(model => model.CategoryId)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ShortDescription)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ShortDescription)
            @Html.ValidationMessageFor(model => model.ShortDescription)
        </div>

        <div class="editor-label">
            @Html.TextAreaFor(model => model.Description)
        </div>
        <div class="editor-field">
            @Html.ValidationMessageFor(model => model.Description)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

Edit:

There is no way for me to use a EditorFor field in my Create View for tags. This is because the Create view is bound to @Model MyBlogger.Post.

Tags only show up as a collection and as such if I say:

@Html.EditorFor(model => m.Tags) 

Then it shows blank in my view when rendered.

I have tried a foreach however that did not work. For Instance trying this in my Create view:

@foreach (var item in Model.Tags)
{
    @Html.EditorFor(model => item.Name)
    @Html.EditorFor(model => item.Description)
    @Html.EditorFor(model => item.UrlSlug)
}

I get the error: Object reference not set to an instance of an object.

G Gr
  • 6,030
  • 20
  • 91
  • 184
  • it's a bit hard to understand what you are asking here; `EditorFor` doesn't really make sense in this context; I suspect what you are wanting is something similar to SO where you have a box to type tags in and then can dynamically add the tag if it doesn't exist or associate it if it already does; you can't really accomplish that without at least some JavaScript. – Claies Apr 21 '15 at 01:41
  • Yeah I am looking for a dumb-downed version of that. What I wanted was just one Text box to add a tag to a post. This isnt a issue its more of an issue with mvc and entity framework. Many to Many Relationships are impossible to implement. – G Gr Apr 21 '15 at 01:45
  • not impossible to implement, just require a bit more analytical thinking. Why not have a text box in your form bound to a string which you can parse and then do the lookup on the server side? – Claies Apr 21 '15 at 02:09
  • basically I think what most of these answers have tried to suggest is that you probably can't do this client side, it needs to be done server side. – Claies Apr 21 '15 at 02:10
  • Yeah I am wasting valuable time here, so are those trying to help :( Feel free to add an answer. – G Gr Apr 21 '15 at 02:13
  • I created a chat room where we can discuss what you are trying to do a bit more easily.... http://chat.stackoverflow.com/rooms/75764/entity-framework-relationships – Claies Apr 21 '15 at 02:16
  • @Garrith you need spend some time on basic tutorials man, i have updated my answer to gave you good direction to follow even though your question is not clear , so went through multiple iterations, what do I get A Vote down. I know you didn't get my answer even though it is right. – pjobs Apr 21 '15 at 04:10
  • Here is link to good explanation to your question http://stackoverflow.com/q/8570388/1748263 – pjobs Apr 21 '15 at 04:23
  • Actually here are the better and easy to understand tutorials , http://stackoverflow.com/questions/14822615/how-does-mvc-4-list-model-binding-work , http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ – pjobs Apr 21 '15 at 04:32

3 Answers3

0

Many to many tables are not displayed in the EF model. For adding rows to it you have to make something like: PostObject1.Tags.Add(TagObject1) or TagObject1.Posts.Add(PostObject1).

Here is how to do it: Insert/Update Many to Many Entity Framework . How do I do it?

For selecting rows you need the EF object and access to the list of the other table.

Community
  • 1
  • 1
joalcego
  • 1,098
  • 12
  • 17
0

In a Many-to-Many relationship if you are using DataAnnotation EF will create the Many-to-Many relationship. in your case

Post class has a collection navigation property for Tag

public virtual ICollection<Tag> Tags { get; set; }

And Tag has a collection navigation property for Post

 public virtual ICollection<Post> Posts { get; set; }

Which will create a Many-to-Many relationship between Post and Tag.


In your view:

There are couple of ways to add/get the value of the Tag ID , one way to bind it to the model Post is to try the following , since you already have a relationship between the two models:

      <div class="editor-field">
            @Html.EditorFor(model => model.Tags.Id)
            @Html.ValidationMessageFor(model => model.Tags.Id)
        </div>

model.Tags returns a collection of Tags if you need an attribute you need to specify it explicitly (such as Id, Name ...)

Insert in M-to-M relationship:

if (ModelState.IsValid)
        {
            Tag tag = new tag{id=post.Tags.Id};
            db.Tag.Attach(tag);
            db.Tag.Add(tag);
            db.Posts.Add(post);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
IndieTech Solutions
  • 2,527
  • 1
  • 21
  • 36
  • Yeah but how is that achievable in my Post Create View? How do I get the tag id back? At the moment I cant access the model => m.Tag EditorFor because Tag is only a collection in the @Model MyBlogger.Post View – G Gr Apr 21 '15 at 01:28
  • I see that your drop down menu is not populating any values . do you need code for that as well? – IndieTech Solutions Apr 21 '15 at 01:35
  • No, tags need to be created by the user. I will have a drop down menu later for other users who want to use the same tag. I have a drop down menu for Categories which was fine as a 1 to many relationship but Post and tag is many to many and I see no way of doing it. I was going to handle creating the url slug and description for the tag in the code behind aswell. But my Create view has no way of using EditorFor for tags.... – G Gr Apr 21 '15 at 01:38
  • My Dropdown works fine for categorys... but thats different from tags. – G Gr Apr 21 '15 at 01:38
  • In the create view , how many tags you will need to add? Just one? – IndieTech Solutions Apr 21 '15 at 01:54
  • More would be better but one would be a start, see my latest edit. – G Gr Apr 21 '15 at 01:56
  • Ok that's easy , i will edit my answer and that will give you a head start – IndieTech Solutions Apr 21 '15 at 01:56
  • Try it now. in order to get the Id you need to use model.Tags.Id – IndieTech Solutions Apr 21 '15 at 02:04
  • Error 2 The type arguments for method 'System.Web.Mvc.Html.EditorExtensions.EditorFor(System.Web.Mvc.HtmlHelper, System.Linq.Expressions.Expression>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. – G Gr Apr 21 '15 at 02:07
  • lemme create a fiddle very quickly, that will save us time – IndieTech Solutions Apr 21 '15 at 02:09
  • this was in my ide the red squiggly line. – G Gr Apr 21 '15 at 02:09
-1

Associated(Mapping) tables may not show up in the EF Model, but you can easily add new tag

post.Tags.add(new Tag(){ Name = ""});

As a good practice You should create View Models instead of using the Models directly for views,

here is the link to help you with that Link

For Tags you can either do EditorTemplate(Recommended) or For loop

Here is the for loop example

@for(var i=0;i<Model.Tags.Count();i++) { @Html.EditorFor(model => model.Tags[i].Name) }

For Create New

Just have Add New button, and onclick, just add a new text box, but set the Id to Tags[i].Name, where i is the Count()+1 of the tags.

pjobs
  • 1,247
  • 12
  • 14
  • How can I do this in the view tho? @Html.EditorFor(model => model.Tags) does not show a field when rendered? Also I wanted the name to be set by the user in the view not hardcoded. – G Gr Apr 20 '15 at 21:15
  • ooh I see, thats totally different animal, I would recommend to add Tag View Model with just the properties you want the user to edit/change.you can write a EditorTemplate for Tag View Model, – pjobs Apr 20 '15 at 21:17
  • if I use `@foreach (var genre in Model.Tags) { @Html.EditorFor(model => genre.Name) }` how do I use it in the code behind to link with post? – G Gr Apr 20 '15 at 21:29
  • cant apply indexing to a collection, also my foreach method did not work, wasnt set to an instance of an object – G Gr Apr 20 '15 at 21:34
  • Please initialize Tags = new List(); in a constructor in your post class – pjobs Apr 20 '15 at 21:38
  • If you would like to see a blank tag entry in your create form, then add one blank Tag to Post. – pjobs Apr 20 '15 at 21:43