将 HBM​​ 映射到 FluentNHibernate 多对多映射时遇到问题

发布于 2024-11-30 13:23:59 字数 4054 浏览 2 评论 0原文

TL; DR:我正在尝试在多对多表上映射一个带有附加 Order 列的多对多。 HBM 效果很好。无法使 FluentNHibernate 映射正常工作。

我有以下两个类,我试图将它们映射为多对多关系:

public class User
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    private IDictionary<int, Profile> profilesMap;

    public virtual IEnumerable<Profile> Profiles { get { return this.profilesMap.Select(kvp => kvp.Value); } }

    public User()
    {
        this.profilesMap = new SortedDictionary<int, Profile>();
    }

    public virtual void Add(Profile x)
    {
        profilesMap.Add(x);
    }
}

public class Profile
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

profilesMap 的键是配置文件顺序。因此,HBM 映射如下:

<class name="User" table="User">
  <id name="Id" column="Id" type="integer">
    <generator class="native" />
  </id>
  <property name="Name" type="string" column="Name" />
  <map name="profilesMap" access="field.camelcase" table="User_Profile">
    <key column="User_Id" />
    <index column="`Order`" type="integer" />
    <many-to-many class="Profile" column="Profile_Id" />
  </map>
</class>
<class name="Profile" table="Profile">
  <id name="Id" column="Id" type="integer">
    <generator class="native" />
  </id>
  <property name="Name" type="string" column="Name" />
</class>

这可以完美地工作并创建正确的多对多表:

create table User_Profile (
   User_Id INT not null,
   Profile_Id INT not null,
   "Order" INT not null,
   primary key (User_Id, "Order"),
   constraint FK6BDEDC07D1EDE651 foreign key (Profile_Id) references Profile,
   constraint FK6BDEDC07650CB01 foreign key (User_Id) references User
)

但是,我不太喜欢使用 HBM,因为它并不是真正适合重构。因此,我试图将其转换为 FluentNHibernate。这是我对用户多对多映射的尝试:

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        this.Id();
        this.Map(o => o.Name);

        var mapMember = Reveal.Member<User, IEnumerable<KeyValuePair<int, Profile>>>("profilesMap");

        this.HasManyToMany<KeyValuePair<int, Profile>>(mapMember)
            .Access.CamelCaseField()
            .AsMap<int>("`Order`")
            .Table("User_Profile");
    }
}

我希望这能起作用,但是在尝试构建会话工厂时它崩溃了:

