Недопустимое исключение индекса NHibernate 3.0 при очистке, преобразованной в, не удалось разрешить свойство: {свойство внешнего ключа} - PullRequest
1 голос
/ 06 января 2011

Пожалуйста, помогите мне понять это.Я прошу прощения, если это дублирующий вопрос, но я не могу заставить что-либо другое, что я читаю, работать.

Я использую NHibernate 3.0, C #, .NET Framework 4.0 и SQL Server 2005 длясоздать веб-сайт с использованием ASP.NET MVC 2. Вот ситуация.У меня есть две таблицы с родителями -> дочерние отношения.Я получаю исключение Invalid index N for this SqlParameterCollection with Count=N..

После прочтения сообщения Дерика Уиттекера по адресу http://devlicio.us/blogs/derik_whittaker/archive/2009/03/19/nhibernate-and-invalid-index-n-for-this-sqlparametercollection-with-count-n-error.aspx я понял, что сопоставил столбец внешнего ключа дочерней таблицы со свойством и объектом родительского класса в дочернем классе.Итак, согласно сообщению Дерика, я удалил отображение свойства в моем файле hbm.xml на внешний ключ и установил свойство, чтобы оно получало только значение из свойства parentEntity.PrimaryKey.Теперь я получаю сообщение о том, что NHibernate не может разрешить свойство внешнего ключа.

Проведя большую часть утренней охоты здесь и в Google, я с тех пор добавил личное поле для хранения внешнего ключа в дочернем классе иверните в отображение внешний ключ, установив для атрибута access значение field.NHibernate по-прежнему не может получить доступ к свойству внешнего ключа.Посредством информации, полученной из некоторых других публикаций, я убедился, что все обнуляемые столбцы в базе данных соответствуют обнуляемым свойствам в моих классах сущностей, и я проверил, чтобы в базе данных не было детей-сирот.Нет, поэтому я не должен нажимать на пустую ссылку при доступе к объекту родительского объекта.Я также попытался отключить отложенную загрузку в моей карте дочерних сущностей, надеясь, что проблема заключается в том, что NHibernate просто не получает родителя из базы данных.Это тоже не было проблемой.

Когда я выполняю свой код в отладчике, возникает ошибка, когда я пытаюсь спроецировать модель данных в модель представления.Если я вернусь к исходному запросу до проекции и посмотрю на значения, которые он извлекает из базы данных, я вижу, что свойство внешнего ключа заполнено!Я мог бы рассматривать это как проблему, если бы были дети-сироты, но, как я уже говорил, это не так.К сожалению, я делаю проектирование в запросе выбора linq, поэтому я не вижу отдельных значений, когда он проходит по каждому из них, поэтому теперь я понятия не имею, почему он внезапно не может найти внешний ключ!

К сожалению, сами эти родительские> дочерние отношения не выражены в базе данных.Само отношение полностью выражено в моем коде.

Вот соответствующая структура таблиц:

Родительская таблица:

