动态对象关系映射D-ORM

动态对象关系映射D-ORM与传统ORM最显著的区别是:

  • 更高的抽象
  • 一切基于动态基于运行时

与传统ORM(如Hibernate、Entity Framework等)相比,D-ORM可以在运行时根据用户需求和业务场景,动态生成和执行SQL,而无需编译或运行前预先定义好实体类和数据库表结构。

也可以根据业务逻辑的需求动态地创建、修改或删除数据库表结构。

这使得D-ORM更加灵活和适应性强,能够处理更加复杂和多变的数据持久化需求。

在数据中台、可视化、低代码、SAAS、自定义表单、异构数据库迁移同步、物联网车联网数据处理、数据清洗、运行时自定义报表/查询条件/数据结构、爬虫数据解析等动态应用场景中有着广泛的应用。

困境 

在传统的ORM框架中,需要生成大量呆板低效的模板文件,特别是在sql生成过程中,需要各种便利判断,占据了编码环节大量的时间成本。而在数据计算过程中,VO DTO等实体类丝毫没有发挥其应有的价值。

这还只是低效的问题,通过时间,人海毕竟还是可以解决的。

但是遇到动态场景时,ORM已经完全不能胜任。

就如结构化数据库保存非结构化数据一样绕路。如mysql代替neo4j+mongodb+redis一样困难。

场景已经变了,路已经不是原来的路

原来有明确固定的实体,确定了实体后在这个基础上生成一系列的模板,

如订单类,产品类,不同的系统中这几个类还是大同小异的,无非也就是属性可能不同,最多也就是属性间可能组合出笛卡尔积,无论怎么千变万化,设计和编码阶段还是看得见的。

而在动态场景中,实体虽然还在,但在设计和编码阶段是看不到的,只有在运行时才能看到,并且也不固定而是随时可能变化,如动态表单场景中,不同的业务会定义不同的表单,随着业务的发展表单也会随之变化。

破局 

这时ORM已经完全找不着路了。为了适应动态场景,可以:

  • 通过动态生成的DML创建/更改数据库对象
  • 创建具有大量稀疏物理列的表,并且仅使用"重叠"逻辑架构所需的表
  • 创建一个"长而窄"表,将动态列值存储为行,然后需要对其进行透视处理以创建一个"短而宽"行集,其中包含特定实体的所有值
  • 也可以利用MongoDB等非关系型数据库

但是无论采用什么方式,都需要一个能够与之相配合的ORM,只不过ORM所要面对的不再是静态的数据结构,而是动态数据结构,不再是数据而是元数据。

  • 对象已经不是原来静态的对象,而是需要一个高度抽象的动态对象,需要能够囊括原来所有的对象。
  • 对象与表,属性与列不再是一一对应,属性也没有固定的数据类型,而是需要更加详细复杂的定义。
    这里还要还原一下“面向对象”中对象的概念,对象不是只有get/set/注解这么弱
    需要把数据及对数据的操作封装在一起,作为一个相互依存的整体,并实现高度的抽象
    要关注元数据,不再关注姓名、姓别等具体属性
    应该能提供统一的数学计算能力,如结果集的聚合、过滤、行列转换、格式、方差、分组等
  • sql也不能写在配置文件里了,需要在运行时动态生成。 既然表与列已经不固定,那SQL自然也无法提前定义了。
  • 数据源也不能在配置文件中枚举了 因为在数据中台场景中可能在运行时随时出现各种各样的数据源。
  • 在此基础之上的业务逻辑,数据存取都要适应动态环境。

如果把这些主要的问题都解决了,那就已经蜕变成前文所说的D-ORM了。

历史原因 

NO-ORM并不是一个新生事物,早在No-SQL兴起时,NO-ORM就应该随之协同发展了。

其之所以发展缓慢,主要原因在于随着windows,互联网,移动互联网三次爆发,传统的软件系统也井喷式的发展,天量资金和人才的涌入,让业界没有动力考虑其动态性,复用性,基本上来一个定制一个,来两个,再组建个团队。

而在这种环境下成长起来的程序员,和培训机构,也把ORM作为了软件开发事实上的标准。在高薪以及模板式的流水中,如果说起另一种事物会开发人员产生一种天然的陌生感甚至抵触感。

不管你是不是埋头的那一个,都应该能感觉到高薪已经很难持续,模板式的流水也已经没有了生存空间。

现状 

虽磁AI的逐渐成熟,许多传统的应用被赋予了更强的动态处理能力。这对应用背后的数据库,以及操作数据库的插件提出了更高的要求,模板式的流水已经很难适应动态场景的需求。

特别是受疫情米国及行业下行压力的影响,野蛮式别说发展了,生存都难以保障。各大厂的降本已经持续了很长一段时间,然而降本只能残喘,增效才能保证长远的发展。

对于后台开发团队来说,NO-ORM已经成了重要的破局方式之一。而D-ORM作为领域内优秀的代表也越来越受到关注。

