Faites confiance à Codd ou à vos installations?

Objets stockés sans maux de tête: un exemple simple de travail avec des objets Caché dans ObjectScript et Python



Château de Neuschwanstein

En juin 2020, exactement 50 ans d'entrepôts de données tabulaires ou, officiellement, un modèle de données relationnel. Voici un document officiel - ce même article célèbre . Nous remercions chaleureusement le Dr Edgar Frank Codd. Et, soit dit en passant, le modèle de données relationnelles figure sur la liste Forbes des innovations mondiales les plus importantes des 100 dernières années.

D'un autre côté, curieusement, Codd considérait les bases de données relationnelles et le langage SQL comme une implémentation déformée de sa théorie. À titre indicatif, il a même développé 12 règles que chaque système de gestion de bases de données relationnelles doit satisfaire (en fait, ce sont 13 règles). Et, en vérité, aujourd'hui, dans le monde, vous ne pouvez pas trouver de SGBD qui satisfont au moins à la «règle 0» de Codd et, par conséquent, personne ne peut appeler leur SGBD 100% relationnel :) Peut-être qu'il y a des exceptions, dites-moi?

Le modèle relationnel n'est pas très complexe et est étudié en parallèle. Elle peut même être trop étudiée. Pendant ce temps, en cette année 2019, nous célébrerons également un autre anniversaire - il y a exactement 10 ans, le hashtag #NoSQL plus tard "non seulement SQL" est apparu sur Twitter et a commencé sa pénétration rapide dans la pratique du développement de modèles de base de données.

Pourquoi une si longue introduction? Au fait que l'univers de programmation est constitué de données (et d'algorithmes bien sûr), et la position de monopole du modèle relationnel conduit, comme il est plus poli à dire, à une conscience partagée du programmeur. Parce que les objets de travail dans la tête du développeur (OOP est également total, non?), Toutes ces listes, files d'attente, arbres, tas, dictionnaires, threads, etc. à l'infini, sont loin des tables.

Et si vous continuez et vous souvenez de l'architecture de stockage dans les SGBD modernes? Disons directement que personne de bon sens ne stocke les données sous forme de tableaux. Les développeurs de SGBD utilisent le plus souvent des variétés de l'arbre B (par exemple, dans PostrgeSQL) ou, beaucoup moins souvent, un stockage basé sur un dictionnaire. D'autre part, les barricades, les développeurs qui utilisent des SGBD pour stocker, fonctionnent également sur des non-tables. Et cela oblige les programmeurs à combler constamment l'écart sémantique avec une couche de données intermédiaire maladroite. Et, par conséquent, provoquer une tension dichotomique interne, un inconfort systémique et une insomnie de débogage.

En bref, il y a une contradiction - nous emballons les données dans des objets adaptés à la tâche, et lors de l'enregistrement, nous devons prendre soin de certaines tables.

Le désespoir? Non :) Mais qu'en est-il du mapping objet-relationnel, est-ce dans le folklore ORM? Laissons cette guerre sainte à Yegor Bugaenko avec des camarades. Et toute cette histoire du siècle dernier, selon l'oncle Bob, ne devrait pas nous inquiéter .

Bien sûr, il convient de mentionner que le "sac avec octets" (Robert Martin "Pure Architecture") peut être sérialisé et déposé dans un fichier ou inséré dans un autre flux approprié. Mais, d'une part, cela nous limitera immédiatement dans la langue, et d'autre part, maintenant nous ne nous soucierons que du stockage dans le SGBD.

Il existe une exception agréable à ces hauts et ces bas avec les sacs d'octets - le SGBD Intersystems Caché (et maintenant la plate-forme de données InterSystems IRIS). C'est probablement le seul SGBD au monde qui ne cache pas l'évidence au développeur et va même plus loin - cela libère quelqu'un de penser "comment tout stocker correctement". Il suffit de dire que la classe continue le genre Persistant et que le point est dans le chapeau, c'est-à-dire en globaux (à ne pas confondre avec les variables globales!).

Tous les types de données peuvent être stockés, y compris les flux de caractères et binaires. Voici un exemple simple:

//       - // :      ,     ,     , ,   Class FW.Events Extends %Persistent { Property "My name" As %String; } //      //   «»  set haJS = ##class(FW.Events).%New() //   write haJS.%Id() 

