我已在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"}
);
答案 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 = 1
,Id = 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"}
);
答案 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)