Проблема приведения NHibernate (предполагаемая причина - неправильное отображение) - PullRequest
1 голос
/ 19 октября 2011

У меня проблемы с отображением отношений M: 1 между Petition и PetitionSignature в NHibernate. Это тот тип отношений, который я описал раньше, но сейчас я просто не могу заставить его работать.

Метод, который я пытаюсь вызвать в своем провайдере, предназначен для возврата коллекции PetitionSignatures на основе объекта Petition, который был передан в:

public IList<PetitionSignature> GetByPetition(Petition p)
{
    IList<PetitionSignature> Signatures = (IList<PetitionSignature>)_session.CreateCriteria(typeof(PetitionSignature))
        .Add(Restrictions.Eq("Petition", p))
        .AddOrder(Order.Desc("Id")).List();
    return Signatures.OrderBy(sig => sig.Date).ToList();
}

Мой класс Петиции определяется как:

public class Petition : IPetition
{
    public virtual int Id { get; set; }
    public virtual string Title { get; set; }
    public virtual string Text { get; set; }
    public virtual string Slug { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual IList<PetitionSignature> Signatures { get; set; }
}

Мой класс PetitionSignature определяется как:

public class PetitionSignature : IPetitionSignature
{
    public virtual int Id { get; set; }
    public virtual Petition Petition { get; set; }
    public virtual string Name { get; set; }
    public virtual string EmailAddress { get; set; }
    public virtual string PhoneNumber { get; set; }
    public virtual string StreetAddress { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual bool OkToEmail { get; set; }

}

Документ для сопоставления моей петиции:

<id name="Id" column="Id" type="int">
  <generator class="native" />
</id>

<property name="Title" column="Title"></property>
<property name="Text" column="Text"></property>
<property name="Date" column="Date"></property>
<property name="Slug" column="Slug"></property>

<bag name="Signatures" lazy="true" cascade="all-delete-orphan" inverse="true">
  <key column="Id"/>
  <one-to-many class="PetitionSignature"/>
</bag>

И мой документ сопоставления PetitionSignature выглядит следующим образом:

<property name="Name" column="Name"></property>
<property name="EmailAddress" column="EmailAddress"></property>
<property name="Date" column="Date"></property>
<property name="OkToEmail" column="OkToEmail"></property>
<property name="PhoneNumber" column="PhoneNumber"></property>
<property name="StreetAddress" column="StreetAddress"></property>

  <many-to-one name="Petition" class="Petition" column="Petition" cascade="all" />

Вот столбцы моей таблицы петиций: Petition Table

И вот столбцы моей таблицы PetitionSignature: PetitionSignature Table

Так вот что происходит. Я запускаю тест интеграции в режиме отладки и проверяю это. Я без проблем увлажняю свой объект Petition и передаю его этому методу в классе PetitionSignatureProvider. Вот когда это происходит: Exception Time!

Конечно, это преобразование может быть сделано. При создании другого метода в поставщике, который принимает PetitionId, преобразование выполняется нормально. Это наводит меня на мысль, что проблема в моем отображении, показанном выше.

Есть идеи?

Ответы [ 3 ]

4 голосов
/ 19 октября 2011

Результатом запроса критерия является , а не универсальный список, он возвращает объект, который реализует IList, поэтому вы не можете просто привести его к универсальному списку. Однако вы можете преобразовать его в общий список, используя методы расширения в IEnumerable. Следующий код должен работать:

public IList<PetitionSignature> GetByPetition(Petition p)
{
    return _session.CreateCriteria(typeof(PetitionSignature))
        .Add(Restrictions.Eq("Petition", p))
        .AddOrder(Order.Desc("Id"))
        .List()
        .Cast<PetitionSignature>()
        .OrderBy(sig => sig.Date)
        .ToList();
}

Но у вас уже есть объект Petition. Если этот объект выбирается через NHibernate в том же сеансе, то вы можете просто написать:

public IList<PetitionSignature> GetByPetition(Petition p)
{
    return p.Signatures.OrderBy(sig => sig.Date).ToList();
}

Или, что еще лучше, вам вообще не нужен метод. Просто напишите

p.Signatures.OrderBy(sig => sig.Date)

всякий раз, когда вам нужны подписи конкретной петиции, упорядоченной по дате. Помимо этого, у меня есть несколько предложений относительно вашего кода:

  • Ошибка в вашем файле отображения. Элемент <key> в вашей сумке должен ссылаться на поле внешнего ключа таблицы PetitionSignature . Должно быть: <key column="Petition" />

  • Если ваша версия NHibernate не слишком старая, я бы использовал новый QueryOver api или NHibernate.Linq. Оба эти API-интерфейса являются безопасными и используют лямбда-выражения вместо магических строк.

  • Я думаю, что вы хотите использовать <set> вместо <bag>. Для получения дополнительной информации о комплектах и ​​сумках см. этот вопрос о стеке .
1 голос
/ 19 октября 2011

Используйте .List<PetitionSignature>() вместо .List() с критериями. Это вернет ожидаемую коллекцию дженериков без необходимости приведения.

Теперь, - это ошибка отображения, которая мешает вам сделать это намного проще:

<bag name="Signatures" cascade="all-delete-orphan" inverse="true">
  <key column="Petition"/> <!-- This is the FK -->
  <one-to-many class="PetitionSignature"/>
</bag>

При этом вы можете просто использовать петицию. Подписи, нет необходимости в запросе критериев.

1 голос
/ 19 октября 2011

System.Collections.ArrayList не не реализует универсальный интерфейс System.Collections.Generic.IList<T>, но не универсальный интерфейс System.Collections.IList. Они не должны быть совместимы, если только C # не использует магию, о которой я не знаю в этом случае.

Если у NHibernate есть API, который возвращает универсальные коллекции, вы должны использовать его для получения результатов. В противном случае вы можете использовать IEnumerable.OfType() или IEnumerable.Cast().

Если это работает в другом методе, возможно, NHibernate возвращает универсальную коллекцию при навигации по ассоциации, которая использует универсальный тип в классе сущности, но возвращает неуниверсальную коллекцию при использовании API-интерфейса ICriteria для запроса список лиц. Документация также подразумевает, что более новый API QueryOver также использует дженерики.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...