看來,我發現了一個 Linq to SQL 的 bug。
要還原現場,當然要 database 。
CREATE TABLE [dbo].[A]( [AId] [int] NOT NULL, [AName] [char](10) NOT NULL, CONSTRAINT [PK_A] PRIMARY KEY CLUSTERED ( [AName] ASC ), CONSTRAINT [IX_A] UNIQUE NONCLUSTERED ( [AId] ASC ) ) GO INSERT [dbo].[A] ([AId], [AName]) VALUES (1, N'Charles ') go CREATE TABLE [dbo].[A2]( [AId] [int] NOT NULL, [AValue] [varchar](50) NOT NULL, CONSTRAINT [PK_A2] PRIMARY KEY CLUSTERED ( [AId] ASC ) ) GO ALTER TABLE [dbo].[A2] WITH CHECK ADD CONSTRAINT [FK_A2_A] FOREIGN KEY([AId]) REFERENCES [dbo].[A] ([AId]) GO ALTER TABLE [dbo].[A2] CHECK CONSTRAINT [FK_A2_A] GO
注意到,A2.AId 是 reference 到 A.AId。而A.AId 是 unique key,而非 primary key。A 的 primary key 是 AName
再來,就開始拉 dbml ,如下圖
再 create 一個 Console Application,如下
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { TestDataContext ctx = new TestDataContext(); A2 a2 = new A2 { AId = 1, AValue = "xxx" }; ctx.A2s.InsertOnSubmit(a2); ctx.SubmitChanges(); } } }程式錯誤訊息如下:
Type : System.InvalidCastException, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Message : Unable to cast object of type 'System.Int32' to type 'System.String'. Source : System.Data.Linq Help link : Data : System.Collections.ListDictionaryInternal TargetSite : Boolean TryCreateKeyFromValues(System.Object[], V ByRef) Stack Trace : at System.Data.Linq.IdentityManager.StandardIdentityManager.SingleKeyManager`2.TryCreateKeyFromValues(Object[] values, V& v) at System.Data.Linq.IdentityManager.StandardIdentityManager.IdentityCache`2.Find(Object[] keyValues) at System.Data.Linq.IdentityManager.StandardIdentityManager.Find(MetaType type, Object[] keyValues) at System.Data.Linq.CommonDataServices.GetCachedObject(MetaType type, Object[] keyValues) at System.Data.Linq.ChangeProcessor.GetOtherItem(MetaAssociation assoc, Object instance) at System.Data.Linq.ChangeProcessor.BuildEdgeMaps() at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) at System.Data.Linq.DataContext.SubmitChanges()
這個錯誤訊息,真是是令人不敢領教。
其實,這個錯誤,只需要修改 A 的 primary key 為 AId 即可。但實務上,卻非常有可能如上例的資料庫設計。
以發票的例子為例,常常會以發票號碼作為 primary key,而另設一個 ObjectId (int) 作為別的 table 的 reference key,因為 int 的size 較小。
Sql Script 可這裡下載, 而程式碼可這裡下載
目前我已向微軟提出這樣的 bug。這是算是我的第一次呢!
[註] 2008/08/19 MS Linq to SQL team 已經證實這個 issue ,而且會在下一次 release 修正。
沒有留言:
張貼留言