【问题标题】:Using an ORM with a database that has no defined relationships?将 ORM 与没有定义关系的数据库一起使用?
【发布时间】:2010-05-13 19:14:37
【问题描述】:

考虑一个由 100 多个表组成的数据库(MSSQL 2005),这些表在一​​定程度上定义了主键。表之间存在“关系”,但是这些不是通过外键约束强制执行的。

考虑以下我正在处理的典型表格类型的简化示例。 User 与 City 和 Province 表之间有明确的关系。但是,它们的关键问题是表中的数据类型和命名约定不一致。

User:
    UserRowId [int] PK
    Name [varchar(50)]
    CityId [smallint]
    ProvinceRowId [bigint]

City:
    CityRowId [bigint] PK
    CityDescription [varchar(100)]

Province:
    ProvinceId [int] PK
    ProvinceDesc [varchar(50)]

我正在考虑重写使用此数据源的应用程序(在 ASP.net MVC 中),因为它在设计中与 MVC 店面的设计相似。。但是,我正在经历概念验证阶段,这是我遇到的绊脚石之一。

  1. 就可以轻松使用的 ORM 选择而言,我有哪些选择,为什么?

  2. 我什至应该考虑 ORM 吗? (我问这个的原因是大多数解释和教程都适用于设计相对干净的现有数据库,或者与我相比是新创建的数据库。因此,我很难找到解决这个问题的方法)

  3. 存在大量现有 SQL 查询,数据映射器(例如 IBatis.net)是否更合适,因为我们可以轻松修改它们以使其工作并重用已经进行的投资?

我在 SO 上找到了this question,这表明可以使用 ORM - 但是我觉得这是一个映射问题?

注意:目前,对象模型没有明确定义,因为它不存在。现有系统几乎用 SQL 完成了几乎所有的事情,或者由过于复杂和大量的查询组成以完成功能。我几乎是一个菜鸟,并且在 ORM 和 MVC 方面的经验为零 - 所以这是一个很棒的学习曲线。

【问题讨论】:

  • 回顾性 ORM 应用程序......这是一场噩梦。祝你好运:P
  • @Aiden - 你有什么经验可以分享吗?
  • 让你的 FK 直截了当,这将使你的数据库更好,你的问题没有实际意义。
  • @Otávio,我希望就这么简单。另一个主要问题是,在这个 Dbs 生命过程中,人们决定删除东西而不是干净。因此,大多数表中都有悬空元组,没有对应关系。这可以被识别和清理,但它将是一个 PITA。
  • 附带说明 - 我们刚刚遇到了一个生产问题,由于缺少 pk 和 fk 约束,因此可以擦除一天的数据(是的,这是人为错误,而且是一个非常大的错误) .我们以为我们已经确定了我们的部署流程,但我们错了!

标签: nhibernate database-design orm datamapper


【解决方案1】:

我同意本。

我在这种情况下使用了 LAMP 堆栈。一个旧的肮脏、糟糕的编码网站需要重新开始。它确实是我见过的最糟糕的数据库,再加上一行又一行的盲目 SQL 执行。

工作?快速摆脱所有 SQL 并用抽象替换它。哪个ORM?我发现回顾性地使用现有的 ORM 来适应坏数据库(实际上是大多数数据库)是个坏消息。我认为这是 ORM 的一个问题,它们将数据库/存储问题移到更靠近应用程序的位置……而不是更远的地方。

我的解决方案:一种反射式 ORM,它只使用现有的数据库状态来计算正在发生的事情。所有选择、插入、更新和未使用的视图/存储过程来掩盖粗糙的数据库。它由一个 linq-esque API 提供支持,只需用它重写严峻的 SQL。将大约 100klocs 的 SQL 语句归结为小于 2klocs。

优点:我可以逐渐将数据库移植到视图和过程后面的更好结构。恕我直言,这就是所有数据库的组织方式,充分利用 SP 和视图提供的抽象。我从不想看到直接针对表的单个 SQL 语句(或伪装成 SQL 的 ORM)。

这就是我的故事。一种过度设计的方法,可以在现有的垃圾数据库之上插入一个很好的抽象,无需先重写数据库,也无需将 ORM 混入其中,从而使事情变得更加复杂。

