2011-01-06 39 views
1

請幫我弄清楚這一點。我很抱歉,如果這是一個重複的問題,但我似乎無法得到任何我正在閱讀工作。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

回答

0

你仍然有外鍵(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> 
+0

這樣做了!謝謝!但是,這會引起一個問題,那就是如何將一條細節行移動到另一個標頭,因爲我不再映射數據庫中的detailLine.HeaderID列?這不是我現在的問題,更多的是這個解決方案帶來的好奇心。 – 2011-01-10 19:25:45

+0

這取決於你的實現,但基本上你從一個頭部的細節集合中刪除一個細節行,並將其添加到另一個頭部的細節集合中。一路上,細節對標題的引用必須改變。 – 2011-01-11 12:16:47

相關問題