2

我将 EF 和 AutoMapper 与 Azure 表存储仿真一起使用。

我有两种类型,Fragment(可序列化 DTO)和 FragmentEntity(EF 持久化 DO)。我使用 AutoMapper 从 DTO 映射到 DO,以便在 PUT 调用上保持持久性,在 GET 调用上反之亦然。

问题是我对 EF 和 AutoMapper 都缺乏经验。我已将 FragmentEntity 类(根据我能找到的文档)配置为在数据库中为 Fragment 生成 Id(见下文)。

实体 ID 定义:

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

在运行时,http 客户端使用新内容(片段)进行 REST PUT 调用。这通过 WCF 接收并序列化为 Fragment,如下所示。

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

在调试期间,如果我跳过代码,接收到的 ID 值为 null(因为我已将 ID 属性定义为可选)。

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

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

我不确定将其定义为可选是否是明智之举;我这样做是因为如果它不是可选的,则该值默认为零,然后自动映射器映射到目标 FragmentEntity,随后数据库中的所有键最终都为零(显然是错误的)。

正如您可能期望的那样,我还使 FragmentEntity Id 成为可选以避免在应用程序代码中设置值,我希望如果它为空,则可能会发生数据库生成,但这似乎没有发生。

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

我的问题:

  1. 我认为在两个类中使 Id 可选的决定是不正确的,我假设有一些 AutoMapper 配置可以适当地处理这种情况,并且两者都可以保持非可选。
  2. 我不确定为什么 DatabaseGenerated 属性没有生效。
4

1 回答 1

0

因此,事实证明,开发人员负责使用 azure 表存储来生成他们唯一的行键。这是为扩展TableServiceEntity的FragmentEntity完成的。又名提供者将不支持数据库密钥生成,开发人员必须拥有它。

这表示:

  1. 您必须拥有 ID 生成代码。
  2. 您无需在TableServiceEntitys 中定义 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));

然后必须配置从FragmentEntityFragment的另一个方向的映射,将 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 键值时不会引入 db-lock 瓶颈。

于 2012-11-30T09:31:11.383 回答