我是Ruby的新手,甚至更新的DataMapper,或任何ORM。我来自Perl背景,并不是真正的OOP类型的开发人员。所以我在这里徘徊在未知领域。为冗长的问题道歉...
在这个项目中,我有设备类和设备的概念,它们将被映射到设备类下。设备类需要能够拥有子设备类。公共根设备类名称(换句话说,所有设备类所来自的根)被称为" FOO"或" BAR" (在此示例代码中)并且每个都可以具有任意一组子设备类。最后,设备类最终包含设备。
所以: 设备类有许多设备类 设备类有许多设备 deviceclass有一个deviceclass_name 许多设备属于设备类
所以,IE:
FOO
JOHNSHOUSE
UPSTAIRS
device1
device2
DOWNSTAIRS
device1
device2
MANYHOUSES
JOE
GARAGE
device1
device2
SUZY
BEDROOM
device1
device2
device3
TIM
LIVINGROOM
device1
ARBITRARY
device1
SOMEPLACE
device1
device2
BAR
ENGLAND
LONDON
MYHOUSE
BEDROOM
device1
device2
device3
这就是我遇到的问题......设备和设备类必须能够自动添加到数据库中,并且以后会执行它们的关联。所以,我无法做到
deviceclass = MyDB::Deviceclass.new
device = MyDB::Device
deviceclass.device.new(blah)
我的模块,其中包含我基于这组问题的相关模型...
问题1 - 我这样做了吗?请注意Deviceclass下的self.validate_root_deviceclasses方法。我必须在DB之前拥有n
根设备类,所以这个方法创建它们。不幸的是,属性更新不起作用。我会喜欢这个方向。
module DeviceDB
ROOT_DEVICECLASSES %w{FOO BAR}
class Deviceclass
include DataMapper::Resource
property :id, Serial
property :hw_id, String, :unique => true
property :root_deviceclass, Boolean, :default => false
property :parent_deviceclass_id, Integer
property :deviceclass_name, String
property :updated_at, DateTime
property :created_at, DateTime
has n, :devices, :through => Resource
has n, :deviceclasses, :through => Resource
has 1, :deviceclass, self, {:through=>:deviceclasses, :via=>:parent_deviceclass_id}
def self.validate_root_deviceclasses
root_deviceclasses = all(:root_deviceclass => true)
if root_deviceclasses.count > 0
# get whats in the db now
db = Array.new(root_deviceclasses.map(&:deviceclass_name))
# match it against the global list (top of this file)
missing = ROOT_DEVICECLASSES.map{|root| root unless db.grep(/#{root}/i)[0]}.compact
# if something's missing, add it.
missing.each do |missing|
begin
create(:deviceclass_name => missing, :root_deviceclass => true).save
rescue DataMapper::SaveFailureError => e
@error = [e.resource.errors.map{|err| err}].join(', ')
return(false)
end
end
else
begin
ROOT_DEVICECLASSES.each do |root|
create(:deviceclass_name => root, :root_deviceclass => true).save
end
rescue DataMapper::SaveFailureError => e
@error = [e.resource.errors.map{|err| err}].join(', ')
return(false)
end
end
begin
default = first(:deviceclass_name => 'PTS').id
property :parent_deviceclass_id, Integer, :default => default # fail
DataMapper.finalize # fail
return(self)
rescue DataMapper::SaveFailureError => e
@error = [e.resource.errors.map{|err| err}].join(', ')
end
return(true)
end
end
class Device
include DataMapper::Resource
property :id, Serial
property :deviceclass_id, Integer
property :device_id, String, :unique => true
property :devicename, String
... more properties...
property :updated_at, DateTime
property :created_at, DateTime
belongs_to :deviceclass, :required => false
end
DataMapper.finalize
DataMapper.auto_upgrade!
Deviceclass.validate_root_deviceclasses
end
问题2:是否有一些神奇的方法来关联设备类和设备,还是我需要通过抓取设备的ID并通过更新将其关联到相关的设备类来实现它?
问题3:有没有办法在表已经迁移之后向模型添加属性,这将通过添加:default来有效地更改表(参见上面的失败案例)。如果没有,是否有任何方法可以在创建模型期间获取我的默认值。 Lambda浮现在脑海中,但只有在表已经存在并且已经添加了ROOT_DEVICENAMES时才能使用Lambda。
答案 0 :(得分:1)
关于架构和自主添加项目的第一个问题,您可以考虑将dm-is-tree
用于Deviceclass
,它会为您完成大量工作。以下是创建项目和“稍后”添加相关项目的示例。
require 'rubygems'
require 'data_mapper'
require 'dm-is-tree'
# setup
DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, 'sqlite::memory:')
# models
class Deviceclass
include DataMapper::Resource
property :id, Serial
property :hw_id, String, :unique => true
property :name, String
property :updated_at, DateTime
property :created_at, DateTime
is :tree, :order => :name
has n, :devices
end
class Device
include DataMapper::Resource
property :id, Serial
property :device_class_id, Integer
property :name, String
property :updated_at, DateTime
property :created_at, DateTime
belongs_to :deviceclass, :required => false
end
# go!
DataMapper.finalize
DataMapper.auto_upgrade!
# make the root deviceclass
parent = Deviceclass.create(:name => "Root")
# later on make a child
child = Deviceclass.create(:name => "Child")
# and add it to the parent
parent.children << child
# again later, create some devices
d1 = Device.create(:name => "D1")
d2 = Device.create(:name => "D2")
# add them
parent.devices << d1
child.devices << d2
# get stuffs
puts parent.children
puts child.root
puts parent.devices
puts child.devices
我不确定使用验证来生成缺少的设备类是个好主意。如果初始数据没有不断变化,我会在启动时运行种子脚本。您可以使用类似dm-sweatshop的内容来为数据库播种。
我想我需要关于#3的更多细节你想要一个Deviceclass的默认名称(你可以添加:default => 'foo'
),你可能已经知道,因为你已经使用:default
了! :)