带有迁移的Code First Seed出错:不支持使用“Identity”模式修改列。专栏:'CreatedAt'。

时间:2015-02-26 07:23:56

标签: c# entity-framework azure azure-mobile-services

我已在Azure Mobile Services项目上激活了迁移。我在迁移的Configuration.cs类中填充了新的种子函数。如果表是空的,则种子功能没有任何问题。当我的AddorUpdate尝试更新第一个对象时,我在内部异常中收到错误:"使用' Identity'修改列。模式不受支持。专栏:' CreatedAt'。表:' CodeFirstDatabaseSchema.Category'。"

我的部分代码如下:

context.categories.AddOrUpdate(
            new Category { Id="1", Code="GEN", Text="General"},
            new Category { Id="2", Code="POL", Text="Politics"},
            new Category { Id="3", Code="FAS", Text="Fashion"},
            new Category { Id="4", Code="PEO", Text="People"},
            new Category { Id="5", Code="TEC", Text="Technology"},
            new Category { Id="6", Code="SPO", Text="Sport"},
            new Category { Id="7", Code="LIV", Text="Living"}
        );

5 个答案:

答案 0 :(得分:4)

这是我对Nikatlas解决方案的通用实现。

答案的简短版本:您无法使用空值修改CreatedAt,因此您可以改为使用此函数:

    private void AddOrUpdatePreservingCreatedAt<T> (DbSet<T> set, T item) where T : EntityData
    {        
        var existing = set.Where(i => i.Id == item.Id).FirstOrDefault();
        if (existing != null)
        {
            item.CreatedAt = existing.CreatedAt;             
        }
        set.AddOrUpdate(i => i.Id, item);
    }

像这样称呼

AddOrUpdatePreservingCreatedAt(context.YourItems, itemToBeUpdatedOrAdded);

答案 1 :(得分:3)

我似乎找到了解决这个问题的方法。

发生此错误的原因是AddOrUpdate方法。 如本帖所述:http://thedatafarm.com/data-access/take-care-with-ef-4-3-addorupdate-method/

更重要的是,如果找到匹配项,那么更新将全部更新并清除任何不在AddOrUpdate中的内容。

这意味着在第一个种子之后,无论何时代码运行,它都会尝试正确更新您的实体,但它会尝试在CreatedAt字段上传递值null。如果查看EntityData类,CreateAt字段具有以下属性:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)] //Here they mark this as IDENTITY        
[Index(IsClustered = true)] // Cluster index. i really dont know why ?         
[TableColumn(TableColumnType.CreatedAt)]         
public DateTimeOffset? CreatedAt { get; set; }

因此,您尝试修改CreatedAt列时会发生错误。

我的解决方案是创建一个列表,查找以将CreatedAt设置为正确值,然后添加orUrUpdate:

 // Create List       
 List<Permission> permissions = new List<Permission>(new Permission[]{             
   new Permission { Id = "ID1" , Name = "Send SMS"},           
   new Permission { Id = "ID2", Name = "Send Email"}            });
   // Iterate through list to set CreatedAt to correct value 
   foreach (Permission p in permissions){
      // Get the record from the db if it exists              
      var t = context.PermissionSet.Where(s => s.Id == p.Id).FirstOrDefault();
      if (t != null){
         p.CreatedAt = t.CreatedAt; //SET CreatedAt to correct Value if the record already exists                
      }
      context.PermissionSet.AddOrUpdate(a => a.Id, p); // NOW I CAN UPDATE WITH NO PROBLEM
   } 

希望这会有所帮助。 :)

答案 2 :(得分:2)

如果您有一个名为Id的整数列,那么Entity Framework将假定它是主键并且它是数据库生成的 - 因此它在数据库中创建为IDENTITY列。 / p>

您无法为IDENTITY列指定ID,因此您可以通过删除Id = 1Id = 2等来停止这样做

我有点因为你遇到问题的专栏被命名为&#34; CreatedAt&#34;。听起来它应该是DateTime,也可能是数据库生成的,但它肯定不应该是IDENTITY

无论如何,您可能想要的用法是指定实体的自然键,以便EF可以识别已存在的任何记录。所以,如果CODE是自然键,那么你应该像这样编写种子:

context.categories.AddOrUpdate(
   x => x.Code,//the natural key is Code    
   new Category { Code="GEN", Text="General"},
   new Category { Code="POL", Text="Politics"},
   new Category { Code="FAS", Text="Fashion"},
   new Category { Code="PEO", Text="People"},
   new Category { Code="TEC", Text="Technology"},
   new Category { Code="SPO", Text="Sport"},
   new Category { Code="LIV", Text="Living"}

);

参考: Take care with the AddOrUpdate method

答案 3 :(得分:0)

This question, its answers and comments可能对你有所帮助,但不多。

您可以使用问题提供的解决方案在标识列上执行插入操作。但您不能更新标识列的值。在标识列上执行更新的唯一方法是将其标记为不是标识。可能是通过添加手动迁移。

This SO question and its answers也可能有所帮助。

Read here also on general MSSQL Server constraints on Updating Identity Column

答案 4 :(得分:0)

相同的问题和解决方案 我们遇到了同样的问题,它是另一个表中的触发器,对我们遇到问题的表产生了影响。

我们的发展细节 我们开发了连接到Azure Web服务的Xamarin应用程序。当我们使用iMobileServices的PushAsync方法时,出现了以下错误:不支持使用“身份”模式修改列。列:“ CreatedAt”。

对我们来说很奇怪,因为某些表没有Web服务问题

原因 似乎触发器更新与来自移动设备的pushasync冲突。

我们禁用了触发器,将职责切换到了前端,并且工作正常。至少对我们来说。

我们希望这种解决方案可以帮助某人。

image