如何在同一类型的实体中拥有多个列表?

时间:2015-02-09 21:30:39

标签: c# asp.net-mvc entity-framework table-per-type

我有一个实体,需要有多个另一个实体的列表。然而,这些列表中的每一个都将由相同类型的实体组成,这似乎使框架混淆。我读过这个问题:

Multiple collections of same type in entity framework

并遵循通过为每个项目列表继承不同类型来区分不同列表的建议。但这似乎没有做任何事情。

我得到的错误是:

Exception:Thrown: "Invalid column name 'ApprovalStage_Id1'. Invalid column name 'ApprovalStage_Id2'. Invalid column name 'ApprovalStage_Id3'." (System.Data.SqlClient.SqlException) A System.Data.SqlClient.SqlException was thrown: "Invalid column name 'ApprovalStage_Id1'. Invalid column name 'ApprovalStage_Id2'. Invalid column name 'ApprovalStage_Id3'." Time: 2/9/2015 3:22:05 PM Thread:Worker Thread[11116]

这是我的实体。它有点密集,但基本上主要对象是ComplexApprovalProcess,它在一个列表中有一些ApprovalStages(这一切都很好)。问题在于,每个ApprovalStage都有三个Approver,“审批者”,“观看者”和“顾问”列表。当Entity尝试保存这些实体时,它会抛出上面的错误。就像我说的那样,我尝试通过继承Approver中的其他三个类来区分它们,因此您可以看到它们现在是ReqApproverAdvisorViewer的集合,但它仍然像以前一样抛出上面的错误。任何想法为什么实体会对此感到困惑?每个Approver实体应该只返回它所属的ApprovalStage,但实体似乎认为它应该引用三个不同的ApprovalStages并尝试动态查找那些列,不存在。感谢。

实体:

public class ComplexApprovalProcess
{
    [Key]
    public long Id { get; set; }

    [InverseProperty("ApprovalProcessId")]
    public List<ApprovalStage> Stages { get; set; }

    [ForeignKey("Form")]
    public long FormId { get; set; }

    public int CurrentStage { get; set; }

    public FormBase Form { get; set; }

    bool Approved { get; set; }

    bool Denied { get; set; }

    private bool CheckCompleted() {

        foreach (ApprovalStage stage in this.Stages)
        {
            if (stage.Completed == false)
            {
                //if any stage is incomplete, the process is not complete
                return false;
            }
        }
        //no stages incomplete means all stages complete
        return true;
    }

    private bool AdvanceStage()
    { 
        //check the completion condition of the current stage, if completed, advance to next stage
        ApprovalStage current = Stages.Where(m => m.StageOrder == this.CurrentStage).FirstOrDefault();

        if (current != null)
        {
            //check if stage is completed
            if (current.CheckCompletion())
            {
                //check if stage is approved
                if (current.Approved)
                {
                    //check if process contains additional stages
                    if (this.Stages.Count > this.CurrentStage)
                    { 
                        //Move to next stage
                        this.CurrentStage += 1;
                        ApprovalStage next = Stages.Where(m => m.StageOrder == this.CurrentStage).FirstOrDefault();

                        if (next != null)
                        {
                            next.StartStage();
                        }
                        else
                        {
                            throw new Exception("Huh?");
                        }
                    }
                }
            }
        }
        else
        {
            throw new Exception("Wut");
        }
        return false;
    }

    public static ComplexApprovalProcess CreateCheckRequestApprovalProcess(FormBase form)
    {
        UsersModel user = null;

        ComplexApprovalProcess process = new ComplexApprovalProcess();

        using (TechnologyProjectPlanContext db = new TechnologyProjectPlanContext())
        {
            int id = SessionVar.Get<int>(SessionVar.USERID);

            user = db.UsersModels.Where(m => m.Id == id).FirstOrDefault();
        }

        process.Form = form;

        ApprovalStage InitialReview = new ApprovalStage();
        InitialReview.StageOrder = 1;
        InitialReview.Approvers = new List<ReqApprover>();
        InitialReview.Advisors = new List<Advisor>();
        InitialReview.Viewers = new List<Viewer>();
        InitialReview.Form = form;

        InitialReview.ApprovalProcess = process;
        InitialReview.Approvers.Add(new ReqApprover(user, form, InitialReview));
        InitialReview.Advisors.Add(new Advisor(user, form, InitialReview));
        InitialReview.Viewers.Add(new Viewer(user, form, InitialReview));
        InitialReview.StageName = "Initial Review";

        ApprovalStage MiddleApproval = new ApprovalStage();
        MiddleApproval.StageOrder = 2;
        MiddleApproval.Approvers = new List<ReqApprover>();
        MiddleApproval.Advisors = new List<Advisor>();
        MiddleApproval.Viewers = new List<Viewer>();
        MiddleApproval.Form = form;

        MiddleApproval.ApprovalProcess = process;
        MiddleApproval.Approvers.Add(new ReqApprover(user, form, MiddleApproval));
        MiddleApproval.Advisors.Add(new Advisor(user, form, MiddleApproval));
        MiddleApproval.Viewers.Add(new Viewer(user, form, MiddleApproval));
        MiddleApproval.StageName = "Middle Approval";


        ApprovalStage FinalApproval = new ApprovalStage();
        FinalApproval.StageOrder = 3;
        FinalApproval.Approvers = new List<ReqApprover>();
        FinalApproval.Advisors = new List<Advisor>();
        FinalApproval.Viewers = new List<Viewer>();
        FinalApproval.Form = form;

        FinalApproval.ApprovalProcess = process;
        FinalApproval.Approvers.Add(new ReqApprover(user, form, FinalApproval));
        FinalApproval.Advisors.Add(new Advisor(user, form, FinalApproval));
        FinalApproval.Viewers.Add(new Viewer(user, form, FinalApproval));
        FinalApproval.StageName = "Final Approval";

        process.Stages = new List<ApprovalStage>();
        process.Stages.AddRange(new ApprovalStage[] { InitialReview, MiddleApproval, FinalApproval });

        //set default values
        process.Approved = false;
        process.Denied = false;

        process.CurrentStage = 1;
        process.Stages[0].StartStage();
        return process;
    }

