【问题标题】:Saving a form in POST edit doesn't work在 POST 编辑中保存表单不起作用
【发布时间】:2013-04-17 14:48:36
【问题描述】:

我有一个控制器方法,我试图保存在视图中编辑的表单。

[HttpPost]
public ActionResult ModifyContract(ModContract mod)
{
    // submit modified contract
    if (ModelState.IsValid)
    {
        OutlookMediaEntities1 db = new OutlookMediaEntities1();

        db.ObjectStateManager.ChangeObjectState(mod, EntityState.Modified);

        // save changes
        db.SaveChanges();

        return RedirectToAction("ContractDetails", "Contract", new { id = (int) ViewData["contractid"] });
    }
    else
    {
        ModelState.AddModelError("", "Missing necessary information");
        return View();
    }
}

我在 db.ObjectStateManager... 行收到 InvalidOperationException。我看到一些东西说这可能是因为我没有分配主键并注意到我的 ModAds 类(如下)不包含主键。添加了它,但我得到了同样的错误。我尝试按照我之前问题中回答者的建议执行 db.Attach(mod) ,但出现编译器错误。 Attach 将“IEntityWithKey”作为参数。所以显然我的实体没有密钥,所以我认为我声明模型内容的方式一定有问题。


    public class ModContract
    {
        public int contract_id; // primary key?
        public string contract_name { get; set; }
        public List<ModAds> ads;

        public string print_product_id { get; set; }
        public string print_ad_option_id { get; set; }
    }

    public class ModAds
    {
        public int contr_ad_id; // primary key?
        public string name;
        public string product_name;
        public string adv_product;
        public List<string> editions;
        public double freq_disc;
        public double other_dis_dol;
        public double? other_dis_per;
        public string non_cash_note;
        public double non_cash_cons;
    }

有没有办法指定主键是什么?我的模型有点奇怪,因为如您所见,我在 ModContract 中有一个 ModAd 列表。不确定这是否是个问题。我还尝试在所有字段中添加 getter 和 setter 以查看是否是问题所在,但我遇到了同样的错误。

我也尝试使用db.Entry(model).State = EntityState.Modified; 进行保存,但没有成功,因为我使用的是 EF 4.0。

非常感谢任何帮助!

编辑

我想我知道出了什么问题,模型是由一堆不同的数据库表组成的,即没有表 ModContract。我很确定我必须以某种方式将模型内容分散到适当的表和列中..

编辑 2

OutlookMediaEntities1 的粘贴箱:http://pastebin.com/YyrhjGDA

编辑 3

这是 GET ModifyContract 方法,它显示了我如何查询数据库以创建模型。

    public ActionResult ModifyContract(int id)
    {
        ViewData["contractid"] = id; // save id

        // get data from db
        OutlookMediaEntities1 db = new OutlookMediaEntities1();
        var cont = from printContractAd in db.print_contract_ads
                   from printContracts in db.print_contracts
                   where printContracts.contract_id == id
                   select new { printContracts.contract_id, printContracts.note }; // name

        // select the ads for this contract
        var ads = from printContractAd in db.print_contract_ads
                  from printAdOption in db.print_ad_option
                  from printContract in db.print_contracts
                  from printProduct in db.print_products
                  from contractAdCount in db.Contract_ad_edition_count
                    where printContractAd.print_ad_option_id == printAdOption.print_ad_option_id &&
                          printContract.contract_id == printContractAd.contract_id &&
                          printProduct.print_product_id == printAdOption.print_product_id &&
                          contractAdCount.contract_ad_id == printContractAd.contract_ad_id &&
                          printContract.contract_id == id
                  select new
                  {
                      printContractAd,
                      printAdOption,
                      printProduct,
                      printContract.IsSigned,
                      contractAdCount.CountFreq
                  };

        ModContract con = new ModContract();
        foreach (var c in cont) // only one
        {
            con.contract_id = c.contract_id;
            con.contract_name = c.note;

            break; // only one
        }

        List<ModAds> cads = new List<ModAds>();
        foreach (var ad in ads)
        {
            ModAds mad = new ModAds();
            mad.contr_ad_id = ad.printContractAd.contract_ad_id;
            mad.product_name = ad.printProduct.product_name;
            mad.adv_product = ad.printAdOption.name;
            mad.name = ad.printContractAd.note;
            mad.freq_disc = ad.printContractAd.frequency_discount;
            mad.other_dis_dol = ad.printContractAd.other_discount;
            mad.other_dis_per = ad.printContractAd.other_discount_percent;
            mad.non_cash_note = ad.printContractAd.non_cash_note;
            mad.non_cash_cons = ad.printContractAd.non_cash_discount; // consideration?

            // get editions
            var eds = from contractEditions in db.print_contract_editions
                      where contractEditions.contract_ad_id == ad.printContractAd.contract_ad_id
                      select new
                          {
                              contractEditions
                          };
            mad.editions = new List<string>();
            foreach (var ed in eds)
            {
                mad.editions.Add("Volume " + ed.contractEditions.vol.ToString() + " Issue " + ed.contractEditions.issue.ToString());
            }

            cads.Add(mad);
        }

        con.ads = cads;

        // bind dropdownlist ad options
        var printproductList = from printProduct in db.print_products
                               select printProduct;
        List<SelectListItem> products_list = new List<SelectListItem>();
        List<print_products> products = printproductList.ToList();
        foreach (print_products product in products)
        {
            SelectListItem temp_item = new SelectListItem();
            temp_item.Text = product.product_name;
            temp_item.Value = product.print_product_id.ToString();
            products_list.Add(temp_item);
        }
        ViewData["products_list"] = new SelectList((IEnumerable<SelectListItem>)products_list.ToList(), "Value", "Text");

        // return view with form to modify
        return View(con);
    }

