Моя схема выглядит так:
Столбец Message.Id является идентификатором (1,1), а таблица MessageHeader использует составной ключ, состоящий из связанного идентификатора сообщения и поля имени заголовка, которое однозначно идентифицирует заголовок в каждом сообщении.
Объекты представлены в коде как:
public class Message {
public virtual int Id { get; set; }
public virtual string Sender { get; set; }
public virtual string Recipient { get; set; }
private IList<MessageHeader> headers = new List<MessageHeader>();
public virtual IList<MessageHeader> Headers {
get { return headers; }
set { headers = value; }
}
public virtual void SetHeader(string headerName, string headerText) {
MessageHeader header = this.Headers.FirstOrDefault(h => h.HeaderName == headerName);
if (header == default(MessageHeader)) {
header = new MessageHeader() {
HeaderName = headerName,
Message = this
};
this.Headers.Add(header);
header.HeaderText = headerText;
}
}
}
public class MessageHeader {
public virtual Message Message { get; set; }
public virtual string HeaderName { get; set; }
public virtual string HeaderText { get; set; }
public virtual byte[] Version { get; set; }
public override bool Equals(object obj) {
if (Object.Equals(this, obj)) return (true);
var that = obj as MessageHeader;
if (that == null) return (false);
return (this.HeaderName == that.HeaderName && this.Message.Equals(that.Message));
}
public override int GetHashCode() {
return (this.HeaderName.GetHashCode() ^ this.Message.GetHashCode());
}
}
Я хочу отобразить эти объекты, используя Fluent NHibernate, чтобы при запуске кода, например:
var message = new Message() { Sender = "alf", Recipient = "bob" };
message.SetHeader("DateSent", DateTime.Now.ToString());
using (var session = NHibernateHelper.GetCurrentSession()) {
using(var tx = session.BeginTransaction()) {
session.Save(message);
tx.Commit();
}
}
NHibernate будет:
- ВСТАВИТЬ сущность Message и получить значение идентификатора.
- ВСТАВИТЬ сущность MessageHeader (с соответствующим MessageId, полученным на шаге 1)
Я не могу заставить эту работу. Он либо пытается сначала вставить MessageHeader (который завершается неудачно с нарушением внешнего ключа), либо пытается ОБНОВИТЬ MessageHeader вместо ВСТАВКИ его, что не возвращает строк и выдает ошибку «Не удалось синхронизировать состояние базы данных с сеансом». *
Мои переопределения отображения FluentNH следующие:
public class MessageOverrides : IAutoMappingOverride<Message> {
public void Override(AutoMapping<Message> map) {
map.HasMany(message => message.Headers).KeyColumn("MessageId");
}
}
public class MessageHeaderOverrides : IAutoMappingOverride<MessageHeader> {
public void Override(AutoMapping<MessageHeader> map) {
map.IgnoreProperty(header => header.Message);
map.CompositeId()
.KeyReference(header => header.Message, "MessageId")
.KeyProperty(header => header.HeaderName);
map.Version(header => header.Version)
.CustomSqlType("timestamp").Nullable()
.Generated.Always();
}
}
Я думал, что добавление явной метки времени Version в таблицу MessageHeader решит эту проблему, но это не так ... Я уверен, что что-то должно быть Inverse или Cascade или что-то еще, но я совершенно озадачен тем, что иди куда.
Спасибо
Dylan