2012-09-06 53 views
0

我想了解爲什麼Linq to Sql爲子實體生成插入語句而不是插入父項。我正在處理兩個表格:WorkOrders和Boats。一個WorkOrder有一個船和其他東西。在我的表單中添加工單,我允許用戶爲選定的客戶添加一條新船。如果他們選擇添加一艘新船而不是選擇一艘現有的船,他們會以另一種形式添加船/船。每次我嘗試保存新船時,都會嘗試插入工單。下面,我已經包含了我的兩個類的Linq to Sql映射的子集,我的SQL Server腳本在WorkOrders和Boats之間創建外鍵,我的C#保存邏輯,生成的linq-to-sql語句以及調用疊加。有人可以告訴我這裏可能會發生什麼嗎?Linq-to-Sql試圖插入父而不是子實體

我已經檢查了我的形式,增加了一個新的容器,它並沒有給工單的參考,所以我知道我不是在保存之前設置一個工單到船隻上。此外,我可以使用表單添加新船隻,而不必在沒有此問題的情況下瀏覽工單屏幕。

標記

<Table Name="dbo.Boats" Member="Boats"> 
    <Type Name="Boat"> 
     <Column Name="recno" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> 
     <Column Name="EditedDateTime" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" /> 
     <Column Name="AddDateTime" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" /> 
     <Association Name="Boat_WorkOrder" Member="WorkOrders" ThisKey="recno" OtherKey="Vessel" Type="WorkOrder" /> 
    </Type> 
</Table> 

SQL

ALTER TABLE [dbo].[WorkOrders] WITH CHECK ADD CONSTRAINT [FK_WorkOrders_Vessel] FOREIGN KEY([Vessel]) 
    REFERENCES [dbo].[Boats] ([recno]) 

    INSERT INTO [dbo].[WorkOrders]([CustomerFullName], [ClassListID], [ClassFullName], [ARAccountListId], [ARAccountFullName], [TemplateListID], [TemplateFullName], [InvoiceDate], [BillingAddress1], [BillingAddress2], [BillingAddress3], [BillingAddress4], [BillingAddress5], [BillingCity], [BillingState], [BillingPostalCode], [BillingCountry], [BillingNote], [ShippingAddress4], [ShippingAddress5], [TermsListID], [TermsFullName], [SalesRepListID], [SalesRepFullName], [Memo], [CustomerMessageListID], [CustomerMessageFullName], [OrderType], [OrderStatus], [Technician], [StartDate], [EstCompletionDate], [CompletionDate], [Vessel], [ShippingAddress1], [ShippingAddress2], [ShippingAddress3], [ShippingCity], [ShippingState], [ShippingPostalCode], [ShippingCountry], [PONumber], [ShippingNote], [Symptoms], [Notes], [AddDateTime], [AddBy], [EditedDateTime], [EditedBy], [TransactionStatus], [SyncStatus], [CustomerListId], [CustomerId], [Location]) 
    VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21, @p22, @p23, @p24, @p25, @p26, @p27, @p28, @p29, @p30, @p31, @p32, @p33, @p34, @p35, @p36, @p37, @p38, @p39, @p40, @p41, @p42, @p43, @p44, @p45, @p46, @p47, @p48, @p49, @p50, @p51, @p52, @p53) 

C#

private void saveBoat() 
    { 
     try 
     { 
      if (operationType == GlobalCollections.dbOperationType.Update) 
      { 
       currentBoat.AddBy = "user"; 
       currentBoat.AddDateTime = DateTime.Now; 
       currentBoat.EditedBy = "user"; 
       currentBoat.EditedDateTime = DateTime.Now; 

       dao.UpdateEntity(currentBoat, false); 
      } 
      else if (operationType == GlobalCollections.dbOperationType.Insert) 
      { 
       currentBoat.AddBy = "user"; 
       currentBoat.AddDateTime = DateTime.Now; 
       currentBoat.EditedBy = "user"; 
       currentBoat.EditedDateTime = DateTime.Now; 
       dao.AddEntity(currentBoat); 
      } 
     } 
     catch (Exception ex) 
     { 
      GlobalCollections.showAndLogErrors(logger, ex); 
     } 
    } 

堆棧跟蹤

