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 = нейтральный, PublicKeyToken = b77a5c561934e089], [ConsoleApplication9. Профиль, ConsoleApplication9, версия = 1.0.0.0, культура = нейтральная, PublicKeyToken = ноль]]
Я провел довольно много исследований о том, как заставить AsMap
работать, и поэтому я изменил его на следующее:
this.HasManyToMany<KeyValuePair<int, Profile>>(mapMember)
.Access.CamelCaseField().AsMap<int>("`Order`")
.Element("Profile_id", ep => ep.Type<int>()) // Added.
.Table("User_Profile");
Однако при этом получается неверная таблица , включая внешний ключ (или ненулевое ограничение) из 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, но я просто не могу этого понять. Простые отношения «многие ко многим» кажутся простыми, но при попытке добавить столбец индекса это не работает. Буду признателен, если кто-нибудь захочет помочь мне решить эту проблему.