虽然在传统的业务系统中,很少有D-ORM的身影,但是在开篇说过的几种应用场景中D-ORM已经无处不在了

应用 

  • 低代码是D-ORM应用最多的领域之一。由于其交付快、响应快,灵活度高、成本低等特点,传统的应用系统及头部的大厂基本都已经提前布局了低代码。
    如阿里的钉钉,腾讯的企业微信以及金蝶用友等传统办公软件。遗憾的是几个比较有影响的产品都不开源,所以也不是很清楚其内部具体如何实现的。
  • 异构数据迁移或汇聚作为大数据、数据中台的重要组成部分,由于第三方数据源的不可按及多样性,也是D-ORM天然的应用场景。如阿里开源的一个datax,这个产品只是单纯的编辑sql,
    所以如果遇到大规模的数据迁移,写sql这一步就能劝退一大批人才。如果有D-ORM的加持应该就简单多了。
  • 自定义表单、自定义报表、动态查询条件作为工作流必不可少的一部分,是提交工作效率、解放程序员时间和精力的重要手段,更是衡量一个工作流成熟度的重要标志之一,由于工作流的本质就是一个自定义的过程,所以在带过定义过程中,到处是对D-ORM的应用。
    开源工作流引擎发展的历史比较久,发JBPM从1.0发展到Activiti5已经开源有20多年时间。
  • 另外在数据可视货、网络爬虫、物联网领域对D-ORM也有较多的应用。

开源

由于在传统应用中对ORM的应用比较少,相应的在开源领域D-ORM也比较少。在Java言语中应用比较多的如anyline,从anyline设计思想和特征中可以看出其定位与D-ORM非常契合,特别是对动态sql的操作及结果集的增强。缺点是版本更新太快,导致许多功能在旧版本找不到。需要新功能只能跟进升级。优点是据说所有功能几乎都是依据社区中一线设计人员的实战需求。另外响应比较快几乎实时。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HibernateD 是 D 语言的 ORM 框架,类似 Java 的 Hibernate,示例代码:import hibernated.core; // Annotations of entity classes class User {     long id;     string name;     Customer customer;     @ManyToMany // cannot be inferred, requires annotation     LazyCollection!Role roles; } class Customer {     int id;     string name;     // Embedded is inferred from type of Address     Address address;     Lazy!AccountType accountType; // ManyToOne inferred     User[] users; // OneToMany inferred     this() {         address = new Address();     } } @Embeddable class Address {     string zip;     string city;     string streetAddress; } class AccountType {     int id;     string name; } class Role {     int id;     string name;     @ManyToMany // w/o this annotation will be OneToMany by convention     LazyCollection!User users; } // create metadata from annotations EntityMetaData schema = new SchemaInfoImpl!(User, Customer, AccountType,                                   T1, TypeTest, Address, Role, GeneratorTest); // setup DB connection factory MySQLDriver driver = new MySQLDriver(); string url = MySQLDriver.generateUrl("localhost", 3306, "test_db"); string[string] params = MySQLDriver.setUserAndPassword("testuser", "testpasswd"); DataSource ds = ConnectionPoolDataSourceImpl(driver, url, params); // create session factory Dialect dialect = new MySQLDialect(); SessionFactory factory = new SessionFactoryImpl(schema, dialect, ds); scope(exit) factory.close(); // Create schema if necessary { // get connection Connection conn = ds.getConnection(); scope(exit) conn.close(); // create tables if not exist factory.getDBMetaData().updateDBSchema(conn, false, true); } // Now you can use HibernateD // create session Session sess = factory.openSession(); scope(exit) sess.close(); // use session to access DB // read all users using query Query q = sess.createQuery("FROM User ORDER BY name"); User[] list = q.list!User(); // create sample data Role r10 = new Role(); r10.name = "role10"; Role r11 = new Role(); r11.name = "role11"; Customer c10 = new Customer(); c10.name = "Customer 10"; User u10 = new User(); u10.name = "Alex"; u10.customer = c10; u10.roles = [r10, r11]; sess.save(r10); sess.save(r11); sess.save(c10); sess.save(u10); // load and check data User u11 = sess.createQuery("FROM User WHERE name=:Name").                            setParameter("Name", "Alex").uniqueResult!User(); assert(u11.roles.length == 2); assert(u11.roles[0].name == "role10" || u11.roles.get()[0].name == "role11"); assert(u11.roles[1].name == "role10" || u11.roles.get()[1].name == "role11"); assert(u11.customer.name == "Customer 10"); assert(u11.customer.users.length == 1); assert(u11.customer.users[0] == u10); assert(u11.roles[0].users.length == 1); assert(u11.roles[0].users[0] == u10); // remove reference u11.roles.get().remove(0); sess.update(u11); // remove entity sess.remove(u11); 标签:HibernateD

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值