我的架构如下所示:
Message.Id列是标识(1,1),MessageHeader表使用由关联的消息ID组成的组合密钥,以及唯一标识每条消息中标头的标题名称字段。
实体在代码中表示为:
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会:
我无法完成这项工作。它要么首先尝试插入MessageHeader(因外键违反而失败),要么尝试UPDATE MessageHeader而不是INSERTing它,它不返回任何行并抛出“无法使数据库状态与会话同步”错误。
我的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();
}
}
我认为将明确的版本时间戳添加到MessageHeader表会解决这个问题,但它看起来不会......我确定某些东西需要Inverse或Cascade或其他东西,但我完全难以理解需要什么去哪里。
谢谢,
迪伦
答案 0 :(得分:0)
这是在黑暗中拍摄,直到我可以到达我可以重现你的问题的机器......
您的HasMany
是否应该同时使用两列来引用标题?
根据您的Fluent NHibernate版本,它可能是:
map.HasMany(x=> x.Headers)
.KeyColumns.Add("MessageId", "HeaderName");
或
map.HasMany(x=> x.Headers)
.Key(ke =>
{
ke.Columns.Add("MessageId", "HeaderName");
});
答案 1 :(得分:0)
解决方案原来是 - 通过Twitter上的@mikehadlow - 我需要HasMany映射上的.Cascade.SaveUpdate():
public void Override(AutoMapping<Message> map) {
map.HasMany(message => message.Headers).KeyColumn("MessageId").Cascade.SaveUpdate()
}
但事实证明,代码中其他地方的非NH相关错误阻止了它正常工作。修复了错误,如上图所示映射了它,并且它有效。 MessageHeader上的Version属性很好用但不是必需的 - 如果省略它,NH将在插入/更新之前查询数据库以找出哪一个是必需的。