我想首先使用EF代码将我的模型类连接到我的数据库,例如:
public partial class Header
{
public int Id { get; set; }
public int DeviceId { get; set; }
...
}
和我的DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Header>().HasKey(k => new { k.Id, k.DeviceId });
modelBuilder.Entity<Header>().MapToStoredProcedures(s =>
{
s.Update(u => u.HasName("dbo.SpUpdateHeader"));
s.Insert(i =>
i.HasName("dbo.SpInsertHeader")
.Result<int>(r => r.Id, "Id"));
s.Delete(d => d.HasName("dbo.SpDeleteHeader"));
});
}
DeviceId固定为生成记录的设备,Id是在该设备上生成的标识。 此DbContext用于同步服务器上的所有设备数据。
此代码的问题是在插入时,我收到此错误: 在修改函数'SpInsertHeader'上找不到属性'Id'的结果绑定。确保该属性是数据库生成的。
如果我设置[DatabaseGenerated(DatabaseGeneratedOption.Computed)]属性或[DatabaseGenerated(DatabaseGeneratedOption.Identity)],该属性永远不会发送到存储过程
如何启用此方案?
修改
PROCEDURE [dbo].[SpInsertHeader]
@Id INT,
@DeviceId INT
AS
BEGIN
--get new id
IF(COALESCE(@Id, 0) = 0)
BEGIN
SELECT TOP 1 @Id = COALESCE(h.Id, 0) + 1
FROM Header h
WHERE h.DeviceId = @DeviceId
ORDER BY h.Id DESC;
END
IF(COALESCE(@Id, 0) = 0)
BEGIN
SET @Id = 1;
END
INSERT INTO Header(Id, DeviceId) VALUES (@Id, @DeviceId);
SELECT @Id AS 'Id';
END
答案 0 :(得分:0)
经过大量测试和谷歌搜索,我发现this blog post帮我找到了解决问题的方法。 我意识到,对于具有相同DbContext的不同设备,我无法在服务器创建的对象和应用程序生成的id上获取数据库生成的id。
所以我需要一种方法来进行2个不同的模型映射,所以我在我的DbContext和OnModelCreating方法上创建了一个UseApiModel属性我设置
modelBuilder.Entity<Header>().Property(t => t.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
和
s.Insert(i => i.HasName("dbo.SpInsertHeader").Result<int>(r => r.Id, "Id"));
或
modelBuilder.Entity<Header>().Property(t => t.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
和
s.Insert(i => i.HasName("dbo.SpApiInsertHeader"));
取决于UseApiModel属性。
Api SP期望有效的Id密钥而另一个SP将生成一个,我需要两个SP,因为EF将根据DatabaseGeneratedOption发送Id属性。
我也使用Colin Angus Mackay建议在INSTEAD OF INSERT上生成Id