2012-11-30 25 views
1

我使用EF和AutoMapper與Azure表存儲模擬。EntityFramework DatabaseGenerated.Identity和AutoMapper == null ID鍵

我有兩種類型,Fragment(可序列化DTO)和FragmentEntity(EF持久DO)。我使用AutoMapper從DTO映射到DO,以便在PUT調用上持久化,反之亦然。

問題是我對EF和AutoMapper都沒有經驗。我已經將FragmentEntity類(根據我可以找到的文檔)配置爲在數據庫中生成片段的Id(請參見下文)。

實體ID的定義:

[Key] 
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
public int? Id { get; set; } 

在運行HTTP客戶端與所述新的內容(片段)一個REST PUT調用。這是通過WCF接收並序列化爲片段,如下所示。

[OperationContract] 
[WebInvoke(UriTemplate = "/Fragments", Method = "PUT")] 
void PutFagment(Fragment fragment); 

在調試過程中,如果我跨越代碼接收到的ID值爲空(因爲我已將ID屬性定義爲可選)。

public void PutFagment(Fragment fragment) 
{ 
     var fragmentEntity = Mapper.Map<Fragment, FragmentEntity>(fragment); 
     _fragmentContext.Add(fragmentEntity); 
} 

[DataMember] 
public virtual int? Id { get; set; } 

我不確定是否將其定義爲可選是明智之舉;我這樣做是因爲如果它不是可選的,那麼默認值爲零,然後automapper映射到目標FragmentEntity,隨後所有的鍵在數據庫中最終爲零(明顯錯誤)。

正如你所料,我也已經使FragmentEntity Id可選,以避免在應用程序代碼中設置一個值,我的希望是如果它爲null數據庫代可能發生但是這似乎並沒有發生。

<Fragment><Id i:nil="true"/><Name>Drei</Name><Type>3</Type></Fragment> 

我的問題:

  1. 我認爲決定把ID可選在這兩個類是不正確的,我認爲有一些AutoMapper配置,這將適當地處理這種情況,並且既可以保持非可選的。
  2. 我不確定爲什麼DatabaseGenerated屬性沒有生效。
+0

1.同意,它可能不應該是可選的。您可以在AutoMapper配置中使用條件選項,以便在零映射時不映射它,但我認爲這不是您真正的問題。 2.這是你真正的問題,但不幸的是,我沒有EF能夠提供幫助的經驗。你可能在這裏找到一些有趣的東西? http://stackoverflow.com/questions/5124911/using-database-generated-guid-and-datetime-with-ef4 – Mightymuke

+0

感謝您的鏈接,它給了我一個有趣的想法。也許是因爲azure表存儲不是關係數據庫,它不提供數據庫密鑰生成。這也可以解釋爲什麼當它在表中有兩個項目(0或null)時它不會引發異常......也許我必須獲得該代碼的所有權。 – Syntax

+0

如果您試圖保留重複的RowKey值,它實際上會拋出異常,但很明顯,因爲RowKey用於唯一性,所以用戶定義的任何鍵都不會被認可,這意味着Azure表存儲不支持[Key]和[DatabaseGeneratedOption]屬性。 – Syntax

回答

0

因此,事實證明,開發人員負責使用天藍色表格存儲來生成其唯一的rowkey。這是爲FragmentEntity完成的,其延伸TableServiceEntity。即使提供商不支持數據庫密鑰生成,開發人員也必須擁有這個。

這意味着:

  1. 您必須擁有ID生成代碼。
  2. 您不需要在您的TableServiceEntity中定義Id屬性,而只需在兩個方向的AutoMapper配置中提供合理的映射。

該ID不應該由客戶端指定(這是服務器的責任)。因此,從DTO到持久化DO的映射會覆蓋默認情況下使用新生成的Guid設置的值(請參閱下面的代碼)。

Mapper.Configuration.CreateMap<Fragment, FragmentEntity>() 
     .ForMember(dest => dest.RowKey, 
       expression => expression.ResolveUsing(source => Guid.NewGuid().ToString())) 
// NB: you are also required to provide a partition key for TableServiceEntities 
     .ForMember(dest => dest.PartitionKey, 
       opt => opt.ResolveUsing(source => PartitionKeyConstants.LocalPartitionKey)); 

然後從FragmentEntity片段在另一個方向上的映射必須被配置成將DTO的Id屬性設置爲FragmentEntity的RowKey值。

Mapper.Configuration.CreateMap<FragmentEntity, Fragment>() 
     .ForMember(dest => dest.Id, 
       expression => expression.ResolveUsing(source => source.RowKey)); 

我的映射代碼註冊在我的Global.asax.cs中以處理映射註冊。我會在某個時候將其轉移到IoC容器中。

由於此更改,我不再在我的FragmentEntity中定義一個ID,並且Fragment類中已定義的Id屬性不再是可選的。

[DataMember] 
public virtual Guid Id { get; set; } 

注意:我使用了Guid,因爲它更容易生成唯一的Guid值,而不是跟蹤int鍵和增量。這也意味着我在檢查下一個int鍵值時不會引入數據庫鎖定瓶頸。