首页 > 其他分享 >A Simple Tutorial with Super Heroes

A Simple Tutorial with Super Heroes

时间:2024-02-18 12:33:47浏览次数:27  
标签:Hero name Power level Simple each new Heroes Super

2 A Simple Tutorial with Super Heroes

本章将循序渐进地介绍 Voyage(对象到文档映射器)提供的各种可能性。 我们将使用一个简单但并不简约的领域:超级英雄、技能及其装备。您将学习如何保存和检索对象。

2.1 创建连接

安装好 MongoBD 后,我们就可以开始连接数据库了,如下所示:

| repository |
repository := VOMongoRepository 
		host: 'localhost' 
		database: 'superHeroes'.
repository enableSingleton.

如果没有连接到数据库,可以使用内存存储库(用于应用程序原型开发)。

| repository |
repository := VOMemoryRepository new. 
repository enableSingleton

通过这个方法,你可以像连接真实的数据库一样工作,以后在开发过程中可以透明地切换模式。

通常,我们定义一个方法来建立资源库。例如,我们可以在稍后的 Hero 类中添加一个类方法。

Hero class >> setUpConnection
	| repository |
	repository := VOMongoRepository 
		host: 'localhost' 
		database: 'superHeroes'.
	repository enableSingleton.

2.2 SuperHeroes

现在,我们可以定义域的第一个版本。下图显示了我们将在本教程中使用的模型。

2.3 英雄

我们来定义Hero

Object subclass: #Hero
  instanceVariableNames: 'name level powers'
  classVariableNames: ''
  package: 'SuperHeroes'
Hero >> name
    ^ name
    
Hero >> name: aString
    name := aString
    
Hero >> level
    ^ level
    
Hero >> level: anObject
    level := anObject
    
Hero >> powers
    ^ powers ifNil: [ powers := Set new ]
    
Hero >> addPower: aPower
    self powers add: aPower

2.4 技能

我们来定义Power

Object subclass: #Power
  instanceVariableNames: 'name'
  classVairableNames: ''
  package: 'SuperHeroes'
Power >> name
    ^ name
    
Power >> name: aString
    name := aString

添加printOn:,以改进超级英雄的导航和调试的方法。

2.5 根类

现在,我们必须决定要保存和查询的对象是什么。为此,我们应声明要保存的对象图的根。根可以是系统中的任何类。声明根的方法是在我们所要保存的对象的类侧实现类方法 isVoyageRoot。我们稍后会看到定义根的意义。现在,我们只需将 Hero 定义为根。

Hero class >> isVoyageRoot 
   ^ true

我们就可以创建一些超级英雄,然后把他们保存在数据库中。

Hero new
   name: 'Spiderman';
   level: #epic;
   addPower: (Power new name: 'Super-strength');
   addPower: (Power new name: 'Wall-climbing');
   addPower: (Power new name: 'Spider instinct');
   save.
Hero new
   name: 'Wolverine';
   level: #epic;
   addPower: (Power new name: 'Regeneration');
   addPower: (Power new name: 'Adamantium claws');
   save.

2.6 检查MongoDB

我们可以直接在数据库中查看对象的保存情况。

> show dbs
local        0.078GB
superHeroes  0.078GB

> use superHeroes
switched to db superHeroes

> show collections
Hero

现在我们可以看到超级英雄实际上是如何存储的。db.Hero.find()[0] 获取集合中的第一个对象。

> db.Hero.find()[0]
{
	"_id" : ObjectId("d847065c56d0ad09b4000001"),
	"#version" : 688076276,
	"#instanceOf" : "Hero",
	"level" : "epic",
	"name" : "Spiderman",
	"powers" : [
		{
			"#instanceOf" : "Power",
			"name" : "Spider instinct"
		},
		{
			"#instanceOf" : "Power",
			"name" : "Super-strength"
		},
		{
			"#instanceOf" : "Power",
			"name" : "Wall-climbing"
		}
	]
}

请注意技能的保存方式:它们被嵌入到代表超级英雄的文档中。

2.7 查询

回到Pharo中,我们可以执行一些查询,以获取存储在数据库中的对象。

Hero selectAll.
> an OrderedCollection(a Hero( Spiderman ) a Hero( Wolverine ))

Hero selectOne: [ :each | each name = 'Spiderman' ].
> a Hero( Spiderman )

