0
votes

I'm seeing a strange behavior from Entity Framework. I'm using code-first approach to define a One-To-Many relationship between two entities:

public class IncomingCheck : AuditedEntityBase
{
    [Key]
    public int Id { get; set; }

    [Required]
    public virtual CheckType Type { get; set; }

    [Required]
    public virtual Bank Bank { get; set; }
    public string Branch { get; set; }

    public virtual IList<IncomingCheckHistory> History { get; set; }
}

public class IncomingCheckHistory
{
    [Key]
    public int Id { get; set; }
    public string LongDescription { get; set; }
}

And here's I I'm trying to add an item to the History:

using (var db = new CheckDataContext())
{
    foreach (var check in SelectedItems)
    {
        var dbCheck = await db.IncomingChecks.FindAsync(check.Id);

        var history = new IncomingCheckHistory()
        {
            LongDescription = "something",
        };

        dbCheck.History.Add(history);
        await db.SaveChangesAsync(); //throws the exception
    }
}

But it throws an exception saying that "Cannot insert the value NULL into column 'Id'". However I've always done it like this. The database is supposed to fill the Id column itself with a unique number.

What am I missing?

Update:

Using SSProfiler, I got the query that runs on the database. It's as follows:

exec sp_executesql N'INSERT [dbo].[IncomingCheckHistories]([LongDescription], [IncomingCheck_Id])
VALUES (@0, @1)
SELECT [Id]
FROM [dbo].[IncomingCheckHistories]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()',N'@0 nvarchar(max) ,@1 int',@0=N'Something',@1=1

Note that scope_identity() should be getting the Id itself, correct?

2
check the table design if ID is identity seeded, if it is then you will need to exclude it from the insert. - RoMEoMusTDiE
@maSTAShuFu It is. I'm using EF, how am I supposed to exclude it? Also since I've always added entities like this, why doesn't this one work?! - Alireza Noori
You can add incoming check and a corresponding forgien key prop to the history class and set the key with out getting the check. This will save you a db call and may fix the issue. - rahicks
@rahicks Tried that too, no luck :( - Alireza Noori

2 Answers

0
votes

Shouldn't the Id be set as the Identity? Like this:

public class IncomingCheckHistory
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Key]
    public string LongDescription { get; set; }
}

Hope that this is the solution to your problem!

0
votes

Well for some strange reason the exact code worked after completely deleting the database and migrations and starting from scratch. I'm not sure why it wouldn't work without migrations. Also I had tried deleting the database before but at the time I was trying a little different code.

In any case the posted code/query should work. Also I checked the database and the columns to see if anything is different and it wasn't. I would appreciate if someone could shed some light on why it wasn't working and it is now.