    public void SaveToDb()
    {
        //make sure we have at least one stage and either a form reference (new form) or form id (old form) before moving forward
        if ((Stages != null && Stages.Count > 0) && (Form != null || FormId > 0))
        { 
            using (TechnologyProjectPlanContext  db = new TechnologyProjectPlanContext())
            {
                //first we have to save the process to get an Id
                //copy stages out so we can save without the fuss
                List<ApprovalStage> stages = this.Stages;

                this.Stages = null;

                db.ComplexApprovalProcesses.Add(this);
                db.SaveChanges();

                //'this' now has an Id

                //ok let's work it out from the bottom to the top, first separate out approvers from stages and save:
                foreach (ApprovalStage stage in stages)
                {
                    ICollection<ReqApprover> approvers = stage.Approvers;
                    ICollection<Advisor> advisors = stage.Advisors;
                    ICollection<Viewer> viewers = stage.Viewers;

                    stage.FormId = stage.Form.Id;
                    stage.Form = null;

                    stage.Approvers = null;
                    stage.Advisors = null;
                    stage.Viewers = null;

                    stage.ApprovalProcessId = this.Id;

                    db.ApprovalStages.Add(stage);
                    db.SaveChanges();

                    //stage now has an id;
                    //iterate through each set of approvers and save
                    foreach (Approver approver in approvers)
                    {
                        approver.FormId = stage.FormId;
                        approver.UserId = approver.User.Id;
                        approver.ApprovalStage_Id = stage.Id;

                        approver.Form = null;
                        approver.User = null;
                        approver.Stage = null;

                        db.Approvers.Add(approver);
                        db.SaveChanges();
                    }

                    foreach (Advisor approver in advisors)
                    {
                        approver.FormId = stage.FormId;
                        approver.UserId = approver.User.Id;
                        approver.ApprovalStage_Id = stage.Id;

                        approver.Form = null;
                        approver.User = null;
                        approver.Stage = null;

                        db.Approvers.Add(approver);
                    }

                    foreach (Viewer approver in viewers)
                    {
                        approver.FormId = stage.FormId;
                        approver.UserId = approver.User.Id;
                        approver.ApprovalStage_Id = stage.Id;

                        approver.Form = null;
                        approver.User = null;
                        approver.Stage = null;

                        db.Approvers.Add(approver);
                    }
                    db.SaveChanges();
                }
            }
        }
    }
}

public class ApprovalStage
{
    //Each stage requires at least one approver
    [Key]
    public long Id { get; set; }

    [ForeignKey("ApprovalProcess")]
    public long ApprovalProcessId { get; set; }

    [ForeignKey("Form")]
    public long FormId { get; set; }

    public FormBase Form { get; set; }

    public ComplexApprovalProcess ApprovalProcess { get; set; }

    public ICollection<ReqApprover> Approvers { get; set; } //These users are required to approve before the form can move to the next stage.

    public ICollection<Advisor> Advisors { get; set; } //These users can see the form and approve at this stage, but they are not required.

    public ICollection<Viewer> Viewers { get; set; } //These users can see the form, but cannot approve

    public string StageName { get; set; } //Name of stage e.g. Review, Final Approval, etc.  Gives a custom feel?

    public int StageOrder { get; set; }

    public bool Completed { get; set; }

    public bool Approved { get; set; }

    public bool Denied { get; set; }

    public bool CanAbstain { get; set; }

    public ApprovalStage()
    { 
        this.Approved = false;
        this.Denied = false;
        this.Completed = false;
    }
}

public class Approver
{
    [Key]
    public long Id { get; set; }

    [ForeignKey("User")]
    public int UserId { get; set; }

    public UsersModel User { get; set; }

    [ForeignKey("Form")]
    public long FormId { get; set; }

    public FormBase Form { get; set; }

    [ForeignKey("Stage")]
    public long ApprovalStage_Id { get; set; }

    public ApprovalStage Stage { get; set; }

    public bool Approved { get; set; }

    public bool Denied { get; set; }

    public bool Abstain { get; set; }

    public Approver() { }

    public Approver(UsersModel user, FormBase form, ApprovalStage stage)
    {
        this.Stage = stage;
        this.User = user;
        this.Approved = false;
        this.Denied = false;
        this.Abstain = false;
    }
}

1 个答案:

答案 0 :(得分:0)

好的,所以我想出了我正在犯的错误。我没有想到这样一个事实:一旦放入数据库,同一对象类型的不同列表就不知道它们来自哪个列表。也就是说,Approver,Advisor和Viewer在插入后对框架看起来都是一样的。随着Approvers的继承,我一直遇到错误,所以我简单地制作了3个不同的类和表,并将设计复制到每个类中,并且它完美地运行。简直不敢相信我花了这么多时间......