Hero selectMany: [ :each | each level = #epic ].
> an OrderedCollection(a Hero( Spiderman ) a Hero( Wolverine ))

由于 MongoDB 内部存储的是 JSON,因此查询的参数可以是一个字典,如下所示:

Hero selectOne: { #name -> 'Spiderman' } asDictionary.
> a Hero( Spiderman ) 

Hero selectMany: { #level -> #epic } asDictionary.
> an OrderedCollection(a Hero( Spiderman ) a Hero( Wolverine )

下面是一个更复杂的查询:

Hero
	selectMany: { #level -> #epic } asDictionary 
	sortBy: { #name -> VOOrder ascending } asDictionary
	limit: 10
	offset: 0

2.8 其他基本操作

计数

Hero count.
> 2

Hero count: [ :each | each name = 'Spiderman' ]
> 1

删除

hero := Hero selectAll anyOne.
hero remove.
> a Hero

从类中删除所有对象。

Hero removeAll.
> Hero class

2.9 添加一个新的根

现在,我们将改变需求,表明我们希望能够查询另一类对象:技能。请注意,在添加根对象时,必须刷新数据库或执行迁移,例如加载旧对象并重新发布它们。

每次更改数据库 "模式 "时,都应使用以下表达式重置数据库:

VORepository current reset.

什么时候需要添加新的根类

在面对是否有必要添加一个类作为根的问题时,有两个要点需要考虑。

  • 首先,一个显而易见的考虑因素是,我们是否需要将查询对象与引用对象分开。

  • 其次,如果需要确保共享子部分而不重复,则应将子部分声明为根。例如,如果您需要在两个超级英雄之间共享一种能力,并希望确保在加载两个超级英雄时不会获得相同技能的两个副本。

2.10 Power作为根

Power class >> isVoyageRoot
    ^ true

现在,我们可以单独保存技能对象,如下所示:

Power new name: 'Fly'; save.
Power new name: 'Super-strength'; save.

如果使用 show collections 功能在数据库中看不到新的对象,可能是遇到了 Voyage 的 BUG,需要在 Pharo 图像中重置内存数据库缓存:

VORepository current reset.

现在保存对象并再次检查 mongo 数据库,应该会显示

> show collections
	Hero
	Power

现在我们可以保存英雄及其技能。为了进行全面的测试,我们将执行 Hero removeAll 来清除数据库中的英雄,并执行以下操作:

| fly superStrength |
fly := Power selectOne: [ :each | each name = 'Fly']. 
superStrength := Power selectOne: [ :each | each name = 'Super-strength'].
Hero new
	name: 'Superman'; level: #epic;
	addPower: fly; 
	addPower: superStrength; 
	save.

请注意,虽然我们保存的技能与英雄无关,但这并不是必须的,因为保存英雄会自动保存其技能。

现在,当我们查询数据库时,我们可以看到一个英雄引用了另一个技能集合,而这些技能并没有嵌套在英雄对象中。

2.11 关系

Voyage支持根对象之间的循环引用,但不支持对嵌入对象的循环引用。我们将在下一节中看到这一点。

2.12 扩展Hero

现在,我们将用装备来扩展 Hero 类。这个示例表明,根集合声明是静态的:当一个超类被定义为根集合时,mongo db 中的集合将包含该类及其子类的实例。如果我们想让每个子类都有一个集合,就必须将每个子类都定义为根集合,并在每个类中复制 isVoyageRoot 方法。

我们为 Hero 类添加一个名为 equipment 的新实例变量。

Object subclass: #Hero
   instanceVariableNames: 'name level powers equipment' 
   classVariableNames: ''
   package: 'SuperHeroes'
Hero >> equipment
   ^ equipment ifNil: [ equipment := Set new ]
   
Hero >> addEquipment: anEquipment 
   self equipment add: anEquipment

由于我们更改了类的结构,因此我们应该执行VORepository current reset来重置数据库的本地缓存。

现在,我们把Equipment定义为新的根类。

Object subclass: #Equipment
    instanceVariableNames: ''
    classVariableNames: ''
    package: 'SuperHeroes'
Equipment class >> isVoyageRoot
    ^ true

然后我们定义两个子类WeaponArmor

Equipment subclass: #Weapon
	instanceVariableNames: ''
	classVariableNames: ''
	category: 'SuperHeroes'
Equipment subclass: #Armor
	instanceVariableNames: ''
	classVariableNames: ''
	category: 'SuperHeroes'

现在,保存一个携带装备的英雄时,也会把装备作为单独的对象进行保存

Hero new
    name: 'Iron-Man';
    level: #epic;
    addEquipment: Armor new;
    save.

我们可以看到对象是如何保存在数据库中的:

> db.Hero.find()[1]
{
	"_id" : ObjectId("d8475734421aa909b4000001"),
	"#instanceOf" : "Hero",
	"#version" : NumberLong("2898020230"),
	"equipment" : [
		{
			"#instanceOf" : "Armor"
		}
	],
	"level" : "epic",
	"name" : "Iron-Man",
	"powers" : null
}

因为我们没有将WeaponArmor定义成单独的根,所以数据库中只有一个名为Equipment的集合,其中既包含武器又包含盔甲。

2.13 装备也可以拥有技能

事实上,装备也可以有技能(就像雷神之锤)。因此,我们为设备增加了以下技能:

Object subclass: #Equipment
    instanceVariableNames: 'powers'
    classVariableNames: ''
    package: 'SuperPowers'
Equipment >> powers
    ^ powers ifNil: [ powers := Set new ]
    
Equipment >> addPower: aPower
    self powers add: aPower

由于我们改变了类的结构,我们应该重置数据库的本地缓存:

VORepository current reset

现在,我们可以为铁人添加一个具有技能的装备,如下所示:

| hero fly superStrength |
hero := Hero selectOne: [ :each | each name = 'Iron-Man' ].
fly := Power selectOne: [ :each | each name = 'Fly' ].
superStrength := Power selectOne: [ :each | each name = 'Super-strength' ].
hero addEquipment: (Armor new
        addPower: fly;
        addPower: superStrength;
        yourself);
save.

我们在数据库中看到,"装备 "集合包含 "盔甲 "对象。

> db.Equipment.find()[0]
{
	"_id" : ObjectId("d8475777421aa909b4000003"),
	"#instanceOf" : "Armor",
	"#version" : NumberLong("4204064627")
}

请注意,一个装备可以包含另一个装备。由于 Equipment类是一个集合根,因此我们没有任何东西来处理循环引用。

2.14 总结

这个小教程展示了在 Mongo 数据库中存储对象是多么容易。它补充了各种可能的解决方案,如使用 Fuel 序列化对象、使用内存 SandStone 方法或使用 Garage 进行更传统的关系数据库映射。

标签:Hero,name,Power,level,Simple,each,new,Heroes,Super
From: https://www.cnblogs.com/zh-geek/p/18019081

相关文章

  • 糟糕,被SimpleDateFormat坑到啦!| 京东云技术团队
    1.问题背景问题的背景是这样的,在最近需求开发中遇到需要将给定目标数据通过某一固定的计量规则进行过滤并打标生成明细数据,其中发现存在一笔目标数据的时间在不符合现有日期规则的条件下,还是通过了规则引擎的匹配打标操作。故而需要对该错误匹配场景进行排查,定位其根本原因所在......
  • Ubuntu服务器使用 Daphne + Nginx + supervisor部署Django项目
    视频:https://www.bilibili.com/video/BV1e6421G7uM/?vd_source=36191bed2c30378060ff2efe6831b331Django从3.0版开始加入对ASGI的支持,使Django开始具有异步功能。截止目前的5.0版,对异步支持逐步也越来越好,相信在未来的版本中异步将会支持的更加完善。所以说,我们也需要适时的......
  • JAVA中this和super
    thisthis表示使用的对象本身,可以调用对象的属性和对象的方法以及对象的构造方法(this.x和this.(),其中this.()只能在构造方法的第一行调用且不能和super.()共同使用)使用原因避免属性和方法变量名相同时出现就近原则的冲突使用细节supersuper代表父类的引用,用于访问父类......
  • [Go] A simple Go server
    HelloWorldLet'screateasimpleGoserver,firstlet'ssetuptheserveranddohelloworld//@filename:main.gopackagemainimport( "fmt" "net/http")funchandleHello(reshttp.ResponseWriter,req*http.Request){......
  • P10125 「Daily OI Round 3」Simple题解
    原题传送门题目概述:给我们一个字符串,不区分大小写,让我们判断此字符串是与Acoipp等价,还是与Svpoll等价,或者是与前两者都不等价,并按题目条件输出。思路分析:我们只需要把此字符串的第一个字符转成大写,其他字符转成小写,并与那两个字符串进行比较就行了代码:#include<bits/st......
  • P10125 「Daily OI Round 3」Simple 题解
    题目传送门简单模拟,主要考察字符串。首先输入一个char类型的数组,然后直接遍历每一位是否为Acoipp或Svpoll即可。//Simple//codeby:cq_irritater//time:2024/02/04#include<bits/stdc++.h>usingnamespacestd;chara[10];intmain(){//freopen("c......
  • Luogu「Daily OI Round 3」Simple 题解
    #include<iostream>#include<cstdio>#include<queue>#include<algorithm>#include<cstring>#include<string>#include<string.h>#include<vector>#defineintlonglong#definerep(a,b,c)for(autoa=b;a......
  • H3C交换机配置超级用户(super user)
    H3C交换机配置超级用户(superuser)一个超级用户,以便在登录后使用su命令切换到超级用户权限。在H3C交换机上,这通常涉及到配置特权级别和用户模式。下面是一个简单的步骤:登录到交换机:使用终端或SSH客户端登录到H3C交换机的管理界面。进入用户视图:输入user-interfacevty04命令,进入......
  • supervisor命令小记
    查看已启动服务状态supervisorctlstatus查看某个服务状态supervisorctlstatus进程名启动某个进程supervisorctlstart进程名重启某个进程supervisorctlrestart进程启动名停止某个进程supervisorctlstop进程名修改或添加某个服务配置文件后,使其......
  • 11-Simple Extensions
    基本类型BaseTypes用ABC表示基本类型basetypes/atomictypes名称,$A$表示基本类型组成的集合当展示求值的结果时,将省略λ抽象体,直接简记为一个<fun>,比如λx:B.x><fun>:B→B单位类型UnitTypesUnit类型的成员只有unitDerivedforms在下一节......