DataMapper-单表继承 [英] DataMapper - Single Table Inheritance

查看:72
本文介绍了DataMapper-单表继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请问有人可以告诉我这是怎么回事吗?

Could Some one please explain to me what is going on here?

这是一个示例,我整理起来展示了所有内容:

This is an example that I put together to show y'all whats up:

class Person
  include DataMapper::Resource
  property :id, Serial
  property :type, Discriminator
  property :name, String
  property :age, Integer
end

class Male < Person
end

class Father < Male
  property :job, String
end

class Son < Male
end

class Female < Person
end

class Mother < Female
  property :favorite_song, String
end

class Daughter < Female
end

DataMapper.auto_upgrade!

如果我拨打Person.all,我会得到:

If I call Person.all I get:

Person.all
=> [#<Son @id=1 @type=Son @name="Mike" @age=23 @status=nil>, 
#<Son @id=2 @type=Son @name="Carlos" @age=12 @status=nil>, 
#<Father @id=3 @type=Father @name="Robert" @age=55 @job=<not loaded>>, 
#<Mother @id=4 @type=Mother @name="Wanda" @age=47 @status=nil @favorite_song=<not loaded>>, 
#<Daughter @id=5 @type=Daughter @name="Meg" @age=16 @status=nil>]

如果我打电话给Person.get(3).type我会得到:

And if I call Person.get(3).type I get:

Person.get(3).type
=> Father

Male.all给我这个:

Male.all
=> [#<Son @id=1 @type=Son @name="Mike" @age=23 @status=nil>, 
#<Son @id=2 @type=Son @name="Carlos" @age=12 @status=nil>, 
#<Father @id=3 @type=Father @name="Robert" @age=55 @job=<not loaded>>]

然后Male.get(3).type给出了这一点:

Male.get(3).type
=> Father

但是Person.all(:type => Male)返回一个空数组:(?)

But Person.all(:type => Male) returns an empty array: (?)

Person.all(:type => Male)
=> []

但是,Person.all(:type => Son)返回所有Son类型的条目(=/)

However, Person.all(:type => Son) returns all of the Son type entries (=/)

Person.all(:type => Son)
=> [#<Son @id=1 @type=Son @name="Mike" @age=23 @status=nil>,
#<Son @id=2 @type=Son @name="Carlos" @age=12 @status=nil>]

如果我尝试做类似@person = People.all的操作,我会完全按照您的期望在@person中获得所有条目.但是我不能做类似@men = @person.all(:type => Male)的操作,我得到一个空数组.

If I try do do something like @person = People.all I get all entries in @person exactly as you would expect. but I cannot do something like @men = @person.all(:type => Male) I get an empty array.

@men = @people.all( :type => Male)
=> []

我会在Sinatra上使用它.我想要的是,例如,可以从数据库中以一克的价格抓住我所有的人员,并将其保存在@people中,但仍然能够对它们进行排序/过滤,以用于我的视图中的各种用途.我以前在协会上做过类似的事情,而且效果很好.但是我想尝试STI,因为它似乎是处理我的数据的一种更简洁的方法.

I would be using this with Sinatra. What I would like is to be able to for example grab all of my people in one gram from the DB and hold them in @people but still be able to sort/filter them for various uses in my views. I have done something similar with associations before and it worked rather well. But I would like to try STI because it seems to be a more concise way to deal with my data.

我也注意到,如果我做类似@women = Female.all的事情,我会得到所有的女人,但是如果我做类似@woman.each do |woman|的事情,我将无法访问视图中的包含属性(即woman.favorite_song返回什么都没有.)

I have noticed things as well that if I do something like @women = Female.all I get all of the woman, but if I do something like @woman.each do |woman| I am unable to access contain properties in my views (i.e. woman.favorite_song returns nothing).

我是否缺少有关其工作原理的信息?我完全不知道这里发生了什么,任何帮助将不胜感激.

Am I missing something about how this works? I do not understand what is going on here at all and any help would be appreciated.

推荐答案

如果您查看正在生成的SQL,它将为您提供正在运行的线索(如果您不知道,可以使用DataMapper::Logger.new(STDOUT, :debug)在调用DataMapper::setup之前 .

If you look at the SQL that's being generated it gives you a clue as to what's going on (if you don't know, you can do this with DataMapper::Logger.new(STDOUT, :debug) before your call to DataMapper::setup).

Person.all只需生成:

SELECT "id", "type", "name", "age" FROM "people" ORDER BY "id"

如您所愿.

Male.all生成:

SELECT "id", "type", "name", "age" FROM "people"
  WHERE "type" IN ('Male', 'Father', 'Son') ORDER BY "id"

Person.all(:type => Male)生成:

SELECT "id", "type", "name", "age" FROM "people"
  WHERE "type" = 'Male' ORDER BY "id"

因此,当您使用Male.all时,Datamapper知道会创建一个包含所有适当类的名称的SQL IN子句,但是当您使用Person.all(:type => Male)时,会使用 just 所指定的类型和没有一个子类.

So when you use Male.all Datamapper knows to create an SQL IN clause containing the names of all the appropriate classes, but when you use Person.all(:type => Male) uses just the type you specify and none of the subclasses.

当您查询集合而不是使用@people.all(:type => Male)的数据库时,必须进行类似的直接比较.

A similar direct comparison must be happening when you query a collection rather than the database with @people.all(:type => Male).

为了正确获取查询中某个类型的所有子类,可以使用

In order to correctly get all subclasses of a type in a query you can use the descendants method.

People.all(:type => Male.descendants)生成此SQL:

SELECT "id", "type", "name", "age" FROM "people"
  WHERE "type" IN ('Father', 'Son') ORDER BY "id"

在这种情况下,它将返回您想要的内容,但是请注意,IN子句不包含Male,它只是模型的后代,不包括所讨论的子树的父级.

In this case this will return what you want, but note that the IN clause doesn't contain Male, it's only the descendants of the model, not including the parent of the subtree in question.

要获得顶级"课程,您可以使用:

To get the 'top' class as well, you could use:

Person.all(:type => Male.descendants.dup << Male)

Male类添加到IN子句.请注意,需要dup,否则将得到 stack level too deep (SystemStackError).

to add the Male class to the IN clause. Note the dup is needed, otherwise you'll get stack level too deep (SystemStackError).

这也将按预期在集合上起作用:

This will also work on collections as expected:

@people.all(:type => Male.descendants.dup << Male)

将返回所有男性,而无需访问数据库(假设@people已经包含所有人员).

will return all males without hitting the database (assuming @people already contains all the people).

如果您决定使用descendants方法,请注意,尽管在文档中未将其标记为私有,但仍将其标记为 <<方法 Male.descendants.dup << Male 被标记为私有,因此该警告在此处更为适用.我从来源到判别器.

If you do decide to use the descendants method, note that although it isn't marked as private in the docs, it's marked @api semipublic in the source, so look out when upgrading Datamapper. The << method in Male.descendants.dup << Male is marked as private, so the warning applies even more here. I got this usage from the source to Discriminator.

关于无法获取某些属性的其他问题似乎与延迟加载有关,但是我无法弄清楚到底发生了什么.可能是一个错误.

Your other issue about not being able to get certain properties looks like it's something to do with lazy loading, but I can't work out exactly what's going on. It might be a bug.

当您用@women = Female.all加载所有女性时,生成的SQL是:

When you load all females with @women = Female.all the SQL generated is:

SELECT "id", "type", "name", "age" FROM "people"
  WHERE "type" IN ('Female', 'Mother', 'Daughter') ORDER BY "id"

因此仅获取所有成员拥有的属性.母亲的favorite_song会在您首次引用时获取.行:

so only attributes possessed by all members are fetched. The favorite_song of mothers is then fetched the first time you reference it. The lines:

puts women.first.inspect
puts women.first.favorite_song
puts women.first.inspect

给出(包括显示何时获取缺失值的SQL日志):

give (including the SQL log showing when the missing value is fetched):

#<Mother @id=4 @type=Mother @name="Wanda" @age=47 @favorite_song=<not loaded>>
 ~ (0.000069) SELECT "id", "type", "favorite_song" FROM "people" WHERE "id" = 4 ORDER BY "id"
Suspicious minds
#<Mother @id=4 @type=Mother @name="Wanda" @age=47 @favorite_song="Suspicious minds">

但是,当我在each块中执行类似操作时,获取缺失值的查询不会包含favorite_song,并且在模型中该值设置为nil:

However, when I do something similar in an each block, the query to fetch the missing value doesn't incude the favorite_song, and the value is set to nil in the model:

women.each do |w|
  next unless w.respond_to? :favorite_song
  puts w.inspect
  puts w.favorite_song
  puts w.inspect
end

给出输出(再次包括SQL):

gives the output (again including the SQL):

#<Mother @id=4 @type=Mother @name="Wanda" @age=47 @favorite_song=<not loaded>>
 ~ (0.000052) SELECT "id", "type" FROM "people" WHERE "type" IN ('Female', 'Mother', 'Daughter') ORDER BY "id"

#<Mother @id=4 @type=Mother @name="Wanda" @age=47 @favorite_song=nil>

我不知道我是否在这里缺少任何东西,或者这确实是一个错误.

I don't know if I'm missing something here, or if this is indeed a bug.

这篇关于DataMapper-单表继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