【问题标题】:asp.net MVC 4, tagging places - best practice (eg Pub, Store, Restaurant)asp.net MVC 4,标记地点 - 最佳实践(例如酒吧、商店、餐厅)
【发布时间】:2013-05-20 16:05:18
【问题描述】:

ASP.NET MVC 4 Web 应用、EF 5、SQL Server 2012 Express、Visual Web Developer 2012 Express、代码优先

我有一个地点对象 - 我想为每个地点添加多个标签。

最好的方法是逗号分隔的字符串还是相关对象?

有任何设计模式或方法来管理整个事物(添加、查找、与地点关联等)?良好的性能也很重要。

标记由管理员完成,因此速度/易于实施以牺牲一点易用性为代价是可以接受的。

谢谢。

【问题讨论】:

    标签: c# asp.net-mvc entity-framework asp.net-mvc-4 asp.net-4.5


    【解决方案1】:

    首先,我认为你不需要一个对象来表示一个标签——假设标签只是一个字符串。

    您应该做的是向您的实体添加一个通用的字符串列表属性,如下所示:

    public IList<string> Tags { get; set; }
    

    Entity Framework 会处理得很好。

    关于UI部分,不要太在意,这几天一切都已经为你实现了, 使用 jQuery 标记它:http://aehlke.github.io/tag-it/

    更新

    因为 EntityFramework 很难处理字符串的映射列表,只需为它创建一个简单的类:

    public class Tag
    {
        public string Name { get; set; }
    }
    

    并使用

    public IList<Tag> Tags { get; set; }
    

    同样,如果不是因为 EF 的限制(或者如果您使用 nhibernate),我仍然建议映射到字符串列表以避免复杂性(假设速度不是关键)

    【讨论】:

    • +1 为 Tag-It。正是我需要的另一个项目。谢谢!
    • 谢谢 - 确认一下,应该是:public IList Tags { get;放; }?那应该直接进入 Place 对象吗?
    • 关于 Chris 提供的用于创建 Tag 类的内容,您可以使用可以使用专用类执行的字符串列表执行几乎所有操作,您可以选择所有具有不同和自动的位置的所有标签完成它们,检查相似的名称等。我并不是说你不应该选择 Tag 类,我只是认为它没有真正的价值(管理员编辑标签,所以选择了很多次不是什么大问题)
    • 好的,我已经添加了 public IList 标签 { get;放; } 到我的地方类 - 但它没有被添加到更新数据库 -verbose 上的数据库中。 (我添加了一个不同的字段作为有效的测试)。知道那里发生了什么吗?
    • 我认为这完全是题外话。你应该问一个单独的问题(当然是在谷歌搜索之后)。
    【解决方案2】:

    无论哪种方式,您都可以真正处理它;它只取决于你想要什么以及你想要完成什么。作为逗号分隔的字符串或IList&lt;string&gt;,它至少是可搜索的,但仅此而已。您也很难对标签进行任何形式的标准化(即不同的地方可能有“Chinese Buffet”、“chinese”、“chinese Buffet”、“chinese-buffet”等)。

    最可靠的方法是实际的Tag 实体与Place 具有M2M 关系。这样,您可以通过使名称成为唯一列并执行先发制人的重复数据删除查询(即输入:“中文”、“您的意思是'中文'吗?”等)来获得相当程度的规范化。

    拥有Tag 实体还可以让您轻松进行自动完成查询,因为您可以在一个地方查找所有标签或以某个字符开头的标签。用逗号分隔的字符串几乎不可能实现这一点,因为它需要首先聚合所有这些字符串(以及所有不同类型的对象),然后在最终返回列表之前解析出唯一标签。

    更新

    我不知道任何现有的 MVC 标签相关项目。 Google 应该能够提供帮助,或者只是在 Visual Studio 的 NuGet 包管理器中进行搜索。

    但是,这很容易自己推出。

    public class Tag
    {
        public int TagId { get; set; }
        public string Name { get; set; }
        // If your tags will be more freeform (and not necessarily URL compatible)
        public string Slug { get; set; }
    }
    
    public class Place
    {
        ...
        public virtual ICollection<Tag> Tags
    }
    

    这里唯一困难的部分是,为了让 EF 将关系识别为 M2M,关系的双方都需要有一个指向对方的导航属性。你有两个选择:

    1. 继续往两边添加导航属性。因此,在 Tag 中,您将添加以下行:

      public virtual ICollection<Place> Places
      

      这并没有什么“错误”,事实上,如果您希望能够轻松查找特定标签的位置,则可能需要这样做。但是,您仍然可以在没有导航属性的情况下获取该信息,即:

      db.Places.Where(m => m.Tags.Contains(someTag))
      
    2. 使用EntityTypeConfiguration 明确告诉 EF 这是一个 M2M。我通常遵循的模式是在我的实体中创建一个“映射”类:

      public class Place
      {
          ...
      
          public class PlaceMapping : EntityTypeConfiguration<Place>
          {
              public PlaceMapping()
              {
                  HasMany(m => m.Tags).WithMany();
              }
          }
      }
      

      然后,在您的 DbContext 中:

      public override void OnModelCreating(DbModelBuilder modelBuilder)
      {
          modelBuilder.Configurations.Add(new Place.PlaceMapping());
          // Any other configurations added here the same way
      }
      

      这只是我为了让事情井井有条而遵循的模式,你可以将 EntityTypeConfiguration 放在任何你喜欢的地方,只要你可以从 DbContext 中引用它。

    【讨论】:

    • 谢谢 - 你知道任何展示标签使用的示例项目吗? @AdamFridental
    • 建立 M2M 关系的最佳方法是什么?我从来没有在 MVC 中这样做过
    • 非常有帮助,谢谢 - 将它添加到双方是否会影响性能? (我猜不是延迟加载?)。 ICollection 比 List 更可取吗?
    • 没有性能损失。默认情况下 EF 延迟加载,因此如果您不使用它,则不会对其进行查询(尽管您可能会意外触发查询,使用 AutoMapper 等工具进行映射,因此如果您真的在查看您的查询,您应该确保告诉它忽略您不想使用的导航属性)。 ICollection 是 EF 用于与其他实体集合的关系。至少从 EF5 开始,您的导航属性不会返回任何结果,除非它们被键入为 ICollections。
    • 它说 'virtual' is not allowed in: public virtual ICollection Places; - 知道为什么吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    • 2011-04-25
    • 2017-06-01
    • 1970-01-01
    相关资源
    最近更新 更多