0

I'm really trying hard to put everything on my project to work with the EF, but it's really getting difficult and sometimes it makes me wonder if it's really the smart move (to rely on EF against coding all the ins and outs of the database). Well, my problem is still related to 1-N creating/editing/deleting functionality (something that should be simple, right?).

Ok, I'm pasting here some simple equivalent of my code.

For the Entities, I got the main class as:

[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>();
    }

}

[Notice that i used the nullable int? for Key - otherwise it throws me validation exception asking for a value on creation]

For the child class, i got this:

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

[Notice that the child class has a reference back to the owner class, which are the "IDLote" and "Lote" attributes, and the owner class has a list of child class instances - so I got i bi-directional refernce - I assume that this is somehow related to the problems]

I got a Controller and View generated automatically by VS2012 with Read/Write functionality related to the class Lote. What I did in the View can be described as: I used a Jquery DataTable to manage the child class data (the user can add "N" instances on the DataTable). I substituted the Post Button with a call to a JS method that simply gets all the data from the Form and from the DataTable and wrap it in a JSon object and send it to the controller via Ajax.

The controller method that receives it can be simplified as below:

    [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() });
        }
    }

Problems: Well I really passed through a lot to got to this point and now, I got only 2 problems. The first being that the creation is throwing a Validation Exception sayin that it needs an IDLote (for the child classes - but anyway, how would i have it if the owner class itself still doesn't have an Id at that point in creation?) Second problem: Deletion dont work at all! Doesn't matter how i code it, it throws the exception "objects cannot be defined because they are attached to different ObjectContext objects". I really feel that this has something to do with the bidirectional reference between owner-children classes, but still, don't have a clue on exactly whats happening and how to solve it

I'm starting to feel really lost here. Any ideas on this would be very appreciated. Thanks

Marcelo Myara
  • 2,841
  • 2
  • 27
  • 36

1 Answers1

0

As there are a lot of views on this old question and now I do have some answer, I'm posting them for reference:

Q - Regarding the int? type for the key attributes: A - It doesn't have to be a nullable int at all. The entity can be declared with a simple int attribute as key and when posting the JSon object from the View, back to some controller method, this attribute (the key) can be filled with the value "0". EF will generate the correct value as soon as it persists the object.

Q - Regarding the navigational attributes and how to implement the relation between the two classes when neither of them have already got a value (non-zero) on theis keys: A - The JSon object to be sent back can implement the exact navigational relationaship between them. Wehn the controller binds the data posted to the model it should be receiving, it will "understand" their relationship and as soon as the values for the keys are generated, they will correctly reference one another.

Q - Regarding the error described on the delete method attempts: A - When objects should interact with other objects, and those interactions should be persisted or "understood" by EF in any way, they must have been obtained, generated or attached to a same DBContext. EF rely on the DB context to create a tree of this interactions, thus, rendering impossible to build this tree when objets are not present on the same DB Context.

Marcelo Myara
  • 2,841
  • 2
  • 27
  • 36