1

私はこのような2つのエンティティを持っています:

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; }
}

これら2つのエンティティの関係は、マッピングと多対多です。

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

ここで足りないものはありますか?

ありがとうございました!

4

1 に答える 1

2

カスケードをとして宣言しCascade.AllDeleteOrphan()ます。.Inverse()また、多対多のマッピングの1つに追加してみてください。

いくつかの詳細情報:

NHibernateドキュメントからの双方向の関連付け
NHibernateの落とし穴:多対多および逆
NHibernateカスケード:すべて、all-delete-orphans、およびsave-updateの違い


編集:

CategoryDescEn発生したエラーから判断すると、カテゴリを保存する前に、カテゴリのプロパティを初期化する必要があります。null保存しようとしたときのようです:

not-nullプロパティは、nullまたは一時的な値ilu.src.Entities.Categoryを参照します。CategoryDe​​scEn

于 2012-06-26T11:34:29.680 に答える