Entity Framework 4 и проблема шаблона репозитория - PullRequest
2 голосов
/ 09 июня 2011

Мне трудно понять, правильно ли я это делаю или нет.У меня есть 3 сущности, которые зависят друг от друга.Я пытаюсь добавить новые объекты к этим объектам, а затем вызвать сохранение изменений, в конечном итоге добавив соответствующие записи в таблицы, соблюдая ограничения FK.

Я получаю сообщение об ошибке:

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

enter image description here

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

public void ProcessSurvey(int surveyContentId, int caseNo, string surveyTitle, string reportVersion, string reportXml)
{
    // get surveyid 
    var surveyContent = _surveyContentRepository.GetSurveyContent(surveyContentId);
    // create response obj
    var surveyResponse = new SurveyResponse()
    {
        SurveyId = surveyContent.SurveyId,
        CaseNo = caseNo,
        SurveyTitle = surveyTitle,
        ReportVersion = reportVersion,
        Created = DateTime.Now,
        ResponseXML = reportXml
    };
    // add response obj to context?
    _surveyResponseRepository.Add(surveyResponse);
    // get the questions elements from the xml data
    var questions = SurveyResponseHelper.GetResponseQuestions(reportXml);
    // iterate over questions
    foreach (XElement question in questions)
        {
        SurveyQuestion thisSurveyQuestion = SurveyResponseHelper.ProcSurveyQuestion(question, surveyContentId);
        // add question?
        _surveyQuestionRepository.Add(thisSurveyQuestion);
        // get question answer
        SurveyAnswer thisSurveyAnswer = SurveyResponseHelper.GetAnswer(question);
        //update the answer with the question and response obj to satisfy the FK reference
        thisSurveyAnswer.SurveyQuestion = thisSurveyQuestion;
        thisSurveyAnswer.SurveyResponse = surveyResponse; // This is where it breaks ERRROR: The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects
        _surveyAnswerRepository.Add(thisSurveyAnswer);
        }
    //commit
    _surveyAnswerRepository.Save();
}

Мои репозитории выглядят следующим образом ..

public interface ISurveyAnswerRepository
{
    void Add(SurveyAnswer surveyAnswer);
    void Save();
}
public class SurveyAnswerRepository : Repository, ISurveyAnswerRepository
{

    //private DiversionProgramsEntities _db;

    public SurveyAnswerRepository()
    {
        //_db = new DiversionProgramsEntities();
    }

    public void Add(SurveyAnswer surveyAnswer)
    {
        this.DataContext.SurveyAnswers.AddObject(surveyAnswer);


    }

    public void Save()
    {
        this.DataContext.SaveChanges();

    }

мой базовый репозиторий

public class Repository
{
    private DiversionProgramsEntities _dataContext;

    public DiversionProgramsEntities DataContext
    {
        get { return _dataContext ?? (_dataContext = DatabaseFactory.CreateContext()); }
    }


}

и статический класс / метод для создания контекста

public static class DatabaseFactory
{

