Хотя коллекция не изменена, NH все еще может думать, что это так.Нечто подобное может быть вызвано призрачным обновлением.Из книги поваренных книг NHibernate 3.0, Джейсон Дентлер (стр. 184): «Как часть автоматической грязной проверки, NHibernate сравнивает исходное состояние объекта с его текущим состоянием. В противном случае неизмененный объект может быть излишне обновлен, потому что преобразование типа привело к сбою этого сравнения".
Призрачное обновление коллекции может быть вызвано кодом, который выглядит следующим образом:
public class Tag
{
private IList<ProjectTag> projectsTags;
public virtual IEnumerable<ProjectTag> ProjectsTags
{
get
{
return new ReadOnlyCollection<ProjectTag>(projectsTags);
}
set
{
projectsTags = (IList<ProjectTag>)value;
}
}
}
Свойство ProjectsTags возвращает коллекцию в оболочке только для чтения, поэтому клиентский код не может добавлять или удалять элементы в /из коллекции.
Ошибка будет появляться, даже если имя тега не изменено:
private void GhostTagUpdate(int id)
{
using (var session = OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var tag = session.Get<Tag>(id);
transaction.Commit();
}
}
}
Коллекция ProjectsTags должна быть сопоставлена со стратегией доступа CamelCaseField, чтобы избежать появления обновлений:
HasMany(x => x.ProjectsTags)
.Access.CamelCaseField()
.AsBag().Inverse().Cascade.AllDeleteOrphan().Fetch.Select().BatchSize(80);
В любом случае ...
Ваша связь кажется дьявольски сложной.Если таблица ProjectsTags должна содержать только идентификатор тега и идентификатор проекта, то было бы проще использовать двунаправленное отображение FNH «многие ко многим»:
public class Tag2Map : ClassMap<Tag2>
{
public Tag2Map()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Projects)
.AsBag()
.Cascade.None()
.Table("ProjectsTags")
.ParentKeyColumn("TagId")
.ChildKeyColumn("ProjectId");
}
}
public class Project2Map : ClassMap<Project2>
{
public Project2Map()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Tags)
.AsBag()
.Cascade.None()
.Inverse()
.Table("ProjectsTags")
.ParentKeyColumn("ProjectId")
.ChildKeyColumn("TagId");
}
}
Теперь в модели не требуется сущность ProjectTag.,Счетчик количества использованных тегов может быть получен двумя способами:
Прямой путь: tag.Projects.Count()
- но он извлекает все проекты из базы данных.
Способ запроса:
var tag = session.Get<Tag2>(tagId);
var count = session.Query<Project2>().Where(x => x.Tags.Contains(tag)).Count();