【问题标题】:Data Access Layer with Perl 6 and DBIish使用 Perl 6 和 DBIish 的数据访问层
【发布时间】:2018-04-02 18:46:39
【问题描述】:

我正在尝试为我的 Perl 6 预算应用程序设计一个“数据访问层”。目标是让用户将各种购买存储在 SQLite 数据库中,我的应用程序将生成各种报告,告知用户消费习惯。

但是,我在做一个“正确的”数据访问层时遇到了麻烦。事实上,我想知道这个应用程序是否值得。无论如何,我想学习如何正确地设计它“面向对象”。

我知道我希望我的类是表,并且类的属性对应于表中的行。就目前而言,我的代码根本不使用类属性,但仍然可以正常工作。

有任何理由使用类属性吗?我有looked up a few resources,其中大部分是Java,我很难翻译到Perl 6。它看起来不必要地复杂,但我怀疑这是因为我不明白这种设计模式的原因。

  1 #!/usr/bin/env perl6
  2
  3 use v6;
  4 use DBIish;
  5
  6 constant DB = 'budgetpro.sqlite3';
  7 my $dbh = DBIish.connect('SQLite', database => DB);
  8
  9 $dbh.do('drop table if exists Essential');
 10
 11 sub create-schema {
 12     $dbh.do(qq:to/SCHEMA/);
 13         create table if not exists Essential(
 14             id      integer primary key not null,
 15             name    varchar not null,
 16             price   numeric(5,2) not null,
 17             quant   integer not null,
 18             desc    varchar not null,
 19             date    timestamp default (datetime('now'))
 20         );
 21     SCHEMA
 22 }
 23
 24 create-schema;
 25
 26 class Item {
 27     has $!table = 'Essential';
 28     has $.name is rw;
 29     has $.price is rw;
 30     has $.quant is rw;
 31     has Str $.desc;
 32
 33     method insert($name, $price, $quant, $desc) {
 34         my $sth = $dbh.prepare(qq:to/INSERT/);
 35             insert into $!table (name, price, quant, desc) values (?,?,?,?)
 36         INSERT
 37         $sth.execute($name, $price, $quant, $desc);
 38     }
 39
 40     multi method select-all {
 41         my $sth = $dbh.prepare(qq:to/SELECT/);
 42             select * from $!table
 43         SELECT
 44         $sth.execute;
 45         $sth.allrows(:array-of-hash);
 46     }
 47
 48     multi method select-all($begin, $end) {
 49         my $sth = $dbh.prepare(qq:to/SELECT/);
 50             select * from $!table where date >= ? and date <= ?
 51         SELECT
 52         $sth.execute($begin, $end);
 53         $sth.allrows(:array-of-hash);
 54     }
 55
 56
 57     # Needs accurate implementation
 58     multi method total-cost($table, $begin?, $end?) {
 59         sub total-price {
 60             my $sth = $dbh.prepare(qq:to/SUM/);
 61                 select sum(price) from $table
 62             SUM
 63             $sth.execute;
 64             $sth.allrows[0];
 65         }
 66         sub total-quant {
 67             my $sth = $dbh.prepare(qq:to/SUM/);
 68                 select sum(quant) from $table
 69             SUM
 70             $sth.execute;
 71             $sth.allrows[0];
 72         }
 73         return (total-quant[0] * total-price[0]);
 74     }
 75
 76     multi method total-cost($table, $begin, $end) {
 77         my $sth = $dbh.prepare(qq:to/SUM/);
 78             select sum(price) from $table where date >= ? and date <= ?
 79         SUM
 80         $sth.execute($begin, $end);
 81         $sth.allrows;
 82     }
 83 }
 84
 85 class Essential is Item {}
 86
 87 class Savings is Item {}
 88
 89 class Personal is Item {}

编辑:使用示例-

 my ($name, $price, $quant, $desc) = 'Apple', 0.99, 2, 'Delicious apple';
 my $item = Essential.new;
 $item.insert($name, $price, $quant, $desc);
 say $item.select-all;

输出: ({date =&gt; 2018-04-02 18:59:46, desc =&gt; A delicious apple, id =&gt; 1, name =&gt; Apple, price =&gt; 5.99, quant =&gt; 2})

【问题讨论】:

    标签: sql database oop dbi raku


    【解决方案1】:

    但是,我在做一个“正确的”数据访问层时遇到了麻烦。事实上,我想知道这个应用程序是否值得。

    这在很大程度上取决于您的应用程序,以及它有多少涉及数据库的位置。

    我知道我希望我的类是表,并且类的属性对应于表中的行。

    这将是一个非常不寻常的映射。您希望该类表示表,并且该类的每个实例(对象)将是一行。属性对应表中的列。

    然后你有某种封装数据库句柄的 session 对象,然后你可以写类似的东西

    my $item = Item.new(id => 42, name => 'something', price => 240.01, quant => 1, ...);
    # to add it to the database, do something like:
    $session.add($item);
    

    但是,正确的面向对象的数据层抽象并不止于此。你如何查询表?您将如何编写对多个表的查询? SQLAlchemy(一个 Python ORM)实现了一个 API,翻译成 Perl 6,看起来像这样:

    my $query = $session.query(Item).join(OtherClass).filter(Item.quantity > 10).filter(OtherClass.id <= 25);
    for $query.all -> $item {
        # do something with $item here
    }
    

    我不知道有一个 Perl 6 ORM 可以很好地支持这些东西,所以实现它可能需要做很多工作,而且对于一个小项目来说可能不值得。

    但是,如果您想了解为动态语言精心设计的对象关系映射器 (ORM) 的外观,我强烈推荐 SQLAlchemy (Python) 或 DBIx::Class (Perl 5)。

    【讨论】:

    • 那么,看来我设计的方式还不错,因为完成的应用程序可能很小,不到 1,000 行。我可以删除类属性并拥有对数据库进行操作的方法。
    【解决方案2】:

    您可以尝试Quicky,这是一个对象关系管理器,它仍然有点原始,但至少可以省去在代码中插入 SQL 语句的麻烦。最近同一位作者发了another ORM, koos,看起来更精致了。它肯定会加速数据库的开发。

    【讨论】:

      猜你喜欢
      • 2023-01-28
      • 1970-01-01
      • 2015-11-14
      • 2011-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-20
      相关资源
      最近更新 更多