De plus, et c'est formidable, vous pouvez communiquer avec des objets stockés non seulement en ObjectScript, natif de Caché, mais en les récupérant et en les enregistrant directement en Python, Java, JavaScript, C ++, C #, Perl. Et même, oh horreur :). Il est également possible d'obtenir des informations à partir des mêmes objets directement via des requêtes SQL, et il est également possible d'appeler vos propres méthodes sur des objets. Plus précisément, les méthodes dans ce cas seules (et le mot magique SqlProc) se transforment en procédures stockées. Toute la magie est déjà sous le capot du SGBD Caché.
Comment obtenir un accès de test gratuit au SGBD Intersystems Caché?
C'est absolument réel, peu importe ce que disent les mauvaises langues! :) Vous pouvez télécharger et installer la version complète mono-utilisateur de Caché ici (vous devrez vous inscrire gratuitement). Les versions sont disponibles pour MacOS, Windows et Linux.
Il est plus pratique de travailler avec du code ObjectScript et d'accéder directement au serveur SGBD Caché (et à la plate-forme InterSystems IRIS également) à l'aide de l'Atelier IDE, qui est basé sur Eclipse. Toutes les instructions de téléchargement et d'installation sont ici .

Pour qui il est plus pratique et familier, vous pouvez utiliser le code Visual Studio confortable et simple, en le complétant avec le plug-in ObjectScript développé par la communauté.

Et maintenant quelques exemples pratiques. Essayons de créer quelques objets liés et travaillons avec eux en ObjectScript et Python. L'intégration avec d'autres langues est implémentée de manière très similaire. Python est choisi pour des raisons "d'affinité maximale" avec ObjectScript - les deux langages sont scriptables, supportent la POO et n'ont pas de typage fort :)

Pour des idées d'exemples, nous nous tournons vers des projets vigoureux de Khabarovsk (à ne pas confondre avec Khabrovsk!) Du «Cadre de rassemblement assis». Le code source idéologique se trouve sur github.com/Hajsru/framework-weekend Et notre code source est plus bas en texte.
Une nuance importante pour les utilisateurs de macOS. Lors du démarrage des modules de support pour Python, vous devez vous rappeler que vous devez spécifier le chemin DYLD_LIBRARY_PATH vers le répertoire où vous avez installé Caché. Par exemple, comme ceci:
export DYLD_LIBRARY_PATH = / application / Cache / bin: $ DYLD_LIBRARY_PATH
Ceci est spécifiquement indiqué dans la documentation.

Nous créons des classes stockées sur ObjectScript


Alors allons-y. Les cours à Caché seront très simples. Vous pouvez vous passer d'un IDE - copiez le code de classe directement via le portail de votre instance de plate-forme Caché (oui, le SGBD Caché est loin d'être un simple SGBD): Navigateur système> Classes> Importer (espace de noms USER).

Après l'enregistrement, les objets apparaîtront dans les globes avec des noms correspondant aux noms des classes correspondantes. Consultez également le portail de gestion Caché: Navigateur système> Globals (Namespace USER).

 //    , ,      Class FW.Event Extends %Persistent { Property title as %String; Property description as %String; Property date as %Date; Property visitors as list of FW.Attendee; } //    / Class FW.Attendee Extends %Persistent { Property name As %String; } 

Accès aux objets dans Caché depuis Python


Tout d'abord, connectez-vous à la base de données du SGBD Caché. Nous répétons comme dans la documentation .
Juste un fait utile pour travailler avec. Gratuit, c'est aussi une version de formation du SGBD Caché, qui vous permettra de faire tout ce qui est disponible dans la version entièrement fonctionnelle, mais ne permet que deux connexions actives. Par conséquent, en même temps, il ne sera pas possible de conserver une connexion à partir de l'IDE et d'essayer d'exécuter un autre code pour interagir avec le serveur. La solution la plus simple trouvée est de fermer l'IDE pendant que le code Python est en cours d'exécution.
 #   Caché    Python3 import intersys.pythonbind3 #    conn = intersys.pythonbind3.connection() conn.connect_now("localhost[1972]:USER","_SYSTEM","SYS", None) #    print ("conn = %d " % conn.handle) #     database = intersys.pythonbind3.database(conn) 

Et maintenant, nous allons créer une base de données d'objets d'événements informatiques et de leurs participants. Très très simple. La première consiste à créer une classe pour enregistrer et stocker des informations sur le participant à l'événement. Pour plus de simplicité pour la classe, seul le nom du membre.

 #         class Attendee: #        def __init__ (self): self.att = database.create_new("FW.Attendee", None) #             id def new (self, name): self.att.set("name", name) self.att.run_obj_method("%Save",[]) #    id     def use (self, id): self.att = database.openid("FW.Attendee",str(id),-1,-1) #       def clean (self): id = self.att.run_obj_method("%Id",[]) self.att.run_obj_method("%DeleteId", [id]) 

