Коллекция не выбрана с помощью NHibernate-Caching

У меня есть следующие сущности:

Лицо Компания

И затем есть сущность PersonCompany, которая устанавливает связь между человеком и компанией.

Отображение для человека:

public class PersonMap : SubclassMap<Person> {
    public PersonMap() {
        this.Table("Person");
        this.KeyColumn("Id");
        this.HasMany(x => x.PersonCompanys).AsSet().KeyColumn("PersonId").Fetch.Select().Inverse().Cascade.Delete();
    }
}

Компания:

public class CompanyMap : SubclassMap<Company> {
    public CompanyMap() {
        this.Table("Company");
        this.KeyColumn("Id");
        this.HasMany(x => x.PersonCompanys).AsSet().KeyColumn("CompanyId").Fetch.Select().Inverse().Cascade.None();
    }
}

и PersonCompany:

public class PersonCompanyMap : ClassMap<PersonCompany> {
    public PersonCompanyMap() {
        this.Table("PersonCompany");

        this.Version(x => x.ObjectVersion);
        this.Id(x => x.Id).GeneratedBy.Assigned();
        this.References(x => x.Company).Column("CompanyId").Fetch.Select();
        this.References(x => x.Person).Column("PersonId").Fetch.Select();
    }
}

Кэширование второго уровня активируется в общем и для каждого объекта с соглашениями. Также кеширование для PersonCompanys-Collection:

public class CachableConventions : IClassConvention, IHasManyConvention, IHasManyToManyConvention {
    private static readonly Type[] notCachableTypes = new[] {typeof(Word), typeof(ActivityWord), typeof(DbVersion), typeof(Deleted), typeof(ExchangeSyncState), typeof(Synchronizer), typeof(SerialletterField)};

    public void Apply(IClassInstance instance) {
        if (Array.IndexOf(notCachableTypes, instance.EntityType) >= 0) {
            return;
        }
        instance.Cache.ReadWrite();
    }

    public void Apply(IManyToManyCollectionInstance instance) {
        if (Array.IndexOf(notCachableTypes, instance.ChildType) >= 0) {
            return;
        }
        instance.Cache.ReadWrite();
    }
    public void Apply(IOneToManyCollectionInstance instance) {
        if (Array.IndexOf(notCachableTypes, instance.ChildType) >= 0) {
            return;
        }
        instance.Cache.ReadWrite();
    }
}

Теперь я создаю нового человека и сохраняю новую компанию, а затем добавляю запись PersonCompany-Record в коллекцию PersonCompanies.

Когда я выберу созданного человека, PersonCompanys-Collection будет пустым. Когда я делаю то же самое без SecondLevel-Caching, PersonCompanys-Collection содержит созданную сущность.

Кто-нибудь знает, что здесь может пойти не так?

Изменить — Дополнительная информация:

Эти шаги вызывают проблему:

  1. создать нового человека с Session.Save(person)
  2. загрузить человека с person = Session.Get(person.Id)
  3. получить personCompany от человека с personCompany = person.PersonCompany.FirstOrDefault() (это будет пусто)
  4. Создайте новую запись PersonCompany-Entry с Session.Save(new PersonCompany(Guid.NewGuid()) {Person = person}))
  5. загрузить человека с person = Session.Get(person.Id)
  6. теперь person.PersonCompany возвращает пустой список.

Когда я не делаю шаг 3, все работает отлично.


person BennoDual    schedule 13.09.2012    source источник
comment
Я чувствую, что это не имеет ничего общего с вашим кэшированием. Не видя, что вы делаете во время создания объектов Person, Company и PersonCompany, я не могу помочь.   -  person Matthew Brubaker    schedule 13.09.2012
comment
Когда я деактивирую кэширование второго уровня, оно работает правильно. Возможно, проблема в том, как я связываю Person с новой PersonCompany. Я делаю personCompany.Person = person и вызываю Session.Insert(personCompany)   -  person BennoDual    schedule 13.09.2012
comment
Прежде всего, если у вас нет действительно веской причины для использования Session.Insert, вам следует использовать Session.SaveOrUpdate(...). Если я правильно помню, Session.Insert избегает большого количества внутреннего кэширования.   -  person Matthew Brubaker    schedule 13.09.2012
comment
ах, извините, мой фабричный метод - это вставка, которая вызывает Session.Save() для создания новой PersonCompany - и до того, как она вызывает Session.Merge(person) для человека (человек не новый). Это две разные сессии.   -  person BennoDual    schedule 13.09.2012
comment
В этом случае похоже, что два сеанса не синхронизируют свои кэши. К сожалению, это может выйти за рамки моей компетенции. Одна вещь, которую вы можете попробовать, - это убедиться, что открытие и закрытие сеанса совпадают. Открыть сессию 1, создать человека 1, закрыть сессию 1, открыть сессию 2, создать компанию 1, закрыть сессию 2, открыть сессию 3, создать PersonCompany (и связать с ней человека 1 и компанию 1), закрыть сессию 3, открыть сессию 4, выберите Person 1 (должен быть правильно связанный PersonCompany), закройте сеанс 4.   -  person Matthew Brubaker    schedule 13.09.2012
comment
по какой причине вы сопоставили компанию Person как отдельный класс, а не многоточие в Company in Person?   -  person Firo    schedule 14.09.2012
comment
@Firo - Да, потому что я добавил дополнительную информацию в PersonCompany   -  person BennoDual    schedule 14.09.2012
comment
@All - я нашел шаги, как воспроизвести проблему и что вызывает проблему (отредактировано в вопросе). Возможно, кто-то может дать объяснение/помощь по этому поводу. Спасибо.   -  person BennoDual    schedule 14.09.2012


Ответы (1)


  1. см. выше
  2. см. выше
  3. получить personCompany от Person с помощью personCompany = person.PersonCompany.FirstOrDefault() (это будет пусто)

    это инициализирует коллекцию пустой коллекцией

  4. Создайте новую запись PersonCompany-Entry с помощью Session.Save(new PersonCompany(Guid.NewGuid()) {Person = person}))

    создаст запись PersonCompany в базе данных

  5. загрузить человека с помощью person = Session.Get(person.Id)

    просто вернет кешированный объект пользователя, так что по сути это "ничего не делать"

  6. теперь person.PersonCompany возвращает пустой список

поскольку коллекция была инициализирована как пустая коллекция на шаге 3, она вернет именно это. nhibernate не будет выдавать другой выбор, чтобы узнать, изменилось ли что-то. если бы это было так, это, вероятно, отбросило бы локальные изменения или вызвало бы конфликты, и это было бы не очень эффективно.

do

  • session.Clear(); в качестве шага 3b или
  • session.Refresh(person); как шаг 5

тогда он работает как положено

person Firo    schedule 14.09.2012
comment
Когда я делаю session.Refresh(person) как шаг 5, это будет работать. Спрашиваю, зачем это нужно, ведь Session — это всегда новая открытая Session. Разве NHibernate-Second-Level Cache не должен делать это за меня? - Когда я сохраняю новую PersonCompany, затем добавляю ее в PersonCompanies-List кэшированных лиц? Если нет, есть ли общий способ решить эту проблему? - person BennoDual; 15.09.2012
comment
кэш второго уровня не будет волшебным образом обновлять ваши объекты, потому что, возможно, это не то, что вы хотите, или есть условия гонки и тому подобное. Также было бы невозможно узнать, куда вставить в коллекцию, когда коллекция отображается с порядком, sql, формулой и т.п. Служба публикации-подписки в приложении, уведомляющая обо всем, чтобы обновить их лица, была бы лучшей ИМО. - person Firo; 17.09.2012