2008年7月22日 星期二

Linq to SQL 的 bug?

看來,我發現了一個 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 ,如下圖

image

再 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()

image

這個錯誤訊息,真是是令人不敢領教。


其實,這個錯誤,只需要修改 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 修正。

沒有留言:

Share with Facebook