毫无疑问是一种 hack,但它的效果非常好,我在项目中使用它,无论如何我都可以从头开始设计数据库;)

【讨论】:

  • 关于数据库级别抽象的好点。我之前很快就对此感到茫然,但现在可能会重新考虑。抽象在应用程序层/堆栈中得到了很好的接受,因此考虑到问题的类型,将这些概念带到数据库级别并不是 imo 过度设计,而是对原则和技术的良好应用。
  • 然后会考虑在这个新的抽象层上使用 ORM。 (响应很慢,因为我在业余时间玩这个)
  • 经过深思熟虑,这种方法是渐进的。 @Otávio Décio 上面的评论也让我思考,我认为将两者结合起来将是一个可行的解决方案。我的 POC 运行良好 :)。谢谢
【解决方案2】:

尝试保留现有模式然后将其转化为更加结构化的 orm 模式所涉及的工作量可能会很大且很复杂。如果您正在重写整个系统并淘汰旧系统,那么我将设计我的数据模型创建一个新的数据库和一组类,也许使用 linq2sql,然后编写一个数据迁移脚本将数据从旧模式移动到新模式.这样一来,您的复杂繁琐代码都在迁移中,您不必维护和管理结构化类模型和设计不佳的数据库之间的复杂映射。

【讨论】:

  • 数据迁移是作为一个绝望的子项目来解决的,主要是因为我们不知道这 100++ 个表中实际使用了哪些。
  • @Ahmad 如果您的所有代码都在存储过程中(恕我直言,这是唯一可行的方法),您可以将表列表与 procs 中引用的内容进行比较(当然,自动),并轻松生成代码中未使用内容的列表。检查关系会给你一个更完整的列表。
【解决方案3】:

我们刚刚遇到了一个糟糕的架构设计问题(随机有主键,根本没有外键,设计糟糕的表 - 只是一团糟)。

我们拥有丰富的技术选择,并采用 MVC2 前端(与您的问题无关),并有 2 个开发人员分开 - 一个尝试使用 NHibernate 建模,另一个使用 Entity Framework 4。

我赶紧补充一下,我们对我们想要从我们的域模型中得到什么有一个深刻的想法,并首先对其进行建模(不希望受到数据库的约束),所以从模式的角度来看,我们的“用户”对象实际上跨越 5 个表,我们封装了很多业务逻辑,这样域模型就不会错了,一旦我们对 User 对象感到满意,我们就开始尝试插入 ORM 的过程。

我可以毫不犹豫地说,在这两种情况下(NH 和 EF4),我们必须在模型上做出妥协才能硬着头皮实现。我将为您提供 EF4 中的示例,因为这是我最密切参与的示例,其他人可能能够将这些与其他 ORM 相关联。

私人二传手

不,EF4 不会影响您的生活。您的属性必须是公开的。有一些解决方法(例如,围绕来自您的数据库的属性创建包装器)

枚举

同样,没有 - 有一个包装器概念和一个“映射”来尝试从数据库中获取查找 int 到模型枚举类型中。

结果

我们用这两种方法坚持了一段时间,直到我们完成了用户的映射,结果是我们不得不以太多方式破坏我们的域模型。

在那之后我们去了哪里?

Linq to SQL 与我们自己的映射层。而且我们从未回头——太棒了——我们自己编写了映射层,一旦将 Dto 对象带到 Dal 层并将它(如我们指定的那样)映射到我们的域模型中。

祝你对 ORM 的任何调查都好运,如果我有一个像样的架构来作为它们的基础,我肯定会重新调查它们,但就目前而言,如果架构糟糕透顶,我们自己的更容易推出。

干杯, 特里

【讨论】:

  • 您提到了 linq-2-sql,但是如果我理解正确,这意味着您滚动了自己的 linq 查询,这些查询类似于您现有的查询来获取您定义的对象,这是正确的吗?您也可以在映射层方面进行更多扩展。
猜你喜欢
  • 2013-10-27
  • 2019-06-06
  • 2011-12-20
  • 2017-09-07
  • 1970-01-01
  • 1970-01-01
  • 2019-08-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多