【问题标题】:ORM library for automatically mapping foreign keys in Python or Ruby用于在 Python 或 Ruby 中自动映射外键的 ORM 库
【发布时间】:2009-12-13 19:32:06
【问题描述】:

我在工作中经常遇到的一项任务是针对预先存在的数据库编写脚本。有时我连接到 Oracle,有时它可能是 MySql 甚至是 sql server。

我想要一个工具,它可以对数据库的表和外键进行逆向工程,并允许我针对数据库编写 OO 风格的脚本。这实际上可以是任何语言,但首选 python 或 ruby​​。

例如 - 这是我理想的 ruby​​ 脚本:(假设 manager 和 employee 表已经存在外键)

DB = Database.connect(connect_string)
DB.managers.each do |manager|
  puts manager.name
  manager.employees.each do |employee|
    puts employee.name
  end
end

这种类型的库存在吗?如果是这样,那将节省我很多时间!

编辑 - 我想要的主要功能是它可以自动从数据库元数据中发现外键关联,而无需显式映射它们 - 我已经尝试过 ActiveRecord、SQLAlchemy、Sequel 和 DataMapper,据我所知,他们都做不到。

【问题讨论】:

    标签: python ruby database orm


    【解决方案1】:

    您应该看看SQLAlchemy 中的SQLSoup extension。它声称可以为您完成所有这些工作(包括外键)。我自己没有测试过。

    【讨论】:

    • 这是我想得到的最接近的结果——我仍然需要声明关系,但这很容易:db.managers.relate('employees', db.employees)跨度>
    【解决方案2】:

    严重的 Ruby ORM 不这样做是有原因的:它不灵活、不够明确并且太神奇了。

    如果您真的想要在您的项目中使用它,请尝试使用 Ruby 自己编写代码。以下是我在 ActiveRecord 上用 5 分钟完成的工作:

    require 'active_record'
    
    class ActiveRecord::Base
      def self.magic!
        connection.tables.map { |table|
          klass = Class.new(self)
          Object.send(:const_set, table.singularize.camelize, klass)
        }.each { |model|
          model.column_names.grep(/_id$/).each { |foreign_key|
            name = foreign_key.sub(/_id$/, '')
            model.belongs_to(name)
            name.camelize.constantize.has_many(model.name.tableize)
          }
        }
      end
    end
    

    让我们设置我们的数据库表并让magic! 分析它们:

    ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
    
    ActiveRecord::Schema.define do
      create_table "managers" do |t|
        t.string "name"
      end
      create_table "employees" do |t|
        t.string "name"
        t.belongs_to "manager"
      end
    end
    
    # it happens!
    ActiveRecord::Base.magic!
    

    创建一些测试记录并以您想要的方式使用它:

    mislav = Manager.create :name => "Mislav"
    mislav.employees.create(:name => "Josh")
    mislav.employees.create(:name => "Mike")
    
    Manager.all.each do |manager|
      puts manager.name
      manager.employees.each do |employee|
        puts employee.name
      end
    end
    

    Full code available on this Gist.

    这仅适用于 belongs_tohas_many 关联。如果您需要一个真正的库来执行此操作以及更多功能,请查看Dr Nic's Magic Models

    【讨论】:

    • 有趣。感谢您深思熟虑的回应。我同意将名称基于列命名约定是一个坏主意,但实际上我正在寻找一个可以分析数据库元数据中的外键以查找关联的库。查看 ruby​​ 数据库驱动程序,似乎它们中的大多数都没有保留任何有关外键的信息,这会使这变得非常困难。我知道大多数 JDBC 驱动程序都会存储这些信息,所以也许我可以使用 JRuby 来执行此操作。
    【解决方案3】:

    试用 SQLAlchemy 的 sqlautocode 模块。它将通过反映数据库来生成 ORM 类。

    【讨论】:

      【解决方案4】:

      在 Ruby 中,有几个 ORM,例如 ActiveRecordDataMapper 甚至 Sequel

      例如使用 ActiveRecord 你会这样做:

      ##################################
      #mysql conection
      ##################################
      begin
        ActiveRecord::Base.establish_connection(
          :adapter  => DBAdapter,
          :host     => DBHost,
          :username => DBUserName,
          :password => DBPass,
          :database => DBDatabase,
          :encoding=> DBEncoding,
          :socket=> DBSocket #drop this option for windows machines 
        )
      rescue Exception => ex
        fout.puts "Error connecting to mysql : #{ex}"
        puts "Migration was terminated due to connection error , check out the log file"
        break
      end
      
      ######################
      # Define models
      ######################
      
      class Employee < ActiveRecord::Base
       belongs_to :manager
      end 
      
      class Manager < ActiveRecord::Base
       has_many :employees
      end 
      

      【讨论】:

      • 这些库都需要你手动设置关联。
      猜你喜欢
      • 1970-01-01
      • 2012-11-23
      • 1970-01-01
      • 1970-01-01
      • 2015-01-10
      • 1970-01-01
      • 1970-01-01
      • 2011-03-13
      • 2012-09-14
      相关资源
      最近更新 更多