Сложный Entity Framework проблема связанных графов: как ограничить изменение, установить / сломать граф? - PullRequest
2 голосов
/ 06 мая 2010

У меня есть EDMX, содержащий Sentences, и Words, скажем, а Sentence содержит три Words, скажем. Соответствующие FK-отношения существуют между таблицами.

Я создаю несколько слов: Word word1 = new Word(); Word word2 = ...

Я строю предложение: Sentence x = new Sentence (word1, word2, word3);

Я строю другое предложение: Sentence y = new Sentence (word1, word4, word5);

Я пытаюсь сохранить x в базе данных, но EF создает набор изменений, который включает в себя все, включая y, word4 и word5, которые не готовы к сохранению в базе данных. Когда происходит SaveChanges (), возникает исключение: Невозможно определить основной конец отношения .... Несколько добавленных объектов могут иметь один и тот же первичный ключ.

Я думаю, что это происходит потому, что Word имеет EntityCollection<Sentence> из отношения FK между двумя таблицами, и, таким образом, Предложение y неразрывно связано с Приложением x через word1.

Поэтому я удаляю свойство навигации Sentences из Word и повторяю попытку. Он все еще пытается поместить весь график в набор изменений.

Какие предложения есть у экспертов Entity Framework относительно способов разорвать эту связь. По сути, мне нужно одностороннее сопоставление от Sentence до Word; Я не хочу, чтобы EntityCollection<Sentence> в Word, и я не хочу, чтобы граф объектов переплетался, как это.

Пример кода: Это помещает два предложения в базу данных, потому что Verb1 связывает их, а EF исследует весь график существующих и добавленных объектов, когда вы делаете Add / SaveChanges.

    Word subject1 = new Word(){ Text = "Subject1"};
    Word subject2 = new Word(){ Text = "Subject2"};
    Word verb1 = new Word(){ Text = "Verb11"};
    Word object1 = new Word(){ Text = "Object1"};
    Word object2 = new Word(){ Text = "Object2"};


    Sentence s1 = new Sentence(){Subject = subject1, Verb=verb1, Object=object1};
    Sentence s2 = new Sentence(){Subject=subject2, Verb=verb1, Object=object2};

    context.AddToSentences(s1);
    context.SaveChanges();

    foreach (var s in context.Sentences)
    {
        Console.WriteLine(s.Subject + " " + s.Verb + " " + s.Object);
    }

1 Ответ

1 голос
/ 07 мая 2010

Одна альтернатива, которая действительно работает, - переименовать и скрыть сгенерированные базой данных свойства (например, SubjectP), сохранить отдельную частную копию установленного Word и затем исправить ее во время сохранения:

в предложении:

    private Word subject;
    ...

    public Word Subject { get {return this.subject ?? this.SubjectP;} set {this.subject = value; }}

    public void FixSelfUp()
    {
        if (this.subject != null && subject != this.SubjectP) this.SubjectP = this.subject;
    ...

А в SaveChanges () ...

    var items = this.context.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added | System.Data.EntityState.Modified);
    // now iterate over them, find any Sentences and call to fix them up.

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

Но, несомненно, есть лучший способ, чем этот!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...