Fluent NHibernate 未将子行映射到集合属性(DB2 数据库)
背景:
我正在处理旧版 DB2 数据库,因此我无法控制架构。我已经在这个网站上搜索过答案,但没有找到。我也搜索过谷歌并没有找到合适的答案。
这里描述的表都使用复合键。我有一个父表,用于存储每个“案例”的资格信息。子表存储与案例相关的每个人的资格信息。子记录通过 pin 编号进行区分,以使其仅在子表中唯一。
我使用 NHibernate v3.1 和 Fluent NHibernate v1.2,两者都是通过 NuGet 包获取的。使用 Fluent NHibernate 自动映射器功能来映射实体。任何自定义映射都是在每个实体的映射覆盖方法中完成的。
另一件需要知道的事情是,这些表没有在 DB2 中定义的“主键”。它们只有“唯一键”,这就是您在下面的复合键定义中看到的内容(请参阅代码)。
T0026_AG_ELIG是父表的名称和对应的POCO类。
T0265_AG_IN_ELIG 是子表的名称和对应的 POCO 类。
问题:
问题是,当我执行查询时,查询了所有数据,父记录成功映射到类,但返回的子行没有映射到父类上的集合。 NHibernate 确实生成对父数据和子数据的查询。当我对数据库执行自己的查询时,确实会返回符合条件的正确数据。由于某种原因,子记录没有绑定到父类 (T0026) 的属性。
问题:
我需要做什么才能让从 T0265_AG_IN_ELIG 返回的多行映射到相应的类并正确加载到父类 (T0026_AG_ELIG) 上的指定集合属性中?
父级 (T0026_AG_ELIG) 的集合属性:
Public Overridable Property IndividualEligibilityRecords As IList(Of T0265_AG_IN_ELIG)
父级 (T0026_AG_ELIG) 的映射覆盖:
mapping.CompositeId() _
.KeyProperty(Function(x) x.CASE_NUM) _
.KeyProperty(Function(x) x.PROGRAM_CD) _
.KeyProperty(Function(x) x.SUBPROGRAM_CD) _
.KeyProperty(Function(x) x.AG_SEQ_NUM) _
.KeyProperty(Function(x) x.CAG_ELIG_SEQ_NUM)
mapping.HasMany(Of T0265_AG_IN_ELIG)(Function(x) x.IndividualEligibilityRecords) _
.Cascade.All() _
.Inverse() _
.Fetch.Join() _
.KeyColumns.Add("CASE_NUM") _
.KeyColumns.Add("PROGRAM_CD") _
.KeyColumns.Add("SUBPROGRAM_CD") _
.KeyColumns.Add("AG_SEQ_NUM") _
.KeyColumns.Add("CAG_ELIG_SEQ_NUM") _
.Not.LazyLoad() _
.AsList(Function(x) x.Column("PIN_NUM"))
mapping.IgnoreProperty(Function(x) x.IndividualEligibilityRecords)
子级 (T0265_AG_IN_ELIG) 的映射覆盖:
mapping.CompositeId() _
.KeyProperty(Function(x) x.CASE_NUM) _
.KeyProperty(Function(x) x.PROGRAM_CD) _
.KeyProperty(Function(x) x.SUBPROGRAM_CD) _
.KeyProperty(Function(x) x.AG_SEQ_NUM) _
.KeyProperty(Function(x) x.CAG_ELIG_SEQ_NUM) _
.KeyProperty(Function(x) x.PIN_NUM)
以下内容执行查询的代码:
transaction = session.BeginTransaction()
query = session.CreateQuery("FROM T0026_AG_ELIG AS T0026 " _
& "WHERE T0026.CASE_NUM = :p0 AND T0026.PROGRAM_CD = :p1 AND " _
& "SUBPROGRAM_CD = :p2 AND AG_SEQ_NUM = :p3 AND CAG_ELIG_SEQ_NUM = :p4")
query.SetParameter("p0", caseNumber)
query.SetParameter("p1", programCode)
query.SetParameter("p2", subProgramCode)
query.SetParameter("p3", agSequenceNumber)
query.SetParameter("p4", cagEligSequenceNumber)
result = query.List()
transaction.Commit()
If result.Count = 1 Then
Return DirectCast(result.Item(0), T0026_AG_ELIG)
End If
Background:
I am working on a legacy DB2 database, so I have no control over the schema. I have searched this site for answers and have found none. I have also searched google and not found a suitable answer.
The tables described herein both utilize composite keys. I have a parent table that stores eligibility information per "case". The child table stores eligibility information regarding each individual associated with the case. The child records are differentiated by pin number to make them unique in the child table only.
I am using NHibernate v3.1 with Fluent NHibernate v1.2, both acquired via NuGet packages. The entities are mapped in using the Fluent NHibernate auto-mapper functionality. Any custom mapping is done in the mapping override method for each entity.
Another thing to know is that these tables do not have a "primary key" defined in DB2. They only have "unique keys", which are what you see in the composite key definition below (see code).
T0026_AG_ELIG is the name of the parent table and the corresponding POCO class.
T0265_AG_IN_ELIG is the name of the child table and the corresponding POCO class.
Problem:
The problem is that when I execute the query, all the data is queried, the parent record is successfully mapped to the class, but the returned child rows do not map into the collection on the parent class. NHibernate does generate the queries for the parent and child data. When I execute my own query against the database, the correct data for the conditions does come back. For some reason, the child records are just not being bound to the property on the parent (T0026) class.
Question:
What do I need to do to get the multiple rows coming back from T0265_AG_IN_ELIG to map to their corresponding class and load properly into the specified collection property on the parent class (T0026_AG_ELIG)?
Collection Property of Parent (T0026_AG_ELIG):
Public Overridable Property IndividualEligibilityRecords As IList(Of T0265_AG_IN_ELIG)
Mapping Override for Parent (T0026_AG_ELIG):
mapping.CompositeId() _
.KeyProperty(Function(x) x.CASE_NUM) _
.KeyProperty(Function(x) x.PROGRAM_CD) _
.KeyProperty(Function(x) x.SUBPROGRAM_CD) _
.KeyProperty(Function(x) x.AG_SEQ_NUM) _
.KeyProperty(Function(x) x.CAG_ELIG_SEQ_NUM)
mapping.HasMany(Of T0265_AG_IN_ELIG)(Function(x) x.IndividualEligibilityRecords) _
.Cascade.All() _
.Inverse() _
.Fetch.Join() _
.KeyColumns.Add("CASE_NUM") _
.KeyColumns.Add("PROGRAM_CD") _
.KeyColumns.Add("SUBPROGRAM_CD") _
.KeyColumns.Add("AG_SEQ_NUM") _
.KeyColumns.Add("CAG_ELIG_SEQ_NUM") _
.Not.LazyLoad() _
.AsList(Function(x) x.Column("PIN_NUM"))
mapping.IgnoreProperty(Function(x) x.IndividualEligibilityRecords)
Mapping Override for Child (T0265_AG_IN_ELIG):
mapping.CompositeId() _
.KeyProperty(Function(x) x.CASE_NUM) _
.KeyProperty(Function(x) x.PROGRAM_CD) _
.KeyProperty(Function(x) x.SUBPROGRAM_CD) _
.KeyProperty(Function(x) x.AG_SEQ_NUM) _
.KeyProperty(Function(x) x.CAG_ELIG_SEQ_NUM) _
.KeyProperty(Function(x) x.PIN_NUM)
The following code executes to execute the query:
transaction = session.BeginTransaction()
query = session.CreateQuery("FROM T0026_AG_ELIG AS T0026 " _
& "WHERE T0026.CASE_NUM = :p0 AND T0026.PROGRAM_CD = :p1 AND " _
& "SUBPROGRAM_CD = :p2 AND AG_SEQ_NUM = :p3 AND CAG_ELIG_SEQ_NUM = :p4")
query.SetParameter("p0", caseNumber)
query.SetParameter("p1", programCode)
query.SetParameter("p2", subProgramCode)
query.SetParameter("p3", agSequenceNumber)
query.SetParameter("p4", cagEligSequenceNumber)
result = query.List()
transaction.Commit()
If result.Count = 1 Then
Return DirectCast(result.Item(0), T0026_AG_ELIG)
End If
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我发布答案是因为它更容易阅读和编辑。
我的下一个猜测是,NH 被
T0265_AG_IN_ELIG
及其复合键的 hasmany 中不同数量的键列所混淆。通常,这种关联是依赖关联,其中子实体不单独映射,而是在集合内映射。尝试从自动映射中排除T0265_AG_IN_ELIG
并在T0026_AG_ELIG
中像这样映射它更新:
值
更新:当您从自动映射中排除 T0265_AG_IN_ELIG 时,您必须指定所有 组件中的列
I post in an answer because its much easier to read and edit.
My next guess is that NH is confused by the different number of key columns in the hasmany of
T0265_AG_IN_ELIG
and its compositekey. normally this kind of association is a dependent association where the child-entities are not mapped seperatly but within the collection. Try excludeT0265_AG_IN_ELIG
from automapping and mapping it like this inT0026_AG_ELIG
Update:
What is the value of:
Update: of yourse when you have excluded T0265_AG_IN_ELIG from automapping you have to specify all columns in the component
我能够弄清楚这一点。本质上,NHibernate 3.1 中存在一些问题,即在使用 Extra Lazy Loading 时只允许记录绑定。即使如此,HQL 也无法正确生成 SQL。解决方案是恢复使用 Fluent NHibernate 1.2 和 NHibernate 2.1.2。
下载链接的标题是“Download for NHibernate 2.1.2”。点击下面进入下载页面。
Fluent NHibernate 下载页面
T0026 的映射覆盖:
映射文件中的主要区别是:我们没有使用逆函数,而是从 NHibernate 返回一个“GenericPersistentBag”。
查询执行方法:
查询执行方法是相同的。
I was able to figure this out. Essentially, there is some issue in NHibernate 3.1 that will only let records bind when using Extra Lazy Loading. Even then, SQL is improperly generated from the HQL. The solution to this was to revert to using Fluent NHibernate 1.2 with NHibernate 2.1.2.
The link for the download is titled "Download for NHibernate 2.1.2". Click below to go to the downloads page.
Fluent NHibernate Downloads Page
Mapping Override for T0026:
The main differences in the mapping file are that we are not using the inverse and we are returning a "GenericPersistentBag" from NHibernate.
Query Execution Method:
The query execution method is identical.