天蓝移动服务中POST / PATCH方法中的外键约束和[Key]属性问题

时间:2016-04-27 06:35:41

标签: entity-framework

我们正在使用现有数据库的代码优先数据库方法开发azure移动服务。我们在require表中添加了Id,CreatedAt,UpdatedAt,Version列。

在项目中,SimpleMappedEntityDomainManager.cs用于域映射类。请在此处查看附件类文件。 初始化每个控制器的方法,使用这个类创建域实例,代码如下。

public class SimpleMappedEntityDomainManager<TData, TModel>
    : MappedEntityDomainManager<TData, TModel>
    where TData : class, ITableData, new()
    where TModel : class
{
    private Expression<Func<TModel, object>> dbKeyProperty;

    public SimpleMappedEntityDomainManager(DbContext context,
        HttpRequestMessage request,
        Expression<Func<TModel, object>> dbKeyProperty)
        : base(context, request, true)
    {
        this.dbKeyProperty = dbKeyProperty;
        //this.Context = context;
    }
    public override SingleResult<TData> Lookup(string id)
    {
        return this.LookupEntity(GeneratePredicate(id));
    }
    public override async Task<TData> UpdateAsync(string id, Delta<TData> patch)
    {
        return await this.UpdateEntityAsync(patch, id);
    }
    public override Task<bool> DeleteAsync(string id)
    {
        return this.DeleteItemAsync(id);
    }

    private static Expression<Func<TModel, bool>> GeneratePredicate(string id)
    {
        var m = Mapper.FindTypeMapFor<TModel, TData>();
        var pmForId = m.GetExistingPropertyMapFor(new PropertyAccessor(typeof(TData).GetProperty("Id")));
        var keyString = pmForId.CustomExpression;
        var predicate = Expression.Lambda<Func<TModel, bool>>(
            Expression.Equal(keyString.Body, Expression.Constant(id)),
            keyString.Parameters[0]);
        return predicate;
    }

    private object ConvertId(string id)
    {
        var m = Mapper.FindTypeMapFor<TData, TModel>();
        var keyPropertyAccessor = GetPropertyAccessor(this.dbKeyProperty);
        var pmForId = m.GetExistingPropertyMapFor(new PropertyAccessor(keyPropertyAccessor));
        TData tmp = new TData() { Id = id };
        var convertedId = pmForId.CustomExpression.Compile().DynamicInvoke(tmp);
        return convertedId;
    }

    private PropertyInfo GetPropertyAccessor(Expression exp)
    {
        if (exp.NodeType == ExpressionType.Lambda)
        {
            var lambda = exp as LambdaExpression;
            return GetPropertyAccessor(lambda.Body);
        }
        else if (exp.NodeType == ExpressionType.Convert)
        {
            var convert = exp as UnaryExpression;
            return GetPropertyAccessor(convert.Operand);
        }
        else if (exp.NodeType == ExpressionType.MemberAccess)
        {
            var propExp = exp as System.Linq.Expressions.MemberExpression;
            return propExp.Member as PropertyInfo;
        }
        else
        {
            throw new InvalidOperationException("Unexpected expression node type: " + exp.NodeType);
        }
    }
}

现有表格如下:

表:tbl_Property_equip

  
      
  1. property_equip_id - 标识列 - 主键
  2.   
  3. property_id
  4.   
  5. equipment_id
  6.   
  7. property_equip_serial_number   property_equip_unit_number
  8.   

表:tbl_property_loc

  
      
  1. property_loc_id - 标识列 - 主键
  2.   
  3. property_id
  4.   
  5. property_loc_name
  6.   

表:tbl_property_equip_area_served

  
      
  1. property_equip_area_served_id - 标识列 - 主键
  2.   
  3. property_equip_id - tbl_Property_equip table reference
  4.   
  5. property_loc_id - tbl_property_loc表格参考
  6.   

模型类生成如下:

public partial class tbl_property_equip {
    //[Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int property_equip_id { get; set; }

    public int property_id { get; set; }

    public int equipment_id { get; set; }

    [StringLength(150)]
    public string property_equip_serial_number { get; set; }

    [StringLength(150)]
    public string property_equip_unit_number { get; set; }

    public virtual ICollection<tbl_property_equip_area_served> tbl_property_equip_area_served { get; set; }
}

public partial class tbl_property_loc
{
    //[Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int property_loc_id { get; set; }

    public int property_id { get; set; }

    [StringLength(255)]
    public string property_loc_name { get; set; }   

    public virtual ICollection<tbl_property_equip_area_served> tbl_property_equip_area_served { get; set; }
}

public partial class tbl_property_equip_area_served
{
    //[Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int property_equip_area_served_id { get; set; }

    public int property_equip_id { get; set; }

    public int property_loc_id { get; set; }

    public virtual tbl_property_equip tbl_property_equip { get; set; }

    public virtual tbl_property_loc tbl_property_loc { get; set; }
}

POST / PATCH方法适用于Property Equipment和Property Location,因为删除了[KEY]和DatabaseGeneratedOption.Identity。它不是将ID视为主键。

但由于从物业设备和位置等级中删除了[KEY],因此服务的物业区无效。因此,将ID视为每个的主键。 与父表的关系无法正常工作。所以邮差中显示的错误如下。

    {
  "message": "An error has occurred.",
  "exceptionMessage": "One or more validation errors were detected during model generation:\r\n\r\ntbl_property_loc_tbl_property_equip_area_served_Source_tbl_property_loc_tbl_property_equip_area_served_Target: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'property_loc_id' on entity 'tbl_property_equip_area_served' does not match the type of property 'Id' on entity 'tbl_property_loc' in the referential constraint 'tbl_property_loc_tbl_property_equip_area_served'.\r\ntbl_property_equip_tbl_property_equip_area_served_Source_tbl_property_equip_tbl_property_equip_area_served_Target: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'property_equip_id' on entity 'tbl_property_equip_area_served' does not match the type of property 'Id' on entity 'tbl_property_equip' in the referential constraint 'tbl_property_equip_tbl_property_equip_area_served'.\r\n",
 "exceptionType": "System.Data.Entity.ModelConfiguration.ModelValidationException",
  "stackTrace": "   at System.Data.Entity.Core.Metadata.Edm.EdmModel.Validate()\r\n   at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)\r\n   at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)\r\n   at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)\r\n   at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)\r\n   at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()\r\n   at System.Data.Entity.Internal.InternalContext.Initialize()\r\n   at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)\r\n   at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()\r\n   at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()\r\n   at System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(Action action, EntityState newState, Object entity, String methodName)\r\n   at System.Data.Entity.Internal.Linq.InternalSet`1.Add(Object entity)\r\n   at System.Data.Entity.DbSet`1.Add(TEntity entity)\r\n   at Microsoft.Azure.Mobile.Server.MappedEntityDomainManager`2.<InsertAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at Microsoft.Azure.Mobile.Server.TableController`1.<InsertAsync>d__3.MoveNext()"
}   

我尝试为属性区域服务表/控制器创建Domain Mapper类,如下面链接中的示例所示。但无法成功。我们应该在现有数据库中使用与此处给出的示例相同的方法。

https://azure.microsoft.com/en-us/documentation/articles/mobile-services-dotnet-backend-use-existing-sql-database/

1 个答案:

答案 0 :(得分:1)

这实际上是一个实体框架问题。问题是您删除了类中的[Key]属性,因此Entity Framework无法映射依赖属性。见Entity Framework 4.1 - Relationships between non-key columns