Comme vous pouvez le voir, nous utilisons des fonctions wrapper prêtes à l'emploi pour les méthodes d'accès aux champs des objets dans Caché: définissez et dans les paramètres, nous passons le nom de la propriété entre guillemets et openid avec le nom du package et de la classe. À propos d'une fonction get similaire, il existe des exemples ci-dessous. Pour accéder à toutes les autres méthodes, y compris celles héritées par la classe de leurs ancêtres, utilisez la fonction run_obj_method () avec le nom de la méthode et les paramètres d'appel, si nécessaire.

La magie la plus importante de la ligne: self.att.run_obj_method ("% Save", [])
C'est ainsi que nous avons la possibilité d'enregistrer des objets avec une référence directe et sans avoir besoin d'utiliser des bibliothèques et des cadres supplémentaires, tels que les ORM omniprésents et disgracieux.

De plus, étant donné la nature orientée objet d'ObjectScript, ainsi que les méthodes de sa classe (dans notre exemple, nous ne les avons pas faites), nous obtenons un bonus de l'accès Python à l'ensemble des méthodes héritées de la classe Persistent et de ses ancêtres. Voici la liste complète , si cela.

Créez le premier membre:

 att = Attendee() att.new("") 

Après avoir exécuté ce code, un global apparaîtra dans la base de données avec le nom FW.AttendeeD et le contenu de l'objet juste enregistré comme dans la capture d'écran:



Après l'enregistrement, cet objet a son propre identifiant (avec le numéro 1). Par conséquent, vous pouvez le charger dans notre programme en utilisant cet identifiant:

 att = Attendee() att.use(1) print (att.att.get("name")) 

Et maintenant, connaissant à nouveau id, si nécessaire, vous pouvez supprimer l'objet de la base de données des participants:

 att = Attendee() att.use(1) att.clean() 

Vérifiez, après avoir exécuté cet exemple, l'enregistrement sur l'objet doit disparaître dans le global. Bien que les données téléchargées restent «en mémoire» de votre objet jusqu'à la fin du programme.

Passons à l'étape suivante. Créez les enregistrements d'événements réels.

 #        class Event: #        def __init__ (self): self.event = database.create_new("FW.Event", None) #            id def new (self, title, desc, date): self.event.set("title", title) self.event.set("description", desc) self.event.set("date", date) self.event.run_obj_method("%Save",[]) #    id    def use (self, id): self.event = database.openid("FW.Event",str(id),-1,-1) #       def addAttendee (self, att): eventAtt = self.event.get("visitors") eventAtt.run_obj_method("Insert", [att]) self.event.set("visitors", eventAtt) self.event.run_obj_method("%Save",[]) #      def clean (self): id = self.event.run_obj_method("%Id",[]) self.event.run_obj_method("%DeleteId", [id]) 

La structure de la classe est presque la même que ci-dessus pour le membre de la classe. Plus important encore, une méthode est apparue pour ajouter des participants à la liste des participants à cet événement addAttendee (att).

Nous essayons de créer un objet-enregistrement sur un nouvel événement et l'enregistrons dans la base de données:

 haJS = Event() haJS.new("haJS", " ", "2019-01-19") 

Cela devrait ressembler à ceci (notez que la date est automatiquement convertie au format ObjectScript et lorsqu'elle est rechargée dans l'objet Python, elle reviendra au format d'origine):



Reste à ajouter le participant à l'événement:

 #     haJS = Event() haJS.use(1) #    att = Attendee() att.new("") #      haJS.addAttendee(att.att) 

Ainsi, ces exemples montrent qu'il n'est pas nécessaire de penser en même temps à votre modèle de données et à son schéma de stockage tabulaire. Vous pouvez utiliser des outils plus évidents pour vos tâches.

Des instructions détaillées pour la connexion et l'utilisation de Caché avec Python et d'autres langues sont toujours à votre disposition dans la documentation et sur le portail de la communauté des développeurs InterSystems - ce ne sont pas moins de 5 000 membres de community.intersystems.com
Aide: Le SGBD multimodèle InterSystems Caché reste le leader mondial permanent des bases de données d'objets


Source: https://habr.com/ru/post/fr435612/


All Articles