NHibernate Удалить многие-ко-многим родителям и детям - PullRequest
0 голосов
/ 13 января 2019

у меня 3 класса. Компания , Адрес и Офисы . Ниже приводится определение сущностей.

Компания:

public class Company: Identity
{
    public Company()
    {
        Offices = Offices ?? new List<Office>();
    }
    public virtual string Name { get; set; }
    public virtual IList<Office> Offices { get; set; }

    public virtual void AddOffice(Office office)
    {
        office.Company = this;
        Offices.Add(office);
    }
}

Адрес:

public class Address: Identity
{
    public Address()
    {
        CompanyOffices = CompanyOffices ?? new List<Office>();
    }
    public virtual string FullAddress { get; set; }
    public virtual IList<Office> CompanyOffices { get; set; }
}

Офис

public class Office: Identity
{
    public Office()
    {
        Company = Company ?? new Company();
        Address = Address ?? new Address();
    }
    public virtual Company Company { get; set; }
    public virtual Address Address { get; set; }
    public virtual bool IsHeadOffice { get; set; }
}

Теперь для этих классов у меня есть следующее Mapping.

Отображение компании:

public class CompanyMapping: IdentityMapping<Company>
{
    public CompanyMapping()
    {
        Map(x => x.Name);
        HasMany(x => x.Offices).KeyColumn("CompanyId").Inverse().Cascade.AllDeleteOrphan();
    }
}

Отображение адресов:

public class AddressMapping: IdentityMapping<Address>
{
    public AddressMapping()
    {
        Map(x => x.FullAddress);
        HasMany(x => x.CompanyOffices).KeyColumn("AddressId").Inverse().Cascade.All();
    }
}

Office Mapping:

public class OfficeMapping: IdentityMapping<Office>
{
    public OfficeMapping()
    {
        Map(x => x.IsHeadOffice);
        References(x => x.Company).Column("CompanyId").Cascade.None();
        References(x => x.Address).Column("AddressId").Cascade.All();
    }
}

Код теста:

var sessionFactory = CreateSessionFactory();
        using (var session = sessionFactory.OpenSession())
        {
            using (var transaction = session.BeginTransaction())
            {
                var companyOne = new Company { Name = "Company One" };
                var companyTwo = new Company { Name = "Company Two" };

                var addressOne = new Address { FullAddress = "Address One" };
                var addressTwo = new Address { FullAddress = "Address Two" };
                var officeOne = new Office { Company = companyOne, Address = addressOne, IsHeadOffice = true };
                var officeTwo = new Office { Company = companyTwo, Address = addressTwo, IsHeadOffice = false };
                var officeThr = new Office { Company = companyOne, Address = addressTwo, IsHeadOffice = true };

                companyOne.AddOffice(officeOne);
                companyTwo.AddOffice(officeTwo);
                companyOne.AddOffice(officeThr);

                session.SaveOrUpdate(companyOne);
                session.SaveOrUpdate(companyTwo);
                transaction.Commit();
            }
        }

        using (var session = sessionFactory.OpenSession())
        {
            using (var transaction = session.BeginTransaction())
            {
                var companyOne = session.Get<Company>((long)1);
                session.Delete(companyOne);
                transaction.Commit();
            }
        }

Код Описание: Здесь у компании будет несколько офисов. Office - это отношение многих ко многим компании и адреса, но из-за того, что может быть много других столбцов (собственные данные Office), я изменил отношение со многих ко многим на 2 один ко многим.

Вопрос: Я хочу, чтобы моя заявка удаляла любой адрес, оставшийся сиротой при удалении компании. Но в этом случае, когда я удаляю свою компанию, она также удалит и ее адрес. Но он не проверяет, является ли адрес сиротой. Если есть другая ссылка на адрес, она все равно будет удалена. Согласно приведенному выше тестовому коду, он должен удалить «Company One» и «Address One», но не «Address Two», поскольку он не является сиротой. Но он также удаляет «Адрес Два».

Пожалуйста, кто-нибудь может дать мне знать что не так с приведенным выше отображением?

1 Ответ

0 голосов
/ 15 января 2019

Я не уверен, что если NHibernate выполняет глобальную проверку для DeleteOrphan или только для проверки Session, то настоящая глобальная проверка, конечно, будет включать запрос БД. Но здесь это на самом деле не имеет значения, причина существования DeleteOrphan заключается в том, что когда вы разъединяете сущности с родителями (например, удаляете элемент из коллекции, затем вызываете Update на родителе), но вы вызываете операцию на верхнем уровне сущность, которая идет прямо вниз.

То, что действительно происходит тогда, это то, что вы вызываете Delete на Company, в соответствии с отображением на Offices, то есть компонентом All этого, таким образом, каждый дочерний элемент в коллекции Offices имеет Delete вызвал его, потому что вы позвонили Delete на родителя Company.

Поскольку отображение для Office также имеет дочерний элемент Address, который также отображается All, и Office только что вызвал Delete, поэтому он будет вызывать Delete непосредственно для своего Address child, так как прямой Delete не заботится о других ассоциациях или нет (если только Session или DB не говорит об этом), Address просто удаляется из DB.


Если вы не можете изменить структуру вашей сущности здесь, то вам придется либо остановить Delete достижение не потерянных Address es (сначала отключить их вручную), либо вообще прекратить каскадное Delete к Address, затем управлять Address удалением полностью вручную.

Я уверен, что есть некоторые более совершенные структуры сущностей, которые могут лучше справляться с этими отношениями, если у вас есть гибкость: P

...