Подтвердить что ты не робот

Произошла ошибка при сохранении объектов, которые не раскрывают свойства внешнего ключа для своих отношений

У меня есть просто код в коде Entity Framework 4.1:

PasmISOContext db = new PasmISOContext();
var user = new User();
user.CreationDate = DateTime.Now;
user.LastActivityDate = DateTime.Now;
user.LastLoginDate = DateTime.Now;
db.Users.Add(user);

db.SaveChanges();
user.Avatar = new Avatar() { Link = new Uri("http://myUrl/%2E%2E/%2E%2E") };
db.SaveChanges();


db.Users.Add(new User() { Avatar = new Avatar() { Link = new Uri("http://myUrl/%2E%2E/%2E%2E") } });
db.SaveChanges();

Проблема в том, что я получаю сообщение об ошибке

Произошла ошибка при сохранении объектов, которые не отображают внешний ключ свойства для их отношений. Свойство EntityEntries будет return null, потому что один объект не может быть идентифицирован как источник исключения. Обработка исключений при сохранении может быть выполнена проще, выставляя свойства внешнего ключа в своих типах объектов. Видеть InnerException для деталей.

at

db.Users.Add(new User() { Avatar = new Avatar() { Link = new Uri("http://myUrl/%2E%2E/%2E%2E") } });
db.SaveChanges();

Я не понимаю, почему работает аналогичная операция. Что-то не так с моей моделью или с первым ef-кодом?

public class Avatar
{
    [Key]
    public int Id { get; set; }

    [Required]
    public string LinkInString { get; set; }

    [NotMapped]
    public Uri Link
    {
        get { return new Uri(LinkInString); }
        set { LinkInString = value.AbsoluteUri; }
    }
}

public class User
{
    [Key]
    public int Id { get; set; }
    public string UserName { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public Avatar Avatar { get; set; }
    public virtual ICollection<Question> Questions { get; set; }
    public virtual ICollection<Achievement> Achievements { get; set; }

    public DateTime CreationDate { get; set; }
    public DateTime LastLoginDate { get; set; }
    public DateTime LastActivityDate { get; set; }
}
4b9b3361

Ответ 1

Для тех из вас, кто все еще будет иметь эту ошибку со всеми правильно определенными ключами, посмотрите на свои сущности и убедитесь, что вы не оставили поле datetime с нулевым значением.

Ответ 2

Это сообщение об ошибке может быть отправлено по любой причине. Свойство InnerException (или его внутреннее исключение или внутреннее исключение этого и т.д.) Содержит фактическую основную причину проблемы.

Конечно, было бы полезно узнать что-то о том, где возникла проблема - какой объект в единице работы вызывает проблему? Сообщение об исключении обычно укажет вам в свойстве EntityEntries, но в этом случае по какой-то причине это невозможно сделать. Это диагностическое осложнение - свойство "EntityEntries" пустое - видимо, потому что некоторые объекты "не раскрывают свойства внешнего ключа для своих отношений".

Даже если OP получает ошибку из-за невозможности инициализировать DateTime для второго экземпляра User, они получают диагностическое осложнение - "EntityEntries" пуст и запутанное сообщение верхнего уровня... потому что один из их Entity не раскрывает свойства внешнего ключа. Чтобы исправить это, Avatar должно иметь свойство public virtual ICollection<User> Users { get; set; }.

Ответ 3

Проблема была решена путем добавления свойства FK.

Ответ 4

В моем случае следующая ситуация давала мне то же Исключение:

Представьте себе первую EF-модель кода, в которой у вас есть объект Garage, у которого есть коллекция объектов Car. Мне нужно было снять машину из гаража, поэтому я закончил с кодом, который выглядел так:

garageEntity.Cars.Remove(carEntity);

Вместо этого он должен был выглядеть так:

context.Cars.Remove(carEntity);

Ответ 5

Просто для других, у кого могут быть подобные проблемы. У меня была такая же ошибка, но по другой причине. В одном из дочерних объектов я определил [Key] как значение, которое было одинаковым для разных значений. Глупая ошибка с моей стороны, но сообщение об ошибке сразу не приводит вас к проблеме.

Ответ 6

В моем случае исключение было выбрано потому, что EF неправильно создал миграцию. Он пропустил настройку identity: true во второй таблице. Поэтому перейдите в миграцию, которая создала соответствующие таблицы, и проверьте, не было ли упущено ее добавления.

CreateTable(
    "dbo.LogEmailAddressStats",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            EmailAddress = c.String(),
        })
    .PrimaryKey(t => t.Id);