表 User_Profile 中的关联引用未映射的类:System.Collections.Generic.KeyValuePair`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[ConsoleApplication9.配置文件,ConsoleApplication9,版本=1.0.0.0,文化=中性, PublicKeyToken=null]]

我对如何让 AsMap 工作进行了大量研究,因此我将其更改为以下内容:

this.HasManyToMany<KeyValuePair<int, Profile>>(mapMember)
    .Access.CamelCaseField().AsMap<int>("`Order`")
    .Element("Profile_id", ep => ep.Type<int>()) // Added.
    .Table("User_Profile");

但是,这会产生一个不正确的表not 包括来自 Profile_id外键(或非空约束):

create table User_Profile (
   User_id INT not null,
   Profile_id INT,
   "Order" INT not null,
   primary key (User_id, "Order"),
   constraint FK6BDEDC07650CB01 foreign key (User_id) references "User")

此外,在尝试向用户添加配置文件时它也会崩溃:

var a = new User() { Name = "A" };
var b = new Profile() { Name = "B" };
a.Add(b);

session.Save(b);
session.Save(a);
session.Flush(); // Error: Unable to cast object of type 'ConsoleApplication9.Profile' to type 'System.IConvertible'.

所以 - 我一直在我花了几个小时揪着头发试图确定如何做正确地将这种关系与 FNH 映射起来,但我似乎无法理解。简单的多对多关系看起来很简单,但是当尝试添加索引列时,它似乎不起作用。如果有人愿意帮助我解决这个问题,我将不胜感激。

TL; DR: I'm trying to map a many-to-many with an additionaly Order column on the many-to-many table. HBM works great. Can't get FluentNHibernate mappings to work.

I have the following two classes which I'm trying to map with a many-to-many relationship:

public class User
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    private IDictionary<int, Profile> profilesMap;

    public virtual IEnumerable<Profile> Profiles { get { return this.profilesMap.Select(kvp => kvp.Value); } }

    public User()
    {
        this.profilesMap = new SortedDictionary<int, Profile>();
    }

    public virtual void Add(Profile x)
    {
        profilesMap.Add(x);
    }
}

public class Profile
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

The key of the profilesMap is the profile order. Therefore, the HBM mappings are as follows:

<class name="User" table="User">
  <id name="Id" column="Id" type="integer">
    <generator class="native" />
  </id>
  <property name="Name" type="string" column="Name" />
  <map name="profilesMap" access="field.camelcase" table="User_Profile">
    <key column="User_Id" />
    <index column="`Order`" type="integer" />
    <many-to-many class="Profile" column="Profile_Id" />
  </map>
</class>
<class name="Profile" table="Profile">
  <id name="Id" column="Id" type="integer">
    <generator class="native" />
  </id>
  <property name="Name" type="string" column="Name" />
</class>

This works perfectly and creates the correct many-to-many table:

create table User_Profile (
   User_Id INT not null,
   Profile_Id INT not null,
   "Order" INT not null,
   primary key (User_Id, "Order"),
   constraint FK6BDEDC07D1EDE651 foreign key (Profile_Id) references Profile,
   constraint FK6BDEDC07650CB01 foreign key (User_Id) references User
)

However, I don't particularly like using HBM because it's not really refactor-friendly. Therefore, I'm trying to translate this to FluentNHibernate. This is my attempt at the user's many-to-many mapping:

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        this.Id();
        this.Map(o => o.Name);

        var mapMember = Reveal.Member<User, IEnumerable<KeyValuePair<int, Profile>>>("profilesMap");

        this.HasManyToMany<KeyValuePair<int, Profile>>(mapMember)
            .Access.CamelCaseField()
            .AsMap<int>("`Order`")
            .Table("User_Profile");
    }
}

I expected this to work, however it blows up when trying to build the session factory:

An association from the table User_Profile refers to an unmapped class: System.Collections.Generic.KeyValuePair`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[ConsoleApplication9.Profile, ConsoleApplication9, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

I did quite a lot of research on how to get AsMap to work and so I changed it to the following:

this.HasManyToMany<KeyValuePair<int, Profile>>(mapMember)
    .Access.CamelCaseField().AsMap<int>("`Order`")
    .Element("Profile_id", ep => ep.Type<int>()) // Added.
    .Table("User_Profile");

However, this produces an incorrect table by not including the foreign key (or not null constraint) from Profile_id:

create table User_Profile (
   User_id INT not null,
   Profile_id INT,
   "Order" INT not null,
   primary key (User_id, "Order"),
   constraint FK6BDEDC07650CB01 foreign key (User_id) references "User")

Additionally, it also blows up when trying to add a profile to a user:

var a = new User() { Name = "A" };
var b = new Profile() { Name = "B" };
a.Add(b);

session.Save(b);
session.Save(a);
session.Flush(); // Error: Unable to cast object of type 'ConsoleApplication9.Profile' to type 'System.IConvertible'.

So - I've been pulling my hair out for hours trying to determine how to properly map this relationship with FNH, but I just can't seem to get it. Simple many-to-many relationships seem easy, but when trying to add the index column, it doesn't seem to work. I would appreciate it if anyone is will to help me solve this problem.

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

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

发布评论

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

评论(1

帅哥哥的热头脑 2024-12-07 13:23:59

您看过类似问题的答案吗?

如何映射 IDictionary在 Fluent NHibernate 中

我看到的一个问题是在多对多中使用 Element。这可能就是为什么您没有为 profile_id 设置任何外键的原因。另外,如果可能的话,我会尝试为profilesMap 添加一个公共访问器。

为了匹配您的情况,我将按如下方式进行映射:

HasManyToMany<Profile>(ProfilesMap) //Assuming the addition of a public get accessor
  .Access.CamelCaseField()
  .ParentKeyColumn("User_Id")
  .ChildKeyColumn("Profile_Id")
  .Table("User_Profile")
  .AsMap<int>("Id");

如果您无法添加访问器,您可以尝试此操作

HasManyToMany<Profile>(Reveal.Member<User, object>("profilesMap"))
  .Table("User_Profile")
  .ParentKeyColumn("User_id")
  .ChildKeyColumn("Profile_id")
  .AsMap<int>("`Order`");

Have you seen this answer to a similar question?

How to map IDictionary<string, Entity> in Fluent NHibernate

One problem I see is the use of the Element in your manytomany. That's probably why you don't get any foreign key setup for profile_id. Also, if possible, I'd try adding a public accessor for profilesMap.

To match your case, I'd make your mapping as follows:

HasManyToMany<Profile>(ProfilesMap) //Assuming the addition of a public get accessor
  .Access.CamelCaseField()
  .ParentKeyColumn("User_Id")
  .ChildKeyColumn("Profile_Id")
  .Table("User_Profile")
  .AsMap<int>("Id");

If you can't add the accessor you can try this

HasManyToMany<Profile>(Reveal.Member<User, object>("profilesMap"))
  .Table("User_Profile")
  .ParentKeyColumn("User_id")
  .ChildKeyColumn("Profile_id")
  .AsMap<int>("`Order`");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文