09/06/2012 09:36:15 Error BEN-LAPTOP MarineService.GlobalCollections.showAndLogErrors Cannot insert the value NULL into column 'AddDateTime', table 'ScribbleSoft.dbo.WorkOrders'; column does not allow nulls. INSERT fails. 
The statement has been terminated. 
09/06/2012 09:36:15 Error BEN-LAPTOP MarineService.GlobalCollections.showAndLogErrors at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) 
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 
    at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 
    at System.Data.SqlClient.SqlDataReader.ConsumeMetaData() 
    at System.Data.SqlClient.SqlDataReader.get_MetaData() 
    at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) 
    at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) 
    at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) 
    at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) 
    at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) 
    at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) 
    at System.Data.Common.DbCommand.ExecuteReader() 
    at System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, Object lastResult) 
    at System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries) 
    at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query) 
    at System.Data.Linq.ChangeDirector.StandardChangeDirector.DynamicInsert(TrackedObject item) 
    at System.Data.Linq.ChangeDirector.StandardChangeDirector.Insert(TrackedObject item) 
    at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) 
    at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) 
    at System.Data.Linq.DataContext.SubmitChanges() 
    at Scribble.Database.Utilities.Domain.Persistence.Repository`1.SaveAll() in C:\Aaron\Dev\HIGH PRIORITY\ServiceModule\MarineService\PureService.DatabaseAccess\Scribble.Database.Utilities\Domain\Persistence\Repository.cs:line 69 
    at Scribble.Database.Utilities.Domain.Persistence.Repository`1.UpdateEntity(T entity, Boolean attach) in C:\Aaron\Dev\HIGH PRIORITY\ServiceModule\MarineService\PureService.DatabaseAccess\Scribble.Database.Utilities\Domain\Persistence\Repository.cs:line 43 
    at MarineService.Tests.AddVesselForm.saveBoat() in C:\Aaron\Dev\HIGH PRIORITY\ServiceModule\MarineService\ServiceModule\AddVesselForm.cs:line 207 
+0

我絕對認爲這有什麼做的LINQ到SQL的映射,我不明白。我嘗試將對客戶對象和工作訂單集合的引用設置爲空,並且沒有發生抱怨。不知何故,Linq正在初始化一個工單對象,並試圖在它執行我的插入或更新語句在船表中的插入它。 – Grasshopper

回答

0

兩天後,我終於想通了,我的問題。總之,我有一個用於添加工單的表單。該表單具有WorkOrder的類變量,用於填充表單。 WorkOrder可以有一艘船和一個客戶。我的問題是,一艘船隻與一名與WorkOrder有關係的客戶有關係。一旦用戶選擇了客戶,客戶就被設置到WorkOrder上。然後,當用戶嘗試添加或更新一艘船時,Linq發現該船被附加到一個連接到WorkOrder的客戶。這解釋了爲什麼該框架在嘗試插入或更新新船之前爲工作訂單生成插入。現在

,我已經修改了表格,讓我修改或訪問備份形式的工單的唯一時間是在加載和保存。否則,我在我的控件上使用文本或標籤屬性。

0

您可能能夠解決您在使用Attach這個問題。

你會做這樣的事情

context.WorkOrders.Attach(currentBoat.WorkOrder); 

這告訴工單是現有對象的情況下,應與數據庫相關聯,但沒有插入像「新」項目將。

+0

謝謝,我試過,但在這種情況下,它不適合我。問題在於,只要我將現有客戶(即已在數據庫中)設置爲Linq關聯屬性,WorkOrder就已經連接到上下文。然後,當我嘗試添加引用客戶的小船時,Linq在插入或更新與WorkOrder相關的Vessel之前嘗試插入WorkOrder。我的手上可能有設計問題。現在,我決定只訪問用於填充表單的WorkOrder,並在構造函數中保存數據庫並保存方法 – Grasshopper

+0

'只要我將現有客戶設置爲Linq關聯屬性' - 不確定您的意思是什麼這(「Linq協會財產」?)。當我遇到這些問題時,我建議在針對上下文的每次操作後插入一個「SubmitChanges」調用。放置一個斷點並查詢數據庫,或者使用'Log'屬性轉儲生成的SQL以查看發生了什麼。由於可以設置關聯屬性/導航屬性的多種方式,因此很難給出明確的答案。 –