CreateTable(
    "dbo.LogEmailAddressStatsFails",
    c => new
        {
            Id = c.Int(nullable: false), // EF missed to set identity: true!!
            Timestamp = c.DateTime(nullable: false),
        })
    .PrimaryKey(t => t.Id)
    .ForeignKey("dbo.LogEmailAddressStats", t => t.Id)
    .Index(t => t.Id);

Столбец Id должен иметь идентификатор (т.е. автоматически увеличивать!), поэтому это должна быть ошибка EF.

Вы можете добавить личность вручную с SQL непосредственно в базу данных, но я предпочитаю использовать Entity Framework.

Если вы столкнулись с той же проблемой, я вижу два простых решения:

Alt 1

измените неверно созданную миграцию с помощью

update-database -target:{insert the name of the previous migration}

Затем добавьте идентификатор: true вручную в код миграции, а затем обновите базу данных снова.

Alt 2

создается новая миграция, которая добавляет идентификатор. Если у вас нет изменений в моделях, и вы запустите

add-migration identity_fix

он создаст пустую миграцию. Затем просто добавьте этот

    public partial class identity_fix : DbMigration
    {
        public override void Up()
        {
            AlterColumn("dbo.LogEmailAddressStatsFails", "Id", c => c.Int(nullable: false, identity: true));
        }

        public override void Down()
        {
            AlterColumn("dbo.LogEmailAddressStatsFails", "Id", c => c.Int(nullable: false));
        }
    }

Ответ 7

Эта проблема также может возникать из обращенных ключевых объявлений. Если вы свободно используете для настройки отношения, убедитесь, что левая и правая клавиши сопоставлены с правильным объектом.

Ответ 8

Другой ответ:

Я использовал это:

public List<EdiSegment> EdiSegments { get; set; }

вместо этого:

public virtual ICollection<EdiSegment> EdiSegments { get; set; }

и получил сообщение об ошибке, указанное выше.

Ответ 9

У меня была такая же ошибка, и в моем случае проблема заключалась в том, что я добавил объект отношения, который уже был загружен "AsNoTracking". Мне пришлось перезагрузить свойство отношения.

Кстати, некоторые предлагают использовать "Attach" для отношений, которые уже существуют в db, но я не пробовал этот параметр.

Ответ 10

У меня была такая же проблема. в моем случае это произошло из-за поля datetime с нулевым значением. Мне пришлось пропустить значение datetime, и все было хорошо.

Ответ 11

В моем случае проблема заключалась в том, что я неправильно переименовал столбец, поэтому миграция сделала два столбца, один из которых называется "TeamId", а один - "TeamID". С# заботится, SQL не делает.

Ответ 12

Еще один другой случай. Запрос был добавлен в список, и при этом он создал сущности своим конструктором для сравнения в выражении linq сразу после ToList(). Это создало объекты, которые вошли в удаленное состояние после завершения выражения linq.
Однако! Была небольшая настройка, которая создала другой объект в конструкторе, чтобы этот новый объект был связан с сущностью, которая была отмечена как "Удалена".

Некоторый код для иллюстрации:

query.Except(_context.MyEntitySetSet()
                .Include(b => b.SomeEntity)
                .Where(p => Condition)
                .ToList() // This right here calls the constructor for the remaining entities after the where
                .Where(p => p.Collection.First(b => Condition).Value == 0)
                .ToList();

Конструктор MyEntity:

public partial class MyEntity
{
    protected MyEntity()
    {
        // This makes the entities connected though, this instance of MyEntity will be deleted afterwards, the instance of MyEntityResult will not.
        MyEntityResult = new MyEntityResult(this);
    }
}

Мое решение состояло в том, чтобы убедиться, что все выражение было сделано внутри IQueryable, чтобы не было создано никаких объектов.

Ответ 13

Я не совсем уверен, что это поможет в вашем случае, потому что я настраиваю свои таблицы с использованием Fluent API, однако, насколько я могу судить, проблема возникает независимо от того, настроена ли схема с использованием аннотаций данных (атрибуты) или Fluent API (конфигурация).

Кажется, что в EF (v. 6.1.3) есть ошибка, поскольку при обновлении базы данных до следующей миграции она не учитывает определенные изменения схемы. Самый быстрый маршрут вокруг него (на этапе разработки) - удалить все таблицы из DB и runt migrations из этапа init снова.

Если вы уже в производстве, самое быстрое решение, которое я нашел, это вручную изменить схему в БД или, если вы хотите иметь управление версиями изменений, вручную манипулировать методами Up() и Down ( ) в вашей миграции.