Entity framework 4 实体框架4和存储库模式问题

Entity framework 4 实体框架4和存储库模式问题,entity-framework-4,repository-pattern,Entity Framework 4,Repository Pattern,我很难理解我做的是否正确。我有3个相互依赖的实体。我试图向这些实体添加新对象,然后调用save changes,最终将相应的记录添加到符合FK约束的表中 我得到一个错误: 无法定义两个对象之间的关系,因为它们附加到不同的ObjectContext对象。 在我的代码中,我正在使用linq解析一些XML,同时将新对象添加到上下文中。在我的服务层中,我有以下方法来处理传入数据 public void ProcessSurvey(int surveyContentId, int caseNo, str

我很难理解我做的是否正确。我有3个相互依赖的实体。我试图向这些实体添加新对象,然后调用save changes,最终将相应的记录添加到符合FK约束的表中

我得到一个错误:

无法定义两个对象之间的关系,因为它们附加到不同的ObjectContext对象。

在我的代码中,我正在使用linq解析一些XML,同时将新对象添加到上下文中。在我的服务层中,我有以下方法来处理传入数据

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;
}



}
公共类调查响应帮助
{
公共静态IEnumerable GetResponseRequestions(字符串xmlResponseData)
{
XElement xmlData=XElement.Parse(xmlResponseData);
var questions=来自xmlData.subjects()中的n
其中n.Parent.Name.LocalName==“问题”
选择n;
回答问题;
}
公共静态调查问题程序调查问题(XElement问题,int Survey内容ID)
{
//获取问题类型
var questionType=question.Name.LocalName;
//获取问题元素文本。这是实际的问题文本
var questionText=question.Elements().Where(e=>e.Name.LocalName==“direction”).SingleOrDefault().Value;
//检查数据表中是否存在此问题,如果存在,我们将使用用于将调查和回答与此问题联系起来的问题ID。
//如果问题不存在,则将创建一个新问题
SurveyQuestionRepository SurveyQuestionRepository=新建SurveyQuestionRepository();
调查问题调查问题;
surveyQuestion=surveyQuestionRepository.GetSurveyQuestion(surveyContentId,questionType,questionText);
如果(surveyQuestion==null)
{
surveyQuestion=新的surveyQuestion()
{
QuestionText=QuestionText,
QuestionType=QuestionType,
SurveyContentId=SurveyContentId
};
}
返回调查问题;
}
公共静态调查回答(问题)
{
//获取答案索引值
var answers=question.Elements()。其中(e=>e.Name.LocalName==“answers”).SingleOrDefault();
int userAnswerIndex=Int32.Parse(answers.Attribute(“userAnswerIndex”).Value);
//将答案移动到数组中,这样我们就可以使用索引来获得正确的答案
XElement[]answersArray=answers.Elements().ToArray();
SurveyAnswer answer=新的SurveyAnswer()
{
AnswerText=answersArray[userAnswerIndex]。值
};
返回答案;
}
}

看起来错误完美地描述了正在发生的事情。在以下行中:

var questions = SurveyResponseHelper.GetResponseQuestions(reportXml);
你从另一个班级得到一个问题。该类可能会创建自己的对象上下文

如果问题来自不同的对象上下文,则不能将其附加到答案

要解决这个问题,最简单的方法是为datacontext的GetResponseQuestions方法添加一个参数,以便其他方法可以使用存储库datacontext来获取问题


此外,各种IoC方法可以简化这一过程。

您的
\u调查内容来自哪里?如果它是静态的,我可以看到这样一个场景:它保留一个
SurveyContent
对象,该对象附加到一个
DiversionProgramSenties
,并且您的
ProSurveyQuestion()
方法查找并返回一个现有的
SurveyQuestion
,附加到另一个
DiversionProgramSenties

除此之外,我认为我可以给你一个通用的指针,就是使用对象本身而不是对象ID来分配对象给彼此,因此,不要:

var surveyResponse = new SurveyResponse { SurveyId = surveyContent.SurveyId }
…使用:

var surveyResponse = new SurveyResponse { Survey = surveyContent }

这会自动将新的
SurveyResponse
对象添加到
SurveyContent
对象所属的同一对象上下文中,这意味着您无需手动向存储库添加任何内容。您可以像这样组装整个对象图,然后调用
Save()
在用于检索第一个对象以保存整个内容的存储库上。

正如@TimHoolihan所述,问题在于您没有使用相同的数据上下文来访问调查响应和调查问题,事实上,我相信ProSurveyQuestion方法下面一行中的问题行

    SurveyQuestionRepository surveyQuestionRepository = new SurveyQuestionRepository();
我看到您在DiversionProgramSenties类中有一个单例数据上下文,但我无法从您的代码推断SurveyQuestionRepository和SurveyResponseRepositories是否也使用相同的上下文。根据您得到的错误,我猜他们使用的是不同的上下文,所以正如@TimHoolihan所建议的,您需要修改代码,以便对两者使用相同的上下文


您还应该研究该模式,因为这是您在这里试图完成的,但是您没有一个通用的上下文来跟踪所有的更改。

SurveyResponseHelper.GetResponseQuestions()方法只返回一个IEnumerable。在对这些对象进行迭代时,我使用SurveyResponseHelper.ProcSurveyQuestion()方法返回SurveyQuestion对象,我没有使用上下文,只是在其中使用了new SurveyQuestion..Steve,我的存储库实例在服务类构造函数中是新的。这是一个现有的应用程序,所以我不想尝试将其纳入Ioc容器中。对于在构造函数方法中初始化的每个repo实例,我都有一个私有字段。我认为我有一个公共的上下文,我的所有存储库都使用相同的基本存储库,这是从静态工厂方法创建上下文的地方。如果我在我的一个存储库之外新建一个实体的实例,你说呢