Отношение один к нулю или один: невозможно вставить явное значение для столбца идентификаторов в таблице, когда IDENTITY_INSERT имеет значение OFF - PullRequest
0 голосов
/ 29 декабря 2018

У меня есть две сущности:

public class Subscription
{
    public int SubscriptionId { get; set; }

    public virtual ICollection<SubscriptionError> SubscriptionErrors { get; set; }
}

public class SubscriptionError
{
    public int SubscriptionErrorId { get; set; }
    public int SubscriptionId { get; set; }

    public virtual Subscription Subscription { get; set; }
}

Первоначально я определил отношения между ними как один-ко-многим в SubscriptionErrorMap следующим образом:

this.HasRequired(t => t.Subscription)
            .WithMany(t => t.SubscriptionErrors)
            .HasForeignKey(d => d.SubscriptionId)
            .WillCascadeOnDelete(false);

Я естьиспользуя следующий код для сохранения SubscriptionError:

context.SubscriptionErrors.Add(subscriptionError);

, где subscriptionError - это сущность, и я явно не задаю поле первичного ключа.

Это нормально работало.Но когда я изменил это отношение на one to zero-or-one, он начал генерировать следующее исключение при сохранении:

Невозможно вставить явное значение для столбца идентификаторов в таблице 'SubscriptionError', когда для IDENTITY_INSERT установлено значение OFF.

Новое отображение:

this.HasRequired(t => t.Subscription)
            .WithOptional(t => t.SubscriptionError)
            .WillCascadeOnDelete(false);

Что-то не так с отображением?

Ответы [ 2 ]

0 голосов
/ 01 января 2019

Вот что у меня сработало:

Удалите поле PK SubscriptionErrorId и установите SubscriptionId как PK и FK для SubscriptionError.

Объекты теперь будут выглядеть какследующее:

public class Subscription
{
     public int SubscriptionId { get; set; }

     public virtual SubscriptionError SubscriptionError { get; set; }
}

public class SubscriptionError
{
    [ForeignKey("Subscription")]
    public int SubscriptionId { get; set; }

    [Required]
    public virtual Subscription Subscription { get; set; }
}
0 голосов
/ 29 декабря 2018

Из того, что я вижу, скрипт модели БД выглядит примерно так:

CREATE TABLE Subscription(
    [SubscriptionId] [int] IDENTITY(1,1) NOT NULL,
    --[FieldName1] [nchar](100) NULL,
    --[FieldNameN] [nchar](100) NULL,
 CONSTRAINT [PK_Subscription] PRIMARY KEY CLUSTERED 
(
    [SubscriptionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE SubscriptionError(
    [SubscriptionErrorId] [int] NOT NULL,
    [SubscriptionId] [int] NULL,
    --[FieldName1] [nchar](100) NULL,
    --[FieldNameN] [nchar](100) NULL,
 CONSTRAINT [PK_SubscriptionError] PRIMARY KEY CLUSTERED 
(
    [SubscriptionErrorId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE SubscriptionError  WITH CHECK ADD  CONSTRAINT [FK_SubscriptionError_Subscription] FOREIGN KEY([SubscriptionId])
REFERENCES Subscription ([SubscriptionId]) 
ALTER TABLE [dbo].[SubscriptionError] CHECK CONSTRAINT [FK_SubscriptionError_Subscription] 

Который [SubscriptionErrorId] является ключевым, но это не поле с автоматическим приращением, поэтому для one-to-many реляционная модель должна быть такой, как показано ниже:

public partial class Subscription
{ 
    public Subscription()
    {
        SubscriptionErrors = new HashSet<SubscriptionError>();
    } 
    public int SubscriptionId { get; set; } 
    public virtual ICollection<SubscriptionError> SubscriptionErrors { get; set; }
}

и для SubscriptionError:

public partial class SubscriptionError
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int SubscriptionErrorId { get; set; } 
    public int? SubscriptionId { get; set; } 
    public virtual Subscription Subscription { get; set; }
}

Это работает как брелок, но для one-to-one или one-to-zero отношений, которые SubscriptionError для Subscription не являются коллекциейи отношение должно быть определено свободно текущими API, как показано ниже:

modelBuilder.Entity<Subscription>()
    .HasOptional(s => s.SubscriptionError)
    .WithRequired(ad => ad.Subscription);

и модели:

public partial class Subscription
{
    public Subscription()
    {
    }
    public int SubscriptionId { get; set; }
    public virtual SubscriptionError SubscriptionError { get; set; }
}
public partial class SubscriptionError
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int SubscriptionErrorId { get; set; }
    public int? SubscriptionId { get; set; }
    public virtual Subscription Subscription { get; set; }
}

, поэтому, пожалуйста, посмотрите на SubscriptionError вашей БД и проверьте, какие свойствав любом случае установите для SubscriptionError в соглашениях EF, когда будет найдено свойство Id pk (SubscriptionErrorId заканчивается Id, а EF интерпретирует его как первичный ключ), он сконфигурирует этот столбец как идентификатор, который означает, что база данных генерирует значение для свойства ключа,например, auto SubscriptionErrorId будет автоматически сопоставлен с ключом идентификации, и нет необходимости явно его украшать DatabaseGeneratedOption, но здесь используется DatabaseGeneratedOption.None, потому что этот ключ должен генерироваться прагмой кода

о вашей проблеме , когда мы определили отношение one-to-one, это означает, что дочерний элемент не означает, что его родитель не существует, по этой причине внешний ключ является первичным ключом в этой ситуации.!!!для вашей модели для режима SubscriptionError опора SubscriptionId также является ключевой из-за отношения один к одному или нулю, если вы посмотрите на образец в здесь нет PK в StudentAddress в любом случае в вашей ситуации SubscriptionError с автоматической генерацией SubscriptionErrorId, если вы не определите PK, вы получите

SubscriptionError: EntityType: EntitySet 'SubscriptionError'основан на типе' SubscriptionError ', для которого не определены ключи.

если вы определите этот столбец как ключ с порядком, например:

[Key, Column("SubscriptionErrorId", Order = 1)]
public int SubscriptionErrorId { get; set; } 
[Key, Column("SubscriptionId", Order = 2)]
public int SubscriptionId { get; set; }

, вы также получите

Объекты в Model.SubscriptionError участвуют в отношениях Subscription_SubscriptionError.0 связанных 'Subscription_SubscriptionError_Source' были найдены.1 'Subscription_SubscriptionError_Source' ожидается. '

, но если ваша модель выглядит примерно так, как указано ниже, определите SubscriptionErrorId как Identity и определите SubscriptionId как ключ, который SubscriptionErrorId является автоматическимприращение:

public partial class SubscriptionError
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int SubscriptionErrorId { get; set; } 
    [Key]
    public int SubscriptionId { get; set; } 
    public virtual Subscription Subscription { get; set; }
}

тогда ваш код будет работать как брелок:

using (var context = new DbContext())
{
    var se = new SubscriptionError()
    {
        FieldName1 = "Value",
        SubscriptionId = 1,//Parent key
        //SubscriptionErrorId is auto 
    };
    context.SubscriptionError1.Add(se);
    context.SaveChanges();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...