简介:我正在创建一个使用ActiveRecord和ActiveRecord SQL Server适配器访问商业应用程序数据库的独立(非Rails)应用程序。我无法更改数据库架构或数据库服务器。我已尝试更改以下名称以保护罪名。
基本模型类:
class AppRecord < ActiveRecord::Base
after_initialize :parent_init
attr_reader :_downcase_field_values
attr_accessor :downcase_field_values
self.primary_key = 'IRN'
def parent_init
set_downcase_field_values
end
def set_downcase_field_values
@downcase_field_values ||= []
@_downcase_field_values = self.attributes.keys.select { |att| att if (att.match(/IRN/) || att == "Id") }
downcase_fields! self
end
def self.table_name
"app.#{self}"
end
def to_h
self.attributes.to_options
end
end
模型类:
class ReportIndex < AppRecord
after_find :init
has_many :ReportIndexParameters, class_name: "ReportIndexParameters", foreign_key: "ReportIndexIRN", dependent: :destroy
has_many :ReportProperties, class_name: "ReportProperties", foreign_key: "ReportIndexIRN", dependent: :destroy
has_many :ReportLayouts, class_name: "ReportLayouts", foreign_key: "ReportIndexIRN", dependent: :destroy
has_many :ReportIndexSeries, class_name: "ReportIndexSeries", foreign_key: "ReportIndexesIRN", dependent: :destroy
has_many :ReportUserDefinedViews, class_name: "ReportUserDefinedViews", foreign_key: "BaseClassID", primary_key: "ClassId"
def init
self.downcase_field_values = %w(BaseClassID)
end
end
class ReportProperties < AppRecord
belongs_to :ReportIndex
after_find :init
has_many :ReportPropertySeriesFilters, class_name: "ReportPropertySeriesFilters", foreign_key: "ReportPropertiesIRN", dependent: :destroy
has_many :ReportPropertyParameters, class_name: "ReportPropertyParameters", foreign_key: "ReportPropertiesIRN", dependent: :destroy
def init
self.downcase_field_values = %w(ClassID)
end
end
ActiveRecord查询:
pp ReportIndex.includes(:ReportProperties).find_by(ReportName: report_name)
错误:
/usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/association.rb:63:in `block in associated_records_by_owner': undefined method `association' for nil:NilClass (NoMethodError)
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/core.rb:367:in `init_with'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/persistence.rb:69:in `instantiate'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/querying.rb:50:in `block (2 levels) in find_by_sql'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/result.rb:55:in `block in each'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/result.rb:55:in `each'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/result.rb:55:in `each'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/querying.rb:50:in `map'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/querying.rb:50:in `block in find_by_sql'
from /usr/local/bundle/gems/activesupport-5.1.6/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/querying.rb:49:in `find_by_sql'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation.rb:678:in `exec_queries'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation.rb:546:in `load'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/association.rb:122:in `block in load_records'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/association.rb:121:in `each'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/association.rb:121:in `each_slice'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/association.rb:121:in `each'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/association.rb:121:in `flat_map'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/association.rb:121:in `load_records'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/association.rb:61:in `associated_records_by_owner'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/collection_association.rb:8:in `preload'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader/association.rb:19:in `run'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:151:in `block (2 levels) in preloaders_for_one'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:149:in `each'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:149:in `map'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:149:in `block in preloaders_for_one'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:148:in `each'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:148:in `flat_map'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:148:in `preloaders_for_one'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:115:in `preloaders_on'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:102:in `block in preload'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:101:in `each'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:101:in `flat_map'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/associations/preloader.rb:101:in `preload'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation.rb:686:in `block in exec_queries'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation.rb:684:in `each'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation.rb:684:in `exec_queries'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation.rb:546:in `load'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation.rb:255:in `records'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation/finder_methods.rb:508:in `find_take'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation/finder_methods.rb:100:in `take'
from /usr/local/bundle/gems/activerecord-5.1.6/lib/active_record/relation/finder_methods.rb:78:in `find_by'
from /src/artest.rb:13:in `<main>'
但是,ActiveRecord生成的SQL似乎是正确的:
D, [2018-06-27T17:42:49.256232 #1] DEBUG -- : SQL (33.3ms) USE [APP]
D, [2018-06-27T17:42:50.017505 #1] DEBUG -- : ReportIndex Load (40.5ms) EXEC sp_executesql N'SELECT [app].[ReportIndex].* FROM [app].[ReportIndex] WHERE [app].[ReportIndex].[ReportName] = @0 ORDER BY [app].[ReportIndex].[IRN] ASC OFFSET 0 ROWS FETCH NEXT @1 ROWS ONLY', N'@0 nvarchar(80), @1 int', @0 = N'Master Condemnation', @1 = 1 [["ReportName", nil], ["LIMIT", nil]]
D, [2018-06-27T17:42:51.043389 #1] DEBUG -- : ReportProperties Load (133.9ms) SELECT [app].[ReportProperties].* FROM [app].[ReportProperties] WHERE [app].[ReportProperties].[ReportIndexIRN] = '3cad6165-221e-4607-b5ad-01bc32f29157'
我怀疑这些违规行为是由于我在体系结构上设法弄错了一些原因。现有的模型代码可用于DELETE
和UPDATE
操作,但不适用于SELECT
。我欢迎蜂巢的头脑给我两美分。
答案 0 :(得分:0)
我学到的东西:
ActiveRecord::Base
子类化通常是一个坏主意,除非您真的知道自己在做什么,而我没有。在模型中的类之间共享代码的最佳方法是使用模块。子类化ActiveRecord::Base
可能会带来意想不到的副作用,除非我非常误解,否则无论如何它不会使您共享回调代码。ActiveRecord::ConnectionAdapters::SQLServerAdapter.lowercase_schema_reflection = true
ActiveRecord::Base.table_name_prefix = prefix
included
块中设置self.table_name来解决这两个问题。也许我做错了事,但是我无法使用这两个选项中的任何一个,并且实际上无法分辨所生成的SQL中的区别。结果,我仍然不得不处理CamelCase列名。uniqueidentifier
列不区分大小写。我正在编写此代码的应用程序的每个GUID均使用小写字母变体,因此给我的印象是我必须模仿这种行为,但是数据库确实
不在乎我花了很多时间试图使ActiveRecord
自动downcase
这些字段,并且我确实使它起作用,但是效果不佳。请参阅下一项。after_init
,after_find
等来更改主键的值,则会破坏关联。就我而言,我正在尝试
将主键从uniqueidentifier
数据类型更改为字符串
带有downcase
d个十六进制值的版本。这就是产生原始物的原因
导致我创建此帖子的错误。代码:
注意:需要ActiveSupport::Inflector
部分,以确保不需要复数的事物不会复数。有关更多信息,请参见ActiveSupport::Inflector
文档。
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.irregular 'index', 'index'
inflect.irregular 'layoutml', 'layoutml'
inflect.acronym 'ML'
end
module AppRecord
extend ActiveSupport::Concern
included do
self.primary_key = 'IRN'
self.table_name = "app.#{self.to_s.pluralize}"
end
def to_h
self.attributes.to_options
end
end
class ReportIndex < ActiveRecord::Base
include AppRecord
has_many :report_index_parameters, foreign_key: "ReportIndexIRN", dependent: :destroy
has_many :report_properties, foreign_key: "ReportIndexIRN", dependent: :destroy
has_many :report_layouts, foreign_key: "ReportIndexIRN", dependent: :destroy
has_many :report_index_series, foreign_key: "ReportIndexesIRN", dependent: :destroy
has_many :report_user_defined_views, foreign_key: "ClassId", primary_key: "BaseClassID"
has_many :report_index_param_series_filters, through: :report_index_series
has_many :report_property_series_filters, through: :report_index_series
has_many :report_layout_images, through: :report_layouts
has_many :report_layout_ml, through: :report_layouts
has_many :report_property_parameters, through: :report_properties
end
class ReportProperty < ActiveRecord::Base
include AppRecord
has_many :report_property_series_filters, foreign_key: "ReportPropertiesIRN", dependent: :destroy
has_many :report_property_parameters, foreign_key: "ReportPropertiesIRN", dependent: :destroy
end
未解决的问题:
ActiveRecord
猜测外键的方案?此应用程序中的外键不符合"#{class.to_s.underscore}_id"
约定,而是符合"#{class.to_s}IRN"
约定。如何干燥我的代码,并避免命名关联中的每个常规外键?dependent: :destroy
?再次,这将帮助我干燥代码。感谢到目前为止发表评论的所有人。