我很难理解为什么当我从 MyUser.Settings 和 SAVE MyUser 中删除子 Settings 对象时,我会收到如下 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 命令。但是,它所做的是更新 Settings 对象的相关行,将 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);
这给出了错误:字典中不存在给定的键
所以尝试添加第二个键列:
mapping.HasMany(m => m.Settings)
.KeyColumn("MyUserId")
.KeyColumn("SettingTypeId")
.Inverse()
.Cascade.DeleteOrphan()
.Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
但是,当从数据库中为给定的 MyUserId 加载设置集合时,这会导致奇怪的行为。查看 nh 探查器,我看到第二个 SELECT ... FROM Settings,但将 SettingTypeId 设置为与 MyUserId 的值相同。
还是完全一头雾水。花了我太多时间,所以要恢复到向设置实体添加主键 id 字段。也许你不能做我正在尝试使用 NHibernate 的事情。在纯 SQL 中,这很简单。