`
wrymax
  • 浏览: 6401 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类

无模式数据表设计

阅读更多
    最近做项目,需要完成一种需求:用户可以为某种任意的model添加任何多个tag。一般来说常规的范式化设计在这种情况下使用一个字段一条记录来存储所有的tag,该记录中使用某种分隔符(如英文逗号,“|”等符号)来分隔各个tag,然后通过程序逻辑来解析tag。
    这种做法最容易被想到,但也最容易出问题。
    有几大问题是不可避免的:
    1. 使用逻辑处理数据不能使用数据库的完整性依赖;
    2. 不能保证用户输入永远合法;
    3. 由于用户输入长度不定,因此可保存的tag数目不定。
    因此,需要一种更加好的解决方案,该方案要对多种model具有兼容性,并且可以扩展任意多种类的tag。

    设计一张table tags:

tags = {
  :id => integer,
  :tag_name => string,
  :tag_type => integer
}

    该表用于保存各种tag的具体类型和名字,比如:
    tag_name => "北京", tag_type => 1
    tag_name => "移动互联网", tag_type => 2
    (在配置文件中写入locaiton = 1, market = 2)

    然后设计一张关联table entity_tags:
entity_tags = {
  :id => integer,
  :entity_type => string,
  :entity_id => integer,
  :tag_id => integer
}
set foreign_key :tag_id references tags.id

    这张表中,entity_type为使用tags的实体的类名,比如User;entity_id为实体的id;tag_id为外键,用于关联tags表。

    如此,每当某个实体添加一个tag,首先去tags表中找相关类型的tag是否存在,如果不存在,则新增一个tag,然后去entity_tags表中生成一条关联信息,比方说:
    tags(:id => 1, :tag_name => "北京", :tag_type => 1)
    entity_tags(:id => 1, :entity_type => 'User', :entity_id => 1, :tag_id => 1)
    entity_tags(:id => 2, :entity_type => 'Company', :entity_id => 1, :tag_id => 1)
    如此一来,User表中id为1的记录和Company表中id为1的记录都拥有了一个location tag“北京”(假设:tag_type => 1 表示location)
    并且,无论怎样添加,tags表中都将为每种tag生成一条唯一的记录,所有的实体和tag关联都保存在entity_tags中,非常易于增删改查。
分享到:
评论
1 楼 christina_zhang 2011-11-11  
 

相关推荐

Global site tag (gtag.js) - Google Analytics