CREATE TABLE [dbo].[POSErrorQueue](
[HeaderID] [int] IDENTITY(1,1) NOT NULL,
     ---About 75 other parent table specific columns---
CONSTRAINT [PK_POSErrorQueue] PRIMARY KEY CLUSTERED 
(
 [HeaderID] ASC
) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Дочерняя таблица:

CREATE TABLE [dbo].[POSErrorQueueDetails](
[DetailID] [int] IDENTITY(1,1) NOT NULL,
[HeaderID] [int] NOT NULL,
     ---About 20 other child table specific columns---
CONSTRAINT [PK_POSErrorQueueDetails] PRIMARY KEY CLUSTERED 
(
[DetailID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

И вот связанные классы в моем коде, после внесения всех изменений, которые я отметил выше:

Родительский класс:

public class POSErrorQueue
{
    public virtual Int32 HeaderID {get; set;}
    //all other table columns as properties
    public virtual IEnumerable<POSErrorQueueDetail> Details { get; set; }
}

Дочерний класс:

public class POSErrorQueueDetail
{
    private Int32 _headerId;
    public virtual Int32 DetailID { get; set; }
    public virtual Int32 HeaderID { get { return Header.HeaderID; } }
    //all other table columns as properties
    public virtual POSErrorQueue Header { get; set; }
}

Я не уверен, что это действительно полезно, но вот мой класс viewmodel:

public class POSErrorQueueViewModel
{
    public int HeaderID { get; set; }
    public int DetailID { get; set; }
    public string DistributorID { get; set; }
    public string BranchCustomerID { get; set; }
    public string InvoiceID { get; set; }
    public DateTime InvoiceDate { get; set; }
    public string ProductDescription { get; set; }
    public string DentsplyProductID { get; set; }
    public string ProductSource { get; set; }
    public string ErrorDescription { get; set; }
    public decimal? Quantity { get; set; }
    public decimal? UnitSalePrice { get; set; }
    public decimal TotalLinePrice
    {
        get
        {
            if (Quantity.HasValue && UnitSalePrice.HasValue)
            {
                return Quantity.Value * UnitSalePrice.Value;
            }
            else
            {
                return 0;
            }
        }
    }
    public string OrderType { get; set; }
}

Вот мои файлы сопоставления:

Родительская карта:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="TPMControlPanel" namespace ="TPMControlPanel.Models">
  <class name="POSErrorQueue" table="POSErrorQueue">
    <id name="HeaderID">
      <generator class="identity" />
    </id>
    <!--all other property mappings removed for brevity -->
    <set name="Details" inverse="true">
      <key column="HeaderID" />
      <one-to-many class="POSErrorQueueDetail"/>
    </set>
  </class>
</hibernate-mapping>

Дочерняя карта:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="TPMControlPanel" namespace ="TPMControlPanel.Models">
  <class name="POSErrorQueueDetail" table="POSErrorQueueDetails">
    <id name="DetailID">
      <generator class="identity" />
    </id>
    <property name="_headerId" column="HeaderID" access="field" />
    <!--all other property mappings removed for brevity -->
    <many-to-one name="Header" class="POSErrorQueue" column="HeaderID" fetch="join" />
  </class>
</hibernate-mapping>

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

И, наконец, воткод, который на самом деле генерирует ошибку:

public IList<POSErrorQueueViewModel> GetFiltered(Models.FilterModels.POSErrorFilterFields filterFields, DateTime fromDate, DateTime toDate)
    {
        var query = MvcApplication.DENTSPLYSession.Query<POSErrorQueueDetail>().Where(d => d.InvoiceDate > fromDate &&
            d.InvoiceDate < toDate);
        //About 20 lines of if statements used to filter the query removed for brevity.
        var detailView = query.Select(e => new POSErrorQueueViewModel
        {
            HeaderID = e.HeaderID,
            DetailID = e.DetailID,
            BranchCustomerID = e.Header.BranchCustomerID,
            DistributorID = e.Header.DistributorID,
            DentsplyProductID = e.DentsplyProductID,
            ErrorDescription = e.ErrorDescription,
            InvoiceID = e.InvoiceID,
            InvoiceDate = e.InvoiceDate.Value,
            OrderType = e.OrderType,
            ProductDescription = e.ProductDescription,
            ProductSource = e.ProductSource,
            Quantity = e.Quantity,
            UnitSalePrice = e.UnitSalePrice
        });

        return detailView.ToList();
    }

Как я уже говорил выше, я удалил некоторый код, который я использую для фильтрации конечного результата.Это не что иное, как набор операторов if, проходящих через значения, содержащиеся в переданной переменной filterFields, и добавление в запрос linq.Я могу опубликовать его, если кто-то сочтет это необходимым, но ошибка возникает при первом посещении страницы, на которой отображаются эти данные, до того, как появятся какие-либо значения фильтра.

Если я могу предложить дополнительную информацию, пожалуйста, сообщитея знаю.

Спасибо,

Джон Норкотт

1 Ответ

0 голосов
/ 07 января 2011

У вас все еще есть сопоставленный внешний ключ (HeaderID) и в вашей модели.У вас должно быть либо HeaderID, либо Header как свойство, но не оба.

Удалите его из модели:

public class POSErrorQueueDetail
{
    public virtual Int32 DetailID { get; set; }
    public virtual POSErrorQueue Header { get; set; }
}

Чтобы получить доступ к HeaderID, просто зайдите в Header.HeaderID.И отображение:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="TPMControlPanel" namespace ="TPMControlPanel.Models">
  <class name="POSErrorQueueDetail" table="POSErrorQueueDetails">
    <id name="DetailID">
      <generator class="identity" />
    </id>
    <!--all other property mappings removed for brevity -->
    <many-to-one name="Header" class="POSErrorQueue" column="HeaderID" fetch="join" />
  </class>
</hibernate-mapping>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...