Fluent NHibernate 1.2 与 SubclassMap 会导致“没有具有给定标识符的行”错误

发布于 2024-10-30 21:59:09 字数 3016 浏览 4 评论 0原文

我正在尝试升级到 Fluent NHibernate 2.1(Build #694)。因此,我也升级到 NHibernate 3.0。我遇到“每个子类表”映射的问题,这会在尝试检索数据时导致错误。

重要说明:这些表和类与现已弃用的“Joined-Subclass”映射版本一起使用,该映射存在于 FluentNhibernate 的早期版本中,它允许子类拥有自己的唯一 id。

我已将代码削减到最小的部分,所以让我通过代码进行解释,它会变得更加清晰:

以下是涉及的表格:

Tables

这里是代表表的类:

public class Field
{
    public virtual int Id { get; set; }
    public virtual string Code { get; set; }
    public virtual string Description { get; set; }
}
public class MenuItem : Field
{
    public virtual string NavigateUrl { get; set; }
}
public class UserLink 
{
    public virtual int Id { get; set; }
    public virtual string ExternalLinkName { get; set; }
    public virtual MenuItem MenuItem { get; set; }
    public virtual int UserId { get; set; }
}

这里是相应的映射:

public class FieldMap : ClassMap<Field>
{
    public FieldMap()
    {
        Table("Field");
        Id(x => x.Id, "ID").GeneratedBy.Identity();
        Map(x => x.Code, "Code");
        Map(x => x.Description, "Description");
    }
}
public class MenuItemMap : SubclassMap<MenuItem>
{
    public MenuItemMap()
    {
        Table("MenuItem");
        Map(x => x.NavigateUrl, "NavigateUrl");
    }
}
public class UserLinkMap : ClassMap<UserLink>
{
    public UserLinkMap()
    {
        Table("UserLink");
        Id(x => x.Id, "ID").GeneratedBy.Identity();
        Map(x => x.ExternalLinkName, "ExternalLinkName");
        Map(x => x.UserId, "User_ID");
        References(x => x.MenuItem).Column("ID");
    }
}

这里是测试:

[Test]
    public void CanRetrieveUserLinks()
    {
        ISession session = GetSession();

        DetachedCriteria criteria = DetachedCriteria.For(typeof (UserLink))
            .Add(Restrictions.Eq("UserId", 1));

        ICriteria executableCriteria = criteria.GetExecutableCriteria(session);
        var userLinks = executableCriteria.List<UserLink>();

        Assert.IsFalse(string.IsNullOrEmpty(userLinks[0].MenuItem.NavigateUrl));

        session.Close();
    }

当执行 Assert 行时,生成的 SQL 不正确,因为它尝试通过 Field_ID 查找 MenuItem ID 。因此,我收到错误: NHibernate.ObjectNotFoundException:不存在具有给定标识符的行[AS.AIMS.DomainModel.MenuItem#11]

首先生成 sql 来检索 userLinks,这是正确的:

SELECT this_.ID               as ID2_0_,
   this_.ExternalLinkName as External2_2_0_,
   this_.User_ID          as User3_2_0_
   FROM   UserLink this_
  WHERE  this_.User_ID = 1 /* @p0 */

然后,为了检索菜单项,它使用 Field_Id 而不是 ID:

SELECT menuitem0_.Field_id      as ID0_0_,
   menuitem0_1_.Code        as Code0_0_,
   menuitem0_1_.Description as Descript3_0_0_,
   menuitem0_.NavigateUrl   as Navigate2_1_0_
  FROM   MenuItem menuitem0_
 inner join Field menuitem0_1_
         on menuitem0_.Field_id = menuitem0_1_.ID
 WHERE  menuitem0_.Field_id = 11 /* @p0 */

I am trying to upgrade to Fluent NHibernate 2.1 (Build #694). As a result, I am also upgrading to NHibernate 3.0. I am having an issue with a "Table-Per-Subclass" mapping, which results in error when trying to retrieve data.

Important Note: these tables and classes worked with the now deprecated version of "Joined-Subclass" mapping which existed in a previous version of FluentNhibernate, which allowed the subclass to have its own unique id.

I have whittled the code down to its smallest parts, so let me explain, via code and it will become more clear:

Here are the tables involved:

Tables

Here are the classes representing the tables:

public class Field
{
    public virtual int Id { get; set; }
    public virtual string Code { get; set; }
    public virtual string Description { get; set; }
}
public class MenuItem : Field
{
    public virtual string NavigateUrl { get; set; }
}
public class UserLink 
{
    public virtual int Id { get; set; }
    public virtual string ExternalLinkName { get; set; }
    public virtual MenuItem MenuItem { get; set; }
    public virtual int UserId { get; set; }
}

Here are the corresponding Mappings:

public class FieldMap : ClassMap<Field>
{
    public FieldMap()
    {
        Table("Field");
        Id(x => x.Id, "ID").GeneratedBy.Identity();
        Map(x => x.Code, "Code");
        Map(x => x.Description, "Description");
    }
}
public class MenuItemMap : SubclassMap<MenuItem>
{
    public MenuItemMap()
    {
        Table("MenuItem");
        Map(x => x.NavigateUrl, "NavigateUrl");
    }
}
public class UserLinkMap : ClassMap<UserLink>
{
    public UserLinkMap()
    {
        Table("UserLink");
        Id(x => x.Id, "ID").GeneratedBy.Identity();
        Map(x => x.ExternalLinkName, "ExternalLinkName");
        Map(x => x.UserId, "User_ID");
        References(x => x.MenuItem).Column("ID");
    }
}

Here is the test:

[Test]
    public void CanRetrieveUserLinks()
    {
        ISession session = GetSession();

        DetachedCriteria criteria = DetachedCriteria.For(typeof (UserLink))
            .Add(Restrictions.Eq("UserId", 1));

        ICriteria executableCriteria = criteria.GetExecutableCriteria(session);
        var userLinks = executableCriteria.List<UserLink>();

        Assert.IsFalse(string.IsNullOrEmpty(userLinks[0].MenuItem.NavigateUrl));

        session.Close();
    }

When the Assert line is executed, the SQL generated is incorrect as it tries to lookup the MenuItem by Field_ID instead of ID. Therefore, I receive the error: NHibernate.ObjectNotFoundException: No row with the given identifier exists[AS.AIMS.DomainModel.MenuItem#11]

First the sql is generated to retrieve the userLinks, which is correct:

SELECT this_.ID               as ID2_0_,
   this_.ExternalLinkName as External2_2_0_,
   this_.User_ID          as User3_2_0_
   FROM   UserLink this_
  WHERE  this_.User_ID = 1 /* @p0 */

Then to retrieve the Menu Item, it uses Field_Id instead of ID:

SELECT menuitem0_.Field_id      as ID0_0_,
   menuitem0_1_.Code        as Code0_0_,
   menuitem0_1_.Description as Descript3_0_0_,
   menuitem0_.NavigateUrl   as Navigate2_1_0_
  FROM   MenuItem menuitem0_
 inner join Field menuitem0_1_
         on menuitem0_.Field_id = menuitem0_1_.ID
 WHERE  menuitem0_.Field_id = 11 /* @p0 */

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(1

︶葆Ⅱㄣ 2024-11-06 21:59:09

只是看看我是如何做到这一点的,我能看到的唯一区别是在数据库上(在您的情况下)MenuItem 将只有一个 Field_ID。这将与现场 ID 相关。

如果删除 MenuItem 上的 ID 并将 Field_ID 作为键,它会起作用吗?就像这样:

MENUITEM                  FIELD

#Field_ID   <---------->  #ID
NavigateUrl               Code        
(Removed Code, Desc)      Description 

Just looked at how i did this, and the only difference i can see is that on the database (in your case) MenuItem would only have a Field_ID. This would would relate to ID on field.

Does it work if you remove ID on MenuItem and make Field_ID the key. Like so:

MENUITEM                  FIELD

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