簡體   English   中英

SqlException:當 IDENTITY_INSERT 設置為 OFF 時,無法為表 [表名] 中的標識列插入顯式值

[英]SqlException: Cannot insert explicit value for identity column in table [Table name] when IDENTITY_INSERT is set to OFF

我正在創建一個用於費用跟蹤的網站,當我發送一個新的 POST 請求調用AddNew方法來添加一個新條目時,我收到此錯誤:

SqlException:當 IDENTITY_INSERT 設置為 OFF 時,無法為表“Accounts”中的標識列插入顯式值。 當 IDENTITY_INSERT 設置為 OFF 時,無法為表 'Categories' 中的標識列插入顯式值。

public class Entry
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Description { get; set; }
    public decimal MoneyAmount { get; set; }
    public virtual Account Account { get; set; }
    public virtual Category Category { get; set; }
    public string CreatedTimestamp { get; set; }
}

public class Account
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual User User { get; set; }
    //public byte[] BankApi { get; set; }
    public decimal MoneyAmount { get; set; }
    public string CreatedTimestamp { get; set; }
    public virtual ICollection<Entry> Entries { get; set; }
}

public class Category
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual EntryType EntryType { get; set; }
    public virtual ICollection<Entry> Entries { get; set; }
}

public interface IEntryService
{
    void AddNew(Entry entry);
}

public class EntryService : IEntryService
{
    private DataContext _context;

    public EntryService(DataContext context)
    {
        _context = context;
    }

    public void AddNew(Entry entry)
    {
        entry.CreatedTimestamp = DateTime.Now.ToString();

        _context.Entries.Add(entry);
        _context.SaveChanges();
    }
}

這是我的郵遞員請求:

郵遞員請求

ID == 1 的帳戶和 ID == 1 的類別都已存在於各自的數據庫中。

此外,當我向 Account 數據庫插入值時,其方法與條目的AddNew完全相同,它可以正常工作。

有誰知道這是關於什么的?

問題是您將具有關系的實體傳遞回服務器。 每個請求都由不同的數據庫上下文提供服務,因此雖然您的條目及其關聯的帳戶和類別看起來像實體,但它們不是。 它們是 DbContext 一無所知的反序列化 POCO 對象。 當您傳遞引用數據庫中已存在的其他實體的實體時,接收上下文不知道這些實體,因此它將它們解釋為新記錄並嘗試插入它們。

我的默認建議是永遠不要在客戶端和服務器之間傳遞實體。 這會導致從服務器到客戶端的序列化錯誤和性能問題,並使您的系統暴露於篡改,以及在從客戶端到服務器使用時插入錯誤或重復等問題。

要在沒有太多更改的情況下解決您的問題:

public void AddNew(Entry entry)
{
    entry.CreatedTimestamp = DateTime.Now.ToString();
    var account = _context.Accounts.Single(x => x.Id = entry.Account.Id);
    var category = _context.Categories.Single(x => x.Id = entry.Category.Id);
    entry.Account = account; 
    entry.Category = category;
    _context.Entries.Add(entry);
    _context.SaveChanges();
}

這將條目帳戶和類別與上下文已知的實例相關聯。

另一種方法是將傳遞回 DbContext 的帳戶和類別附加到。 這也可以,但它會使您的系統容易受到篡改。 傳回控制器的數據可以被客戶端機器上的調試工具或嗅探器截獲,其中可以更改消息中的數據,以您不希望的方式更改記錄及其相關記錄中的詳細信息。 如果出於任何原因,任何代碼最終將這些重新附加的實體設置為修改狀態,則這些更改將在 SaveChanges 上持久保存到數據庫中。 在處理多個分離的引用時,附加實體也很麻煩。 例如,如果您一次與親戚保存多條記錄。 當所有親戚都是唯一的時,附加每個都可以正常工作,但是如果沒有額外的邏輯來檢查每個人以查看是否已經附加了引用,則在嘗試對已附加(或加載)實體附加的第二個引用時,您可能會收到錯誤. 這意味着更多的代碼來檢查本地關聯並在找到時替換它。

我剛剛改變了條目模型

public class Entry
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Description { get; set; }
    public decimal MoneyAmount { get; set; }
    public virtual Account Account { get; set; }
    public virtual Category Category { get; set; }
    public string CreatedTimestamp { get; set; }
}

對此:

 public class Entry
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public string Description { get; set; }
        public decimal MoneyAmount { get; set; }
        public int AccountId { get; set; }
        public int CategoryId { get; set; }
        public string CreatedTimestamp { get; set; }
    }

現在似乎一切正常。 C# 發揮了它的魔力,並選擇 AccountId 和 CategoryId 作為外鍵。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM