EntityFramework DatabaseGenerated.Identity和AutoMapper == null ID键

时间:2012-11-30 04:42:58

标签: c# entity-framework azure automapper

我正在使用EF和AutoMapper与Azure表存储模拟。

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

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

实体ID定义:

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

在运行时,http客户端使用新内容(Fragment)进行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; }

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

正如您所料,我也已将FragmentEntity Id设置为可选,以避免在应用程序代码中设置值,我希望如果它为null,则可能会发生数据库生成,但这似乎不会发生。

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

我的问题:

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

1 个答案:

答案 0 :(得分:0)

因此,事实证明开发人员负责使用azure表存储来生成其唯一的rowkey。这是为扩展 TableServiceEntity FragmentEntity 完成的。提供者Aka不支持数据库密钥生成,开发人员必须拥有此代码。

这意味着:

  1. 您必须拥有ID生成代码。
  2. 您无需在TableServiceEntity中定义Id属性,只需在AutoMapper配置中提供两个方向的合理映射。
  3. 客户端不应指定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 Fragment 的另一个方向的映射,以将DTO的Id属性设置为的RowKey值FragmentEntity

    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瓶颈。