【问题标题】:Using NHibernate with ancient database with some "dynamic" tables将 NHibernate 与带有一些“动态”表的古代数据库一起使用
【发布时间】:2009-11-04 08:45:20
【问题描述】:

我有一个设计非常邪恶的遗留数据库,我需要为其编写一些应用程序。我根本不允许接触数据库设计,看看这是一个由唾沫和祈祷组成的脆弱的旧系统。我当然非常清楚,这不是数据库最初应该设计的方式,但现实生活有时会阻碍..

对于我的新应用程序,我正在使用 NHibernate(使用 Fluent 进行映射,使用 NHibernate LINQ 进行查询)并尝试正确地做事。所以有 IoC 和存储库以及更多的接口,我数不清。但是,数据库结构让我有些头疼。

该系统非常关注客户的概念,每个客户都生活在一个广告系列中。这些活动是由旧应用程序之一创建的。系统中的每个活动都在名为 CampaignSettings 的表中定义。此表的其中一列只是一个名为“表”的文本列,它指的是与 CampaignSettings 中的活动条目同时创建的数据库表。该表的名称与活动的名称相关,这几乎可以是客户想要的任何东西(在 SQL Server(2000 或 2005)给定的约束范围内)。客户居住在这些表格中。

这就是挑战#1——直到运行时我才知道表名。而且它会因站点而异 - 我猜没有静态映射。

更糟糕的是,我们面临挑战 #2 - 此广告系列表在结构上也是动态的,这意味着它有一定数量的列(客户 ID、姓名、电话号码、电子邮件地址和其他内务管理)东西),然后还有另外两组列,根据客户的要求逐案添加。

旧的应用程序使用 SQL 来获取表中存在的列名,然后将它不知道的列名添加为应用程序中的“自定义字段”。我需要处理这个。

我知道我可能无法简单地通过使用映射魔法来应对这些挑战,除了我从 NHibernate 获得的 ORM 优点之外,我还准备做一些丑陋的 SQL(在这里以及 NHibernate 处理得很好) - 但是如何?

我将创建一个客户实体,我想我可以通过执行类似 SQL 的直接 SQL 手动填充它

SELECT * FROM SomeCampaignTable WHERE id=<?>

然后一一浏览列并将内容放在它所属的位置。不好玩,但很有必要。

然后我猜想首先发现表的结构,我可以这样运行 SQL:

SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'SomeCampaignTable'
ORDER BY ORDINAL_POSITION

再次做一些手动工作来配置我的对象来处理自定义字段。

我的问题很简单——我如何在 NHibernate 中做到这一点?找到一种方法来运行我自己的 SQL,然后循环遍历结果是一件简单的事情,还是有更优雅的方法来消除它的痛苦?

虽然我很欣赏这个数据库设计属于某种酷刑博物馆的某个地方,但“添加一些视图”或“更改数据库”之类的答案对我没有帮助 - 如果我提出类似的建议,我会被枪杀。

感谢您在这里帮助我保持理智!

【问题讨论】:

    标签: c# sql-server nhibernate fluent-nhibernate


    【解决方案1】:

    您也许可以通过本机 SQL 实体查询来使用 NHibernate。忘记 Linq2NH - 我不会推荐 Linq2NH 用于任何严肃的应用程序。

    检查此页面。
    13.1.2.实体查询 https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/querysql.html

    你可以也许做这样的事情: 根据“假”表映射您的实体,以在编译映射文档时让 NHibernate 满意(我知道您说过您不能更改数据库,但希望可以制作一个空表来让 NH 满意)。

    然后按照上面的 13.1.2 运行这样的查询:

    sess.CreateSQLQuery("SELECT tempColumn1 as mappingFileColumn1, tempColumn2 as mappingFileColumn2, tempColumn3 as mappingFileColumn3 FROM tempTableName").AddEntity(typeof(Cat));
    

    NHibernate 应该将您返回的列与映射实体拼接在一起,并为您提供填充了所有属性的“Cat”类型的实体。不过,我在这里推测,我不确定这是否可行,这是我能想到的使用 NHibernate 的唯一方法,因为您在编译时不知道表/列。您绝对不能使用 HQL、Criteria、Linq2NH,因为您在编译时不知道表和列,并且 HQL 等都将您的映射转换为映射的列名以生成底层 SQL。本机 SQL 查询是我认为的唯一方法。

    【讨论】:

    • 谢谢 - 这让我走上了正轨!使用 CreateSQLQuery 和 .SetResultTransformer(Transformers.AliasToEntityMap) 可以从表中获取所需的所有信息。它很脏,但它有效!谢谢!只是出于好奇——Linq2NH 不好的任何特殊原因(不是针对这种特殊情况,只是一般情况下)?
    • Linq2NH 还很不成熟。它只支持基本查询,不支持缓存,急切加载......我在我当前的应用程序中使用了它 6 个月,然后我放弃了它,因为我懒得学习 HQL/Criteria,然后花了一周时间把它撕掉。 Linq2NH 易于学习,易于操作,但如果您花一点时间学习 HQL/Criteria,您将拥有更多的功能和控制权,并且您的应用程序会更快。祝你好运!听起来你手头有一个地狱般的项目!
    • 谢谢!到目前为止,我也使用过 Linq2NH,但我想我可以在没有那一周(或其他任何时间)的情况下摆脱它。感谢您的帮助、建议和祝福,我很幸运能退出这个项目我头上还留着头发。 :)
    猜你喜欢
    • 2014-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-30
    • 1970-01-01
    • 2011-01-24
    • 2017-02-15
    • 1970-01-01
    相关资源
    最近更新 更多