Entity Framework вставляет объект с несколькими свойствами навигации одинакового типа и идентификатора - PullRequest
0 голосов
/ 04 октября 2018

Я прочитал несколько сообщений об этом (например, Почему EF не может обработать два свойства с одним и тем же внешним ключом, но с отдельными ссылками / экземплярами? ), но ни одно из них не дало удовлетворительного решения.

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

Настройка:

public abstract class EntityBase
{
    public int Id { get; set; }
    public bool IsTransient => Id <= 0;
}

public class Person : EntityBase
{
    public string Name { get; set; }
}

public class Task : EntityBase
{
    public int CreatorId { get; set; }
    public int ReceiverId { get; set; }
    public string Text { get; set; }

    public Person Creator { get; set; }
    public Person Receiver { get; set; }
}

Когда я пытаюсь вставить новую задачу, подобную следующей, возникает исключение, когда creator и receiver имеют одинаковые Person (т.е. имеют одинаковое значение Id). Исключение составляет: «... потому что несколько сущностей типа« Персона »имеют одно и то же значение первичного ключа.».

public void AddTask(string text, Person creator, Person receiver)
{
    using (var context = new MyEntities())
    {
        Task task = new Task()
        {
            Text = text,
            Creator = creator,
            Receiver = receiver
        };
        context.Task.Add(task);
        context.Entry(creator).State = EntityState.Unchanged;
        context.Entry(receiver).State = EntityState.Unchanged; // Exception is raised here

        context.SaveChanges();
    }
}

Исключение можно избежать, используя следующий код:

public void AddTask(string text, Person creator, Person receiver)
{
    using (var context = new MyEntities())
    {
        Task task = new Task()
        {
            Text = text,
            Creator = creator,
            Receiver = receiver
        };
        context.Task.Add(task);
        context.Entry(creator).State = EntityState.Unchanged;
        if (creator.Id == receiver.Id)
            task.Receiver = creator;
        else
            context.Entry(receiver).State = EntityState.Unchanged;

        context.SaveChanges();
    }
}

Вопрос: Есть ли какой-нибудь удобный способ избежать исключения, кроме проверки значений Id свойств навигации перед вставкой?

Это простой экзаменЗдесь дано.Есть гораздо более сложные графы объектов, которые нужно вставить, когда ручная проверка, как показано здесь, довольно громоздка.

РЕДАКТИРОВАТЬ: Сообщение об исключении (немецкий):

System.InvalidOperationException: Fehler beim Speichern oder Übernehmen der Änderungen, weil mehrere Entitäten des Typs 'Person' den gleichen Primärschlüsselwert aufweisen.Stellen Sie sicher, dass explizit festgelegte Primärschlüsselwerte eindeutig sind.Die von der Datenbank genierten Primärschlüssel müssen in der Datenbank and im Entity Framework-Modell ordnungsgemäß konfiguriert sein.Verwenden Sie Den Entity Designer для базы данных Первая / Модель Первая Конфигурация.Veruenden Sie die Fluent-API 'HasDatabaseGeneratedOption' oder 'DatabaseGeneratedAttribute' für die Code First-Konfiguration.

Причина, по которой я явно установил EntityState, заключается в том, что я работаю с отсоединенными объектами.Если бы я не установил состояние объекта Person, он был бы вставлен как новая запись.Чтобы избежать этого, я отмечаю это как Unchanged.

1 Ответ

0 голосов
/ 04 октября 2018

Вы можете просто установить Id:

using (var context = new MyEntities())
{
    Task task = new Task()
    {
        Text = text,
        CreatorId = creator.Id,
        ReceiverId = receiver.Id
    };
    context.Task.Add(task);
    context.SaveChanges();
}
...