从asp.net POST动作方法更新nhibernate实体的正确方法是什么?

Wil*_*ean 8 nhibernate asp.net-mvc

我是nHibernate的新手,并且试图通过正确的方式从Web应用程序表单POST更新分离的对象.(我们使用的是ASP.NET MVC)

我正在尝试更新的对象包含(除其他外)IList的子对象,映射的内容如下:

<bag name="PlannedSlices" inverse="true" cascade="all-delete-orphan">
      <key column="JobNumber" />
      <one-to-many class="SliceClass" />
</bag>
Run Code Online (Sandbox Code Playgroud)

我们已经安排了我们的MVC编辑视图表单,以便当它被回发时,我们的操作方法被传递给对象(包括子项的List <>.我们通过表单正确地往返所有实体ID.

我们对post动作方法的天真尝试执行session.SaveOrUpdate(parentObject),其中parentObject已被默认的modelbinder从视图表单中删除.

对于以下任何一种情况,这似乎都可以正常工作:

  • 创建新的父对象
  • 修改父级的属性
  • 添加新的子对象
  • 修改现有的子对象(查看nHibernate日志,我可以看到它正确建立对象是新的还是现有的,并发出适当的UPDATE或INSERT)

失败的方案是: - 删除子对象 - 即如果它们不在IList中,则不会从数据库中删除它们.没有例外或任何事情,他们只是不被删除.

我的理解是,这是因为nHibernate执行创建需要删除的子列表的魔力不适用于分离的实例.

我无法找到一个简单的例子,说明使用nHibernate这种行为方法应该是什么样的(即使用模型绑定器对象作为分离的nHibernate实例) - 基于MS EF的示例(例如http:// stephenwalther. com/blog/archive/2009/02/27/chapter-5-understanding-models.aspx)似乎使用方法'ApplyPropertyChanges'将已更改的属性从模型绑定对象复制到重新加载的实体实例.

所以,在这之后,问题很简单 - 如果我有模型绑定器给我一个包含子对象集合的新对象,我应该如何通过nHibernate更新它(其中'update'包括可能删除子节点)?

小智 4

这是一个我认为你想做的事情的例子。如果我误解了您想要做的事情,请告诉我。

给定以下“域”类:

public class Person
{
    private IList<Pet> pets;

    protected Person()
    { }

    public Person(string name)
    {
        Name = name;
        pets = new List<Pet>();
    }

    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IEnumerable<Pet> Pets
    {
        get { return pets; }
    }

    public virtual void AddPet(Pet pet)
    {
        pets.Add(pet);
    }

    public virtual void RemovePet(Pet pet)
    {
        pets.Remove(pet);
    }
}

public class Pet
{
    protected Pet()
    { }

    public Pet(string name)
    {
        Name = name;
    }

    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

通过以下映射:

   public class PersonMap : ClassMap<Person>
    {
        public PersonMap()
        {
            LazyLoad();
            Id(x => x.Id).GeneratedBy.GuidComb();
            Map(x => x.Name);
            HasMany(x => x.Pets)
                   .Cascade.AllDeleteOrphan()
                   .Access.AsLowerCaseField()
                   .SetAttribute("lazy", "false");
        }
    }

    public class PetMap : ClassMap<Pet>
    {
        public PetMap()
        {
            Id(x => x.Id).GeneratedBy.GuidComb();
            Map(x => x.Name);
        }
    }
Run Code Online (Sandbox Code Playgroud)

本次测试:

    [Test]
    public void CanDeleteChildren()
    {
        Person person = new Person("joe");

        Pet dog = new Pet("dog");
        Pet cat = new Pet("cat");

        person.AddPet(dog);
        person.AddPet(cat);

        Repository.Save(person);

        UnitOfWork.Commit();

        CreateSession();
        UnitOfWork.BeginTransaction();

        Person retrievedPerson = Repository.Get<Person>(person.Id);
        Repository.Evict(retrievedPerson);

        retrievedPerson.Name = "Evicted";

        Assert.AreEqual(2, retrievedPerson.Pets.Count());
        retrievedPerson.RemovePet(retrievedPerson.Pets.First());

        Assert.AreEqual(1, retrievedPerson.Pets.Count());

        Repository.Save(retrievedPerson);

        UnitOfWork.Commit();

        CreateSession();
        UnitOfWork.BeginTransaction();

        retrievedPerson = Repository.Get<Person>(person.Id);
        Assert.AreEqual(1, retrievedPerson.Pets.Count());
    }
Run Code Online (Sandbox Code Playgroud)

运行并生成以下sql:

DeletingChildrenOfEvictedObject.CanDeleteChildren : 通过 NHibernate: INSERT INTO [Person] (Name, Id) VALUES (@p0, @p1); @p0 = '乔', @p1 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate: INSERT INTO [Pet] (Name, Id) VALUES (@p0, @p1); @p0 = '狗',@p1 = '464e59c7-74d0-4317-9c22-9bf801013abb'

NHibernate: INSERT INTO [Pet] (Name, Id) VALUES (@p0, @p1); @p0 = '猫',@p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'

NHibernate: UPDATE [Pet] SET Person_id = @p0 WHERE Id = @p1; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2', @p1 = '464e59c7-74d0-4317-9c22-9bf801013abb'

NHibernate: UPDATE [Pet] SET Person_id = @p0 WHERE Id = @p1; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2', @p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'

NHibernate:从 [Person] person0_ WHERE person0_.Id=@p0 中选择 person0_.Id 作为 Id5_0_,person0_.Name 作为 Name5_0_;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate:选择 pets0_.Person_id 作为 Person3_1_,pets0_.Id 作为 Id1_,pets0_.Id 作为 Id6_0_,pets0_.Name 作为 Name6_0_ FROM [Pet] pets0_ WHERE pets0_.Person_id=@p0; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate:更新[人] SET 名称 = @p0 其中 Id = @p1;@p0 = '被驱逐', @p1 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate: 更新 [Pet] SET 名称 = @p0 其中 Id = @p1; @p0 = '狗',@p1 = '464e59c7-74d0-4317-9c22-9bf801013abb' NHibernate:更新[Pet] SET Person_id = null,其中Person_id = @p0 AND Id = @p1;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2', @p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'

NHibernate:从 [Pet] 删除,其中 Id = @p0;@p0 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'

NHibernate:从 [Person] person0_ WHERE person0_.Id=@p0 中选择 person0_.Id 作为 Id5_0_,person0_.Name 作为 Name5_0_;@p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate:选择 pets0_.Person_id 作为 Person3_1_,pets0_.Id 作为 Id1_,pets0_.Id 作为 Id6_0_,pets0_.Name 作为 Name6_0_ FROM [Pet] pets0_ WHERE pets0_.Person_id=@p0; @p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

请注意从 [Pet] 中删除...

因此,您需要做的就是使用修改后的集合对 Person 对象(在本例中)进行 nhibernate,它应该能够确定要删除的内容。确保您已设置 Cascade.AllDeleteOrphan() 属性。