Пожалуйста, помогите мне понять это.Я прошу прощения, если это дублирующий вопрос, но я не могу заставить что-либо другое, что я читаю, работать.
Я использую 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.Я могу опубликовать его, если кто-то сочтет это необходимым, но ошибка возникает при первом посещении страницы, на которой отображаются эти данные, до того, как появятся какие-либо значения фильтра.
Если я могу предложить дополнительную информацию, пожалуйста, сообщитея знаю.
Спасибо,
Джон Норкотт