I want to use EF code first to connect my model classes to my database, for example:
public partial class Header
{
public int Id { get; set; }
public int DeviceId { get; set; }
...
}
and in my 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"));
});
}
The DeviceId is fixed to the device that the record is generated, and the Id is the identity generated on that device. This DbContext is used to sync all the devices data on the server.
The problem with this code is that on insert, i get this error: A result binding for the property 'Id' was not found on the modification function 'SpInsertHeader'. Ensure that the property is database generated.
And if i set [DatabaseGenerated(DatabaseGeneratedOption.Computed)] attribute or [DatabaseGenerated(DatabaseGeneratedOption.Identity)] that property is never sent to the stored procedure
What can i do to enable this scenario?
EDIT
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
After much testing and googling, i found this blog post with help me found a solution to my problem. I realize that i cannot get the database generated id, on the server created objects, and app generated id, for the diferent devices with the same DbContext.
So i need a way to have to 2 diferent model mappings, so i created a UseApiModel property on my DbContext and on the OnModelCreating method i set
modelBuilder.Entity<Header>().Property(t => t.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
and
s.Insert(i => i.HasName("dbo.SpInsertHeader").Result<int>(r => r.Id, "Id"));
or
modelBuilder.Entity<Header>().Property(t => t.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
and
s.Insert(i => i.HasName("dbo.SpApiInsertHeader"));
Depending on the UseApiModel property.
The Api SP expect a valid Id key and the other SP will generate one, i need two SP's because EF will send the Id property or not depending on the DatabaseGeneratedOption.
I also use the Colin Angus Mackay advise to generate the Id on a INSTEAD OF INSERT
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.