实体框架和一对多CRUD操作

时间:2012-11-12 13:13:35

标签: asp.net-mvc entity-framework one-to-many objectcontext

我真的很努力地把所有东西放在我的项目上与EF一起工作,但它真的变得困难有时它让我怀疑它是否真的是聪明的举动(依靠EF反对编码所有的进出口数据库)。   好吧,我的问题仍然与1-N创建/编辑/删除功能有关(这应该很简单,对吧?)。

好的,我在这里粘贴了一些简单的代码。

对于实体,我得到了主要的课程:

[Table("OLIM_LOTE")]
public class Lote
{
    [Key]
    [Column("LOTE_ID_LOTE")]
    public int? IDLote { get; set; }

    [Column("LOTE_TX_OBS")]
    public string Obs {get;set;}

    [Column("LOTE_TX_DOCUMENTO_EXTRA")]
    public string DocumentoExtra { get; set; }

    [NotMapped]
    public List<DocumentoLote> Documentos { get; set; }

    public void LoadLists()
    {
        OlimpiqueDBContext myDbContext = new OlimpiqueDBContext();
        var docs = (from doc in myDbContext.DocumentosLote
                     where doc.IDLote == this.IDLote
                     select doc);
        this.Documentos = docs.ToList<DocumentoLote>();
    }

}

[注意我使用了可空的int?对于Key - 否则它会抛出验证异常,要求创建一个值]

对于孩子班,我得到了这个:

[Table("OLIM_DOCUMENTO_LOTE")]
public class DocumentoLote
{
    [Key]
    [Column("DOLO_ID_DOCUMENTO_LOTE")]
    public int? IDDocumentoLote { get; set; }

    [Column("DOCU_ID_DOCUMENTO")]
    [ForeignKey("Documento")]
    public int IDDocumento { get; set; }

    public virtual Documento Documento { get; set; }

    [Column("LOTE_ID_LOTE")]
    [ForeignKey("Lote")]
    public int IDLote { get; set; }

    public virtual Lote Lote { get; set; }
}

[请注意,子类有一个返回所有者类的引用,它是“IDLote”和“Lote”属性,并且所有者类有一个子类实例列表 - 所以我得到了双向引用 - 我认为这与问题有某种关系]

我有一个由VS2012自动生成的Controller和View,具有与Lote类相关的读/写功能。 我在View中所做的可以描述为:我使用Jquery DataTable来管理子类数据(用户可以在DataTable上添加“N”个实例)。我用一个JS方法替换了Post Button,它简单地从Form和DataTable中获取所有数据并将其包装在一个JSon对象中,并通过Ajax将它发送给控制器。

接收它的控制器方法可简化如下:

    [HttpPost]
    public JsonResult Edit(Lote lote)
    {
        try
        {
            if (ModelState.IsValid) //<< HAVING PROBLEMS HERE... DETAILS BELOW
            {
                if (lote.IDLote.HasValue)
                {
                    //Separete updates/inserts from deletes
                    List<int?> dbDocs = db.DocumentosLote
                                    .Where(dt => dt.IDLote == lote.IDLote)
                                    .Select(dt => dt.IDDocumentoLote)
                                    .ToList();

                    List<int?> postedDocs = lote.Documentos
                        .Select(pt => pt.IDDocumentoLote)
                        .ToList();

                    List<int?> deletedDocs = dbDocs
                        .Except(postedDocs).ToList();

                    //Perform deletes
                    foreach (var delDocId in deletedDocs)
                    {
                        if (delDocId.HasValue)
                        {
                            DocumentoLote delDoc = db.DocumentosLote
                                .Where(dt => dt.IDLote == lote.IDLote && dt.IDDocumentoLote == delDocId)
                                .Single();

                            db.Entry(delDoc).State = EntityState.Deleted;
                        }
                    }

                    //Perform insert and updates
                    foreach (var doc in lote.Documentos)
                    {
                        if (doc.IDDocumentoLote.HasValue)
                        {
                            db.Entry(doc).State = EntityState.Modified;
                        }
                        else
                        {
                            db.Entry(doc).State = EntityState.Added;
                            doc.IDLote = (int)lote.IDLote;
                        }
                    }
                }
                else
                {
                    db.Lotes.Add(lote);
                }
                db.SaveChanges();

                // If Sucess== 1 then Save/Update Successfull else there it has Exception
                return Json(new { Success = 1, ex = "" });
            }
            else
            {
                return Json(new { Success = 0, ex = "Falha ao tentar salvar os dados" });
            }
        }
        catch (Exception ex)
        {
            // If Sucess== 0 then Unable to perform Save/Update Operation and send Exception to View as JSON
            return Json(new { Success = 0, ex = ex.Message.ToString() });
        }
    }

问题:我真的经历了很多事情,到现在为止,我只遇到了2个问题。第一个是创建抛出一个Validation Exception,说它需要一个IDLote(对于子类 - 但无论如何,如果所有者类本身在创建时仍然没有Id,我将如何拥有它?) 第二个问题:删除根本不起作用!无论我如何对其进行编码,它都会引发异常“无法定义对象,因为它们附加到不同的ObjectContext对象”。我真的觉得这与所有者 - 孩子班级之间的双向参考有关,但是,仍然没有确切知道发生了什么以及如何解决它

我开始感到真的迷失在这里。任何有关这方面的想法都将非常感激。谢谢

1 个答案:

答案 0 :(得分:0)

由于对这个老问题有很多看法,现在我有一些答案,我将其张贴以供参考:

问:关于关键属性的int?类型: A - 它根本不必是可以为空的int。可以使用简单的int属性作为键声明实体,并且当从View发布JSon对象时,返回到某个控制器方法,可以使用值“0”填充此属性(键)。 EF会在持久保存对象后立即生成正确的值。

问:关于导航属性以及当两个类都没有在theis键上获得值(非零)时如何实现两个类之间的关系: A - 要发回的JSon对象可以实现它们之间的精确导航关系。当控制器将发布的数据绑定到它应该接收的模型时,它将“理解”它们之间的关系,并且一旦生成了键的值,它们就会正确地相互引用。

问:关于删除方法尝试中描述的错误: A - 当对象应与其他对象交互时,这些交互应由EF以任何方式保持或“理解”,它们必须已获取,生成或附加到同一个DBContext。 EF依赖于DB上下文来创建此交互的树,因此,当在同一个DB上下文中不存在objets时,无法构建此树。