Jon*_*ein 7 sql database oop dbi perl6
我正在尝试为我的Perl 6预算应用程序设计一个"数据访问层".目标是让用户在SQLite数据库中存储各种购买,我的应用程序将生成各种报告,通知用户消费习惯.
但是,我在做一个"正确"的数据访问层时遇到了麻烦.事实上,我想知道这个应用程序是否值得.无论如何,我想学习如何正确地设计它"面向对象".
我理解我希望我的类成为表,并且类的属性对应于表中的行.就目前而言,我的代码根本不使用类属性,但仍然可以正常工作.
是否有任何理由使用类属性?我查了几个资源,其中大部分都是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 {}
Run Code Online (Sandbox Code Playgroud)
编辑:使用示例 -
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;
Run Code Online (Sandbox Code Playgroud)
输出:
({date => 2018-04-02 18:59:46, desc => A delicious apple, id => 1, name => Apple, price => 5.99, quant => 2})
但是,我在做一个"正确"的数据访问层时遇到了麻烦.事实上,我想知道这个应用程序是否值得.
这在很大程度上取决于您的应用程序,以及它触及数据库的位置.
我理解我希望我的类成为表,并且类的属性对应于表中的行.
这将是一个非常不寻常的映射.您希望该类表示该表,并且该类的每个实例(对象)都是一行.属性对应于表中的列.
然后你有一些封装数据库句柄的会话对象,然后你可以编写类似的东西
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);
Run Code Online (Sandbox Code Playgroud)
但是,适当的面向对象的数据层抽象并不止于此.你怎么查询表?你会如何在多个表上编写查询?SQLAlchemy(Python ORM)实现了一个转换为Perl 6的API,如下所示:
my $query = $session.query(Item).join(OtherClass).filter(Item.quantity > 10).filter(OtherClass.id <= 25);
for $query.all -> $item {
# do something with $item here
}
Run Code Online (Sandbox Code Playgroud)
我不知道Perl 6 ORM可以很好地支持这些事情,所以实现它可能需要做很多工作,而且可能不值得为一个小项目付出努力.
但是如果你想了解一个设计良好的动态语言对象关系映射器(ORM)的样子,我强烈推荐SQLAlchemy(Python)或DBIx :: Class(Perl 5).