我有两个这样的实体:
public class Service
{
public virtual int ServiceId { get; set; }
public virtual char LayoutCode { get; set; }
public virtual string ServiceNameEn { get; set; }
public virtual string ServiceNameTh { get; set; }
public virtual string ServiceDescEn { get; set; }
public virtual string ServiceDescTh { get; set; }
public virtual string ServicePhone { get; set; }
public virtual byte[] ServiceImage { get; set; }
public virtual bool Permanent { get; set; }
public virtual bool Active { get; set; }
public virtual bool IsAutoAssign { get; set; }
public virtual DateTime CreatedDatetime { get; set; }
public virtual DateTime LastUpdatedDatetime { get; set; }
public virtual string RedirectUrl { get; set; }
public virtual IList<Reply> Replies { get; set; }
public virtual IList<Employee> Employees { get; set; }
public virtual IList<ServicesOfUser> ServicesOfUser { get; set; }
private IList<Category> _categories = new List<Category>();
public virtual IEnumerable<Category> Categories
{
get
{
return _categories;
}
}
public virtual void Add(Category category)
{
if (!_categories.Any(x => x.CategoryId == category.CategoryId))
{
_categories.Add(category);
}
}
public virtual void Clear()
{
_categories.Clear();
}
}
和
public class Category
{
public virtual int CategoryId { get; set; }
public virtual string CategoryNameEn { get; set; }
public virtual string CategoryNameTh { get; set; }
public virtual string CategoryDescEn { get; set; }
public virtual string CategoryDescTh { get; set; }
public virtual byte[] CategoryImage { get; set; }
public virtual bool Active { get; set; }
public virtual DateTime CreatedDatetime { get; set; }
public virtual DateTime LastUpdatedDatetime { get; set; }
public virtual IList<Service> Services { get; set; }
}
这两个实体的关系是多对多的映射:
public class ServiceMap : ClassMap<Service>
{
public ServiceMap()
{
Table("[SERVICES]");
Id(x => x.ServiceId)
.GeneratedBy.Identity()
.Column("service_id")
.CustomType("int")
.Access.Property()
.CustomSqlType("int")
.Not.Nullable();
Map(x => x.LayoutCode)
.Column("layout_code")
.CustomType("char")
.Access.Property()
.CustomSqlType("char")
.Length(1)
.Not.Nullable();
Map(x => x.ServiceNameEn)
.Column("service_name_en")
.Access.Property()
.CustomType("string")
.CustomSqlType("varchar")
.Length(128)
.Not.Nullable();
Map(x => x.ServiceNameTh)
.Column("service_name_th")
.Access.Property()
.CustomType("string")
.CustomSqlType("nvarchar")
.Length(128)
.Not.Nullable();
Map(x => x.ServiceDescEn)
.Column("service_desc_en")
.CustomType("string")
.Access.Property()
.CustomSqlType("varchar")
.Length(4000)
.Nullable();
Map(x => x.ServiceDescTh)
.Column("service_desc_th")
.CustomType("string")
.Access.Property()
.CustomSqlType("nvarchar")
.Length(4000)
.Nullable();
Map(x => x.ServicePhone)
.Column("service_phone")
.Access.Property()
.CustomType("string")
.CustomSqlType("nvarchar")
.Length(50)
.Nullable();
Map(x => x.ServiceImage)
.Column("service_image")
.CustomType("BinaryBlob")
.Access.Property()
.Generated.Never()
.CustomSqlType("image")
.Length(131231)
.Nullable();
Map(x => x.Permanent)
.Column("permanent")
.CustomType("bool")
.Access.Property()
.CustomSqlType("bit")
.Not.Nullable();
Map(x => x.Active)
.Column("active")
.CustomType("bool")
.Access.Property()
.CustomSqlType("bit")
.Not.Nullable();
Map(x => x.IsAutoAssign)
.Column("is_auto_assign")
.CustomType("bool")
.Access.Property()
.CustomSqlType("bit")
.Not.Nullable();
Map(x => x.CreatedDatetime)
.Column("created_datetime")
.Access.Property()
.CustomType("DateTime")
.CustomSqlType("datetime")
.Not.Nullable();
Map(x => x.LastUpdatedDatetime)
.Column("last_updated_datetime")
.Access.Property()
.CustomType("DateTime")
.CustomSqlType("datetime")
.Not.Nullable();
Map(x => x.RedirectUrl)
.Column("redirect_url")
.Access.Property()
.CustomType("string")
.CustomSqlType("nvarchar")
.Length(213123)
.Nullable();
HasMany<ServicesOfUser>(x => x.ServicesOfUser)
.AsBag()
.Cascade.None()
.LazyLoad()
.Inverse()
.KeyColumns.Add("service_id", mapping => mapping.Name("service_id")
.SqlType("int")
.Nullable());
HasMany<Reply>(x => x.Replies)
.AsBag()
.Cascade.None()
.LazyLoad()
.Inverse()
.KeyColumns.Add("send_to_service_id", mapping => mapping.Name("send_to_service_id")
.SqlType("int")
.Nullable());
HasManyToMany<Employee>(x => x.Employees)
.AsBag()
.Cascade.None()
.LazyLoad()
.Table("SERVICE_MONITORS")
.Inverse()
.ChildKeyColumns.Add("employee_id", mapping => mapping.Name("employee_id")
.SqlType("uniqueidentifier")
.Not.Nullable())
.ParentKeyColumns.Add("service_id", mapping => mapping.Name("service_id")
.SqlType("int")
.Not.Nullable());
HasManyToMany<Category>(x => x.Categories)
.AsBag()
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.AllDeleteOrphan()
.Table("SERVICES_IN_CATEGORIES")
.ChildKeyColumns.Add("category_id", mapping => mapping.Name("category_id")
.SqlType("int")
.Not.Nullable())
.ParentKeyColumns.Add("service_id", mapping => mapping.Name("service_id")
.SqlType("int")
.Not.Nullable());
}
}
和
public class CategoryMap : ClassMap<Category>
{
public CategoryMap()
{
Table("[SERVICE_CATEGORIES]");
Id(x => x.CategoryId)
.GeneratedBy.Identity()
.Column("category_id")
.CustomType("int")
.Access.Property()
.CustomSqlType("int")
.Not.Nullable();
Map(x => x.CategoryNameEn)
.Column("category_name_en")
.CustomType("string")
.Access.Property()
.CustomSqlType("varchar")
.Length(128)
.Not.Nullable();
Map(x => x.CategoryNameTh)
.Column("category_name_th")
.CustomType("string")
.Access.Property()
.CustomSqlType("nvarchar")
.Length(128)
.Not.Nullable();
Map(x => x.CategoryDescEn)
.Column("category_desc_en")
.CustomType("string")
.Access.Property()
.CustomSqlType("varchar")
.Length(3423423)
.Not.Nullable();
Map(x => x.CategoryDescTh)
.Column("category_desc_th")
.CustomType("string")
.Access.Property()
.CustomSqlType("nvarchar")
.Length(3243234)
.Not.Nullable();
Map(x => x.CategoryImage)
.Column("category_image")
.CustomType("BinaryBlob")
.Access.Property()
.Generated.Never()
.CustomSqlType("image")
.Length(131231)
.Nullable();
Map(x => x.Active)
.Column("active")
.CustomType("bool")
.Access.Property()
.CustomSqlType("bit")
.Not.Nullable();
Map(x => x.CreatedDatetime)
.Column("created_datetime")
.Access.Property()
.CustomType("DateTime")
.CustomSqlType("datetime")
.Not.Nullable();
Map(x => x.LastUpdatedDatetime)
.Column("last_updated_datetime")
.Access.Property()
.CustomType("DateTime")
.CustomSqlType("datetime")
.Not.Nullable();
HasManyToMany<Service>(x => x.Services)
.AsBag()
.Cascade.AllDeleteOrphan()
.Inverse()
.LazyLoad()
.Table("SERVICES_IN_CATEGORIES")
.ChildKeyColumns.Add("service_id", mapping => mapping.Name("service_id")
.SqlType("int")
.Not.Nullable())
.ParentKeyColumns.Add("category_id", mapping => mapping.Name("category_id")
.SqlType("int")
.Not.Nullable());
}
}
编码:
using (unitOfWork = new UnitOfWork(SessionFactory))
{
serviceRepo = new ServiceRepo(unitOfWork.Session);
try
{
Service service = new Service();
if (id != null)
service = serviceRepo.GetById((int)id);
// set values for service here
IList<Category> categories = new List<Category>();
// add some categories to service
serviceRepo.Save(service);
unitOfWork.Commit();
return service;
}
catch (Exception ex)
{
unitOfWork.Rollback();
return null;
}
}
服务已更新,但联系表中的关联记录不会被删除。
如果我在向服务添加类别之前添加以下代码:
service.Clear();
提交时,我收到以下错误消息:
not-null property references a null or transient value ilu.src.Entities.Category.CategoryDescEn
完整堆栈跟踪:
at NHibernate.Engine.Nullability.CheckNullability(Object[] values, IEntityPersister persister, Boolean isUpdate)
at NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource session, Object entity, EntityEntry entityEntry, Boolean isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet transientEntities)
at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event, ISet transientEntities)
at NHibernate.Impl.SessionImpl.Delete(String entityName, Object child, Boolean isCascadeDeleteEnabled, ISet transientEntities)
at NHibernate.Engine.CascadingAction.DeleteCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeToOne(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type)
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
at NHibernate.Event.Default.DefaultDeleteEventListener.CascadeBeforeDelete(IEventSource session, IEntityPersister persister, Object entity, EntityEntry entityEntry, ISet transientEntities)
at NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource session, Object entity, EntityEntry entityEntry, Boolean isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet transientEntities)
at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event, ISet transientEntities)
at NHibernate.Impl.SessionImpl.Delete(String entityName, Object child, Boolean isCascadeDeleteEnabled, ISet transientEntities)
at NHibernate.Engine.CascadingAction.DeleteCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeToOne(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type)
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
at NHibernate.Event.Default.DefaultDeleteEventListener.CascadeBeforeDelete(IEventSource session, IEntityPersister persister, Object entity, EntityEntry entityEntry, ISet transientEntities)
at NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource session, Object entity, EntityEntry entityEntry, Boolean isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet transientEntities)
at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event, ISet transientEntities)
at NHibernate.Impl.SessionImpl.Delete(String entityName, Object child, Boolean isCascadeDeleteEnabled, ISet transientEntities)
at NHibernate.Engine.Cascade.DeleteOrphans(String entityName, IPersistentCollection pc)
at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type)
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
at NHibernate.Event.Default.AbstractFlushingEventListener.CascadeOnFlush(IEventSource session, IEntityPersister persister, Object key, Object anything)
at NHibernate.Event.Default.AbstractFlushingEventListener.PrepareEntityFlushes(IEventSource session)
at NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent event)
at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
at NHibernate.Impl.SessionImpl.Flush()
at NHibernate.Transaction.AdoTransaction.Commit()
at ilu.src.Common.UnitOfWork.Commit() in D:\Arunsawad\iLertU\ilu\ilu\src\Common\UnitOfWork.cs:line 41
at ilu.Controllers.AdminController.SaveService(Nullable`1 id, String name, String nameth, String desc, String descth, String phone, String catids, String url, Char layoutcode, Boolean permanent, Boolean active, Boolean autoassign) in D:\Arunsawad\iLertU\ilu\ilu\Controllers\AdminController.cs:line 107
这里有什么我想念的吗?
谢谢!
答案 0 :(得分:2)
将级联声明为Cascade.AllDeleteOrphan()
。另外,尝试将.Inverse()
添加到多对多映射之一。
更多信息:
来自NHibernate文档的 Bidirectional associations
NHibernate Pitfalls: Many to Many and Inverse
NHibernate Cascades: the different between all, all-delete-orphans and save-update
修改强>
根据您获得的错误判断,您只需要在尝试保存之前初始化该类别的CategoryDescEn
属性。您尝试保存时似乎是null
:
not-null属性引用 null 或瞬态值 ilu.src.Entities.Category。的 CategoryDescEn 强>