請幫我弄清楚這一點。我很抱歉,如果這是一個重複的問題,但我似乎無法得到任何我正在閱讀工作。NHibernate 3.0對flush的無效索引異常變成無法解析屬性:{foreign key property}
我使用NHibernate 3.0,C#,.NET Framework 4.0和SQL Server 2005來構建一個使用ASP.NET MVC 2的網站。 這裏是情況。我有兩個父母 - >孩子關係的表。我得到了Invalid index N for this SqlParameterCollection with Count=N.
例外。
看完後Derik Whittaker's post at http://devlicio.us/blogs/derik_whittaker/archive/2009/03/19/nhibernate-and-invalid-index-n-for-this-sqlparametercollection-with-count-n-error.aspx我意識到我已經將子表上的外鍵列映射到子類中的屬性和父類對象。因此,在Derik的文章中,我將hbm.xml文件中的屬性映射移除到了外鍵,並將該屬性設置爲僅從parentEntity.PrimaryKey屬性中獲取它的值。現在我得到一個錯誤,指出NHibernate無法解析外鍵屬性。
花費大半個上午狩獵在這裏和谷歌之後,我因爲添加了一個私有字段來保存在子類的外鍵並放回映射到外鍵,設置它的access
屬性field
。 NHibernate仍然無法訪問外鍵屬性。通過從其他一些帖子收集的信息,我確信數據庫中的所有可爲空的列對應於實體類中的可爲空的屬性,並且已經檢查確保數據庫中沒有孤兒。沒有,所以我不應該在訪問父實體對象時觸擊空引用。我也嘗試在我的子實體映射中關閉延遲加載,希望問題是NHibernate只是沒有從數據庫中獲取父項。那也不是問題。
當我在調試器中遍歷我的代碼時,當我嘗試將數據模型投影到視圖模型時出現錯誤。如果我回到原始查詢,在投影之前,看看它從數據庫中拉回的值,我可以看到外鍵屬性被填充了!如果有一些孤兒,我可以將其視爲一個問題,但正如我之前所說的那樣,情況並非如此。不幸的是,我正在linq select查詢中進行投影,所以我無法看到各個值,因爲它逐步遍歷每個值,所以我現在不知道爲什麼它突然找不到外鍵!
不幸的是,這個父 - >子關係本身沒有在數據庫中表達。關係本身完全在我的代碼中表達。
這裏是表的培訓相關結構:
父表:
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>
對於ommitted屬性映射,該屬性的名稱和在表中的相關聯的列是相同的。
最後,這裏是實際產生錯誤的代碼:
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查詢中。如果有人認爲它是必需的,我可以發佈它,但是在任何過濾器值出現之前,我第一次點擊顯示此數據的頁面時發生錯誤。
如果我可以提供更多信息,請告訴我。
謝謝
約翰Norcott
這樣做了!謝謝!但是,這會引起一個問題,那就是如何將一條細節行移動到另一個標頭,因爲我不再映射數據庫中的detailLine.HeaderID列?這不是我現在的問題,更多的是這個解決方案帶來的好奇心。 – 2011-01-10 19:25:45
這取決於你的實現,但基本上你從一個頭部的細節集合中刪除一個細節行,並將其添加到另一個頭部的細節集合中。一路上,細節對標題的引用必須改變。 – 2011-01-11 12:16:47