使用NHibernate与古老的数据库和一些“动态”表

时间:2009-11-04 08:45:21

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

我有一个遗留数据库,其设计非常邪恶,我需要编写一些应用程序。我根本不被允许触摸数据库设计,看看这是一个由吐痰和祈祷聚集在一起的脆弱的旧系统。我当然非常清楚,这不是数据库应该首先设计的方式,但现实生活有时会受到影响..

对于我的新应用程序,我使用NHibernate(使用Fluent进行映射,使用NHibernate LINQ进行查询)并尝试正确处理。所以有IoC和存储库以及比我可以计算的更多接口。但是,数据库结构给我带来了一些麻烦。

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

这就是挑战#1 - 直到运行时我才知道表名。并且它会在不同的站点之间发生变化 - 我猜测没有静态映射。

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

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

我知道我可能无法通过使用映射魔法来处理这些挑战,除了从NHibernate获得的ORM优点之外,我还准备做一些丑陋的SQL(有20个“静态”表这里以及NHibernate处理得非常漂亮) - 但是怎么样?

我将创建一个Customer实体,我想我可以通过执行直接SQL手动填充

SELECT * FROM SomeCampaignTable WHERE id=<?>

然后逐个浏览列并将其放在它所属的位置。不好玩,但必要。

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

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

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

我的问题很简单 - 如何在NHibernate中执行此操作?这是一个简单的问题,找到一种方法来运行我自己的SQL,然后循环结果,还是有一种更优雅的方式来消除它的痛苦?

虽然我很欣赏这个数据库设计属于某种类型的酷刑博物馆,但是“添加一些观点”或“更改数据库”这样的答案对我没有帮助 - 如果我建议这样的话,我会被拍摄。

感谢任何可以帮助我在这里保持理智的事情!

1 个答案:

答案 0 :(得分:2)

您可以使用Native SQL Entity Queries来使用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查询是我认为的唯一方法。