MyUser.Settings から子設定オブジェクトを削除して MyUser を保存すると、次のような SQL エラーが発生する理由を理解するのに苦労しています。
Cannot insert the value NULL into column 'MyUserId', table '###.Settings'; column does not allow nulls. UPDATE fails.
The statement has been terminated.
コレクションからアイテムを削除してから MyUser を保存すると、NHibernate が特定の子に対して DELETE コマンドを発行することが予想されます。ただし、設定オブジェクトの関連行を更新し、MyUserId を NULL に設定します。これは、複合キーを使用しているため許可されません。
Inverse() とさまざまな Cascade オプションの非常に多くの組み合わせを試しましたが、何も機能していないようです。MyUser を保存すると、コレクションへの追加が完全に機能することを指摘しておく必要があります。
私は完全に困惑しています!
以下は、私のエンティティとマッピングを試して説明するための擬似コードです。
public class SettingType
{
public virtual int SettingTypeId { get; set; }
public virtual string Name { get; set; }
public virtual bool Active { get; set; }
}
public class Setting
{
public virtual MyUser MyUser { get; set; }
public virtual SettingType SettingType { get; set; }
public virtual DateTime Created { get; set; }
}
public class MyUser
{
public virtual int MyUserId { get; set; }
public virtual IList<Setting> Settings { get; set; }
public virtual string Email { get; set; }
public void AddSetting(SettingType settingType, DateTime now)
{
var existing = _settings.SingleOrDefault(s => s.SettingType.SettingTypeId == settingType.SettingTypeId);
if (existing != null)
{
existing.Updated = now;
}
else
{
var setting = new Setting
{
MyUser = this,
SettingType = settingType,
Created = now,
};
_settings.Add(setting);
}
}
public void RemoveSetting(SettingType settingType)
{
var existingPref = _settings.SingleOrDefault(s => s.SettingType.SettingTypeId == settingType.SettingTypeId);
if (existingPref != null)
{
_settings.Remove(existingPref);
}
}
private readonly IList<Setting> _settings = new List<Setting>();
}
そして私のマッピング:
public class SettingTypeMap : IAutoMappingOverride<SettingType>
{
public void Override(AutoMapping<SettingType> mapping)
{
mapping.Table("SettingTypes");
mapping.Id(m => m.SettingTypeId).GeneratedBy.Identity();
mapping.Map(m => m.Name).Not.Nullable().Length(100);
mapping.Map(m => m.Active).Not.Nullable().Default("0");
}
}
public class SettingMap : IAutoMappingOverride<Setting>
{
public void Override(AutoMapping<Setting> mapping)
{
mapping.Table("Settings");
mapping.CompositeId()
.KeyReference(m => m.MyUser)
.KeyReference(m => m.SettingType);
mapping.Map(m => m.Created).Not.Nullable().Default("CURRENT_TIMESTAMP");
mapping.Map(m => m.Updated).Nullable();
}
}
public class MyUserMappingOverride : IAutoMappingOverride<MyUser>
{
public void Override(AutoMapping<MyUser> mapping)
{
mapping.Table("MyUsers");
mapping.Id(m => m.MyUserId).GeneratedBy.Identity();
mapping.Map(m => m.Email).Not.Nullable().Length(200);
mapping.HasMany(m => m.Settings).KeyColumn("MyUserId").Cascade.DeleteOrphan()
.Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
}
}
すべて使用:
FluentNHibernate v1.3.0.733
NHibernate v3.3.1.4000
更新: いくつかの提案の後、MyUser エンティティのマッピングを変更しようとしました。
まずこれに:
mapping.HasMany(m => m.Settings)
.KeyColumn("MyUserId")
.Inverse()
.Cascade.DeleteOrphan()
.Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
これにより、エラーが発生します:指定されたキーが辞書に存在しませんでした
したがって、2番目のキー列を追加しようとしました:
mapping.HasMany(m => m.Settings)
.KeyColumn("MyUserId")
.KeyColumn("SettingTypeId")
.Inverse()
.Cascade.DeleteOrphan()
.Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
しかし、これにより、特定の MyUserId の DB から設定コレクションをロードするときに、奇妙な動作が発生します。nh プロファイラーを見ると、2 番目の SELECT ... FROM Settings が表示されますが、SettingTypeId が MyUserId の値と同じに設定されています。
まだ完全に困惑しています。時間がかかりすぎたので、主キー ID フィールドを設定エンティティに追加することに戻ります。NHibernate を使用して私が試みていることを実行できないだけかもしれません。純粋な SQL では、これは簡単です。