【问题标题】:many-to-many relationship in mvc and EFmvc和EF中的多对多关系
【发布时间】:2015-04-20 21:05:00
【问题描述】:

我创建了一个博客站点,用户可以在其中 Post 一个博客,在我使用实体框架的模型和数据库中,PostsTags 之间存在多对多关系。

在我的数据库中,我也有 PostTagMap,但是我在我的 EF 模型中没有看到它。不确定我是否需要。 PostTagMap 只包含 Post 和 Tag 的唯一标识符。

(应该注意我是从模型创建的数据库)

在我的Create Post 视图(和控制器)上,我希望用户可以选择创建标签(连同那里的帖子),以确保它们彼此被识别。但是我找不到这样做的方法。

后模型:

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>

编辑:

我无法在Create 视图中使用EditorFor 字段来获取标签。这是因为Create 视图绑定到@Model MyBlogger.Post

标签只显示为一个集合,如果我说:

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

然后它在渲染时在我的视图中显示为空白。

我尝试了foreach,但没有奏效。例如在我的Create 视图中尝试此操作:

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

我收到错误:Object reference not set to an instance of an object.

【问题讨论】:

  • 这里有点难以理解你在问什么; EditorFor 在这种情况下没有任何意义;我怀疑你想要的是类似于 SO 的东西,你有一个输入标签的框,然后可以动态添加标签,如果它不存在,或者如果它已经存在则关联它;如果没有一些 JavaScript,你就无法真正做到这一点。
  • 是的,我正在寻找一个愚蠢的版本。我想要的只是一个文本框来为帖子添加标签。这不是一个问题,它更多的是 mvc 和实体框架的问题。多对多关系是不可能实现的。
  • 并非不可能实现,只是需要更多的分析思维。为什么不在表单中将文本框绑定到可以解析的字符串,然后在服务器端进行查找?
  • 基本上我认为这些答案中的大多数试图暗示的是您可能无法在客户端执行此操作,它需要在服务器端执行。
  • 是的,我在这里浪费了宝贵的时间,那些试图提供帮助的人也是如此:(随时添加答案。

标签: c# sql asp.net-mvc linq


【解决方案1】:

Many-to-Many 关系中,如果您使用DataAnnotation,EF 将创建多对多关系。在你的情况下

Post 类具有 Tag

的集合导航属性
public virtual ICollection<Tag> Tags { get; set; }

Tag 有一个 Post

的集合导航属性
 public virtual ICollection<Post> Posts { get; set; }

这将在 Post 和 Tag 之间创建多对多关系。


在你看来:

有几种方法可以添加/获取 Tag ID 的值,将其绑定到模型 Post 的一种方法是尝试以下方法,因为您已经在两个模型之间建立了关系:

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

model.Tags 返回一个标签的集合,如果你需要一个你需要明确指定的属性(例如Id、Name ...)

插入M对M关系:

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

【讨论】:

  • 是的,但是如何在我的创建后视图中实现?如何取回标签 ID?目前我无法访问模型 => m.Tag EditorFor 因为 Tag 只是 @Model MyBlogger.Post 视图中的一个集合
  • 我看到您的下拉菜单没有填充任何值。你也需要代码吗?
  • 不,标签需要用户自己创建。稍后我将为想要使用相同标签的其他用户提供一个下拉菜单。我有一个类别的下拉菜单,作为一对多的关系很好,但发布和标签是多对多的,我看不出有什么办法。我还将在后面的代码中处理为标签创建 url slug 和描述。但是我的 Create 视图无法将 EditorFor 用于标签....
  • 我的下拉菜单适用于类别...但这与标签不同。
  • 在创建视图中,您需要添加多少个标签?只有一个?
【解决方案2】:

EF 模型中不显示多对多表。要向其中添加行,您必须执行以下操作:PostObject1.Tags.Add(TagObject1) 或 TagObject1.Posts.Add(PostObject1)。

操作方法如下:Insert/Update Many to Many Entity Framework . How do I do it?

要选择行,您需要 EF 对象并访问其他表的列表。

【讨论】:

    【解决方案3】:

    关联(映射)表可能不会显示在 EF 模型中,但您可以轻松添加新标签

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

    作为一种好的做法,您应该创建视图模型,而不是直接将模型用于视图,

    这里是帮助您解决问题的链接Link

    对于标签,您可以使用 EditorTemplate(推荐)或 For 循环

    这是 for 循环示例

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

    对于新建

    只有Add New按钮和onclick,只是添加一个新的文本框,但将Id设置为Tags[i].Name,其中i是标签的Count()+1

    【讨论】:

    • 如何在视图中执行此操作? @Html.EditorFor(model => model.Tags) 渲染时不显示字段?我还希望用户在视图中设置名称,而不是硬编码。
    • 哦,我明白了,那是完全不同的动物,我建议添加标签视图模型,只包含您希望用户编辑/更改的属性。您可以为标签视图模型编写 EditorTemplate,跨度>
    • 如果我使用@foreach (var genre in Model.Tags) { @Html.EditorFor(model =&gt; genre.Name) },我如何在后面的代码中使用它来链接帖子?
    • 无法对集合应用索引,我的 foreach 方法也不起作用,没有设置为对象的实例
    • 请初始化Tags = new List();在您的帖子类的构造函数中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    • 2019-07-18
    • 1970-01-01
    • 2011-07-30
    • 1970-01-01
    • 2021-10-11
    相关资源
    最近更新 更多