编辑 4

如果有帮助,这也是视图(我无法在此处获得格式):http://pastebin.com/SZvzJ9FB

【问题讨论】:

  • 顺便问一下,您的设置如何?您是在使用代码优先、数据库优先、模型优先吗?
  • 不确定。另一个团队开始了这个项目,我们正在接管。如何检查?
  • 我已经有一段时间没有与 EF 合作了,所以我无法回答这个特定的问题。我对 Code-First 的印象是你有一个 DbContext 并且没有 edmx 文件。但是你可以look here for Model FirstCode FirstDatabase First。阅读这些内容将使您对项目的选择工具有更多的见解和知识。此外,帮助您确定其他团队采取的方法。
  • 你能发布 OutlookMediaEntities1 的代码吗?
  • 呃...不知道从哪里得到。我查询数据库的 GET ModifyContract 方法会有帮助吗?或者也许是一个数据库图? @BehnamEsmaili

标签: c# asp.net-mvc asp.net-mvc-4 entity-framework-4


【解决方案1】:

对于更新实体,实体必须附加到Data Context。这样做可以使用Single 方法从数据上下文中获取实体就足够了。 尝试像这样更改您的代码:

[HttpPost]
public ActionResult ModifyContract(ModContract mod)
{
    // submit modified contract
    if (ModelState.IsValid)
    {
        OutlookMediaEntities1 db = new OutlookMediaEntities1();

        var updatedMod = db.ModContract.Single(m=>m.contract_id == mod.contract_id);
        TryUpdateModel<ModContract>(updatedMod);
        // save changes
        db.SaveChanges();

        return RedirectToAction("ContractDetails", "Contract", new { id = (int) ViewData["contractid"] });
    }
    else
    {
        ModelState.AddModelError("", "Missing necessary information");
        return View();
    }
}

【讨论】:

  • 这段代码的问题是 mod 来自视图并且它已经在其中进行了更改。如果您再次查询它并使用另一个实例,那么您必须将更改从 mod 复制到该新(查询)实例以保持更新。
  • 也没有db.ModContract,检查对原始问题的编辑。
  • TryUpdateModel 照你说的做。它将更改从 mod 复制到新查询的实例。关于 db.ModContract,我预测到了。它是暴露你 @987654327 的属性的名称@Data context 类中的表
【解决方案2】:

你可以告诉 EF contract_id 是关键:

public class ModContract
{
    [Key]
    public int contract_id;
}

并确保属性映射到的数据库列是 PK。尽管它是否是 IDENTITY 可能很重要,这取决于您如何使用它。

【讨论】:

  • 是的,它是主键。顺便说一句,模型类基于一堆数据库表(即没有表 ModContract),并且不包括某些列,等等。我是否有做一些不同的事情来保存这样的模型?大概……
【解决方案3】:

您可以在 ModAds 类中的主键上方添加 [Key] 属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-28
    • 1970-01-01
    • 1970-01-01
    • 2017-12-20
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多