使用Fluent NHibernate更新实体,删除多对多关系中的关联

使用Fluent NHibernate更新实体,删除多对多关系中的关联,nhibernate,fluent-nhibernate,mapping,many-to-many,Nhibernate,Fluent Nhibernate,Mapping,Many To Many,我有两个这样的实体: 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 v

我有两个这样的实体:

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();
    }
}
提交时,我收到以下错误消息:

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
这里有我遗漏的东西吗


谢谢大家!

将级联声明为
Cascade.AllDeleteOrphan()
。另外,尝试将
.Inverse()
添加到多对多映射之一

更多信息:

来自NHibernate文档


编辑:

根据您得到的错误判断,您只需要初始化类别的
CategoryDescEn
属性,然后再尝试保存它。您尝试保存时,似乎是
null

not null属性引用一个null或瞬时值 ilu.src.Entities.Category.CategoryDesk


谢谢你的帮助。我将
.Cascade.None().Inverse()
添加到CategoryMap,将
.Cascade.AllDeleteOrphan()
添加到ServiceMap,因为我只为服务更新类别,对吗?但当我更新服务时,我收到一条消息,
notnull属性引用类别属性上的null或瞬态值,这是怎么回事?不确定。显然,其中一个外键对象为null。当您离开
类别映射上的
.Cascade.SaveUpdate()
时会发生什么?你能说出哪个属性抛出错误吗?另外,如果你能用一个完整的映射更新你的帖子可能会有帮助。我已经解决了我的问题,实际上不是你告诉我的方式,但是你的回答对我帮助很大!谢谢你!好天气;)
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