    public static DiversionProgramsEntities CreateContext()
    {
        return new DiversionProgramsEntities();
    }

}

вот мой вспомогательный код ..

public class SurveyResponseHelper
{
public static IEnumerable<XElement> GetResponseQuestions(string xmlResponseData)
{
    XElement xmlData = XElement.Parse(xmlResponseData);
    var questions = from n in xmlData.Descendants()
                    where n.Parent.Name.LocalName == "questions"
                    select n;

    return questions;
}

public static SurveyQuestion ProcSurveyQuestion(XElement question, int surveyContentId)
{
    // get the question type
    var questionType = question.Name.LocalName;
    // get question element text. This is the actual question text
    var questionText = question.Elements().Where(e => e.Name.LocalName == "direction").SingleOrDefault().Value;
    // check to see if this question exists in the data table, if it does then we will use the questionid from that which will get used to tie the SurveyAnswer to this question.
    // if question does not already exist then a new one will be created
    SurveyQuestionRepository surveyQuestionRepository = new SurveyQuestionRepository();
    SurveyQuestion surveyQuestion;
    surveyQuestion = surveyQuestionRepository.GetSurveyQuestion(surveyContentId, questionType, questionText);
    if (surveyQuestion == null)
    {
        surveyQuestion = new SurveyQuestion()
        {
            QuestionText = questionText,
            QuestionType = questionType,
            SurveyContentId = surveyContentId
        };
    }

    return surveyQuestion;
}

public static SurveyAnswer GetAnswer(XElement question)
{
    // get the answer index value
    var answers = question.Elements().Where(e => e.Name.LocalName == "answers").SingleOrDefault();
    int userAnswerIndex = Int32.Parse(answers.Attribute("userAnswerIndex").Value);
    // move the answers to an array so we can use the index to get the correct answer
    XElement[] answersArray = answers.Elements().ToArray();
    SurveyAnswer answer = new SurveyAnswer()
    {
        AnswerText = answersArray[userAnswerIndex].Value
    };

    return answer;
}



}

Ответы [ 3 ]

1 голос
/ 09 июня 2011

Откуда приходит ваш _surveyContentRepository? Если он статичен, я мог бы увидеть сценарий, в котором он относится к объекту SurveyContent, который присоединен к одному DiversionProgramsEntities, а ваш метод ProcSurveyQuestion() находит и возвращает существующий SurveyQuestion, присоединенный к другому DiversionProgramsEntities.

Кроме этого, я думаю, что общий указатель, который я могу вам дать, - это присваивать объекты друг другу, используя сами объекты, а не идентификаторы объектов, поэтому вместо:

var surveyResponse = new SurveyResponse { SurveyId = surveyContent.SurveyId }

... использование:

var surveyResponse = new SurveyResponse { Survey = surveyContent }

Это автоматически добавляет новый объект SurveyResponse в тот же контекст объекта, к которому принадлежит объект SurveyContent, и означает, что вам не нужно ничего добавлять вручную в хранилище. Вы можете собрать весь свой граф объектов таким образом, а затем вызвать Save() в хранилище, которое вы использовали для извлечения первого объекта, чтобы сохранить все это.

1 голос
/ 09 июня 2011

Похоже, ошибка прекрасно описывает, что происходит. В следующей строке:

var questions = SurveyResponseHelper.GetResponseQuestions(reportXml);

Вы получаете вопрос из другого класса. Этот класс, вероятно, создает свой собственный объектный контекст.

Вы не можете прикрепить вопрос к ответу, если он из разных контекстов объекта.

Чтобы решить эту проблему, проще всего добавить параметр в ваши методы GetResponseQuestions для datacontext, чтобы ваш другой метод мог использовать этот datacontext репозитория для получения вопросов.

Кроме того, различные методы IoC упростили бы это.

0 голосов
/ 09 июня 2011

Как @TimHoolihan заявил, что проблема заключается в том, что вы не используете один и тот же контекст данных для доступа к ответам на опрос и вопросам опроса, и на самом деле я считаю, что строки вопроса в строке ниже из метода ProcSurveyQuestion.

    SurveyQuestionRepository surveyQuestionRepository = new SurveyQuestionRepository();

Я вижу, что у вас есть одноэлементный DataContext в классе DiversionProgramsEntities, но я не могу вывести из вашего кода, если SurveyQuestionRepository и SurveryResponseRepositories также используют этот же контекст.Исходя из полученной ошибки, я предполагаю, что они используют разные контексты, поэтому, как и @TimHoolihan, вам нужно изменить код, чтобы он использовал один и тот же контекст для обоих.

Вам также следует изучитьшаблон UnitOfWork , поскольку это то, чего вы пытаетесь достичь, но у вас нет общего контекста для отслеживания всех ваших изменений.

...