Fluent NHibernate 未将子行映射到集合属性(DB2 数据库)

发布于 2024-12-13 20:48:07 字数 2755 浏览 2 评论 0原文

背景

我正在处理旧版 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

云仙小弟 2024-12-20 20:48:07

我发布答案是因为它更容易阅读和编辑。

我的下一个猜测是,NH 被 T0265_AG_IN_ELIG 及其复合键的 hasmany 中不同数量的键列所混淆。通常,这种关联是依赖关联,其中子实体不单独映射,而是在集合内映射。尝试从自动映射中排除 T0265_AG_IN_ELIG 并在 T0026_AG_ELIG 中像这样映射它

mapping.HasMany(Of T0265_AG_IN_ELIG)(Function(x) x.IndividualEligibilityRecords) _
   .Cascade.All() _
   .Inverse() _
   .KeyColumns.Add("CASE_NUM", "PROGRAM_CD", "SUBPROGRAM_CD", "AG_SEQ_NUM", "CAG_ELIG_SEQ_NUM") _
   .Not.LazyLoad() _
   .AsList(Function(x) x.Column("PIN_NUM"))
   .Component(Function(c) c.ParentReference(Function(x) x.T0026_AG_ELIG))

更新:

DirectCast(result.Item(0), T0026_AG_ELIG).IndividualEligibilityRecords.GetType().Name

更新:当您从自动映射中排除 T0265_AG_IN_ELIG 时,您必须指定所有 组件中的列

class AutomapConfiguration : DefaultAutomappingConfiguration
{
    public override bool ShouldMap(Type type)
    {
        return type != typeof(T0265_AG_IN_ELIG);
    }
}

class T0265_AG_IN_ELIG
{
    public T0026_AG_ELIG T0026_AG_ELIG { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
}


.Component(c =>
{
    c.ParentReference(x => x.T0026_AG_ELIG);
    c.Map(x => x.Prop1));
    c.Map(x => x.Prop2));
    c.Map(x => x.Prop3));
})

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 exclude T0265_AG_IN_ELIG from automapping and mapping it like this in T0026_AG_ELIG

mapping.HasMany(Of T0265_AG_IN_ELIG)(Function(x) x.IndividualEligibilityRecords) _
   .Cascade.All() _
   .Inverse() _
   .KeyColumns.Add("CASE_NUM", "PROGRAM_CD", "SUBPROGRAM_CD", "AG_SEQ_NUM", "CAG_ELIG_SEQ_NUM") _
   .Not.LazyLoad() _
   .AsList(Function(x) x.Column("PIN_NUM"))
   .Component(Function(c) c.ParentReference(Function(x) x.T0026_AG_ELIG))

Update:

What is the value of:

DirectCast(result.Item(0), T0026_AG_ELIG).IndividualEligibilityRecords.GetType().Name

Update: of yourse when you have excluded T0265_AG_IN_ELIG from automapping you have to specify all columns in the component

class AutomapConfiguration : DefaultAutomappingConfiguration
{
    public override bool ShouldMap(Type type)
    {
        return type != typeof(T0265_AG_IN_ELIG);
    }
}

class T0265_AG_IN_ELIG
{
    public T0026_AG_ELIG T0026_AG_ELIG { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
}


.Component(c =>
{
    c.ParentReference(x => x.T0026_AG_ELIG);
    c.Map(x => x.Prop1));
    c.Map(x => x.Prop2));
    c.Map(x => x.Prop3));
})
垂暮老矣 2024-12-20 20:48:07

我能够弄清楚这一点。本质上,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 的映射覆盖:

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) _
   .KeyColumns.Add("CASE_NUM", "PROGRAM_CD", "SUBPROGRAM_CD", "AG_SEQ_NUM", "CAG_ELIG_SEQ_NUM") _
   .Cascade.All() _
   .Table("PWS639TC.T0265_AG_IN_ELIG") _
   .Not.LazyLoad() _
   .AsBag()

映射文件中的主要区别是:我们没有使用逆函数,而是从 NHibernate 返回一个“GenericPersistentBag”。

查询执行方法:

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()

If result.Count = 1 Then
   returnable = DirectCast(result.Item(0), T0026_AG_ELIG)
End If

transaction.Commit()

查询执行方法是相同的。

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:

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) _
   .KeyColumns.Add("CASE_NUM", "PROGRAM_CD", "SUBPROGRAM_CD", "AG_SEQ_NUM", "CAG_ELIG_SEQ_NUM") _
   .Cascade.All() _
   .Table("PWS639TC.T0265_AG_IN_ELIG") _
   .Not.LazyLoad() _
   .AsBag()

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:

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()

If result.Count = 1 Then
   returnable = DirectCast(result.Item(0), T0026_AG_ELIG)
End If

transaction.Commit()

The query execution method is identical.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文