views:

307

answers:

3

Hi There

I am building a very simple asp.net MVC file upload form. Currently I have a problem creating the new database object that stores info on said file.

The code for the action method looks as follows:

[Authorize(Roles = "Admin")]
    public ActionResult AddFile(Guid? id)
    {
        var org = organisationRepository.GetOrganisationByID(id.Value);
        Quote newFile = new Quote();
        newFile.Organisation = org;
        newFile.QuotedBy = User.Identity.Name;
        return View("AddFile", newFile);
    }

The problem is that the value of newFile.Organisation is lost when the form is posted back. I suppose EF does not provide a value for OrganisationID at this stage.

[Authorize(Roles = "Admin")]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult AddFile(Quote quote)
    {
        //save the file to the FS - nice!
        if (ModelState.IsValid)
        {
            try
            {
                foreach (string inputTagName in Request.Files)
                {
                    HttpPostedFileBase file = Request.Files[inputTagName];
                    if (file.ContentLength > 0)
                    {
                        string filePath = Path.Combine(HttpContext.Server.MapPath("~/Content/TempOrgFiles/")
                        , Path.GetFileName(file.FileName));
                        file.SaveAs(filePath);
                        quote.QuoteURL = file.FileName;
                    }
                }
                surveyRepository.AddQuote(quote);
                surveyRepository.Save();
            }
            catch (Exception ex)
            {
                //add model state errors
                ViewData["error"] = ex.Message;
            }
        }

        return View("AddFile");
    }

If this were linq to sql I would simplt set the OrganisationID, but with it being EF that is not possible (at least with my setup)

Any ideas as the best way to handle these situations? (save for doin something crazy like setting a hidden form field to the organisaionid and setting it in the post method)

+1  A: 

You can store OrganisationID in session

[Authorize(Roles = "Admin")]
public ActionResult AddFile(Guid? id)
{
Session["OrganisationID"] = id;
}

and then set EntityKey with something like:

quote.OrganisationReference.EntityKey = new EntityKey("ContainerName.OrganizationSet","ID",Session["OrganisationID"])

If You have organisation ID in URL, You can change post function to:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddFile(Quote quote,Guid? id)

and retrieve it automatically (with adequate routing).

You don't neet to get organisation from repository during get, just store ID.

LukLed
grabbing the organisation id in the post seems to work - but has led to a nice new error - An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Sergio
Is this code everything that You do in post? It happens when You try to connect objects from different contexts.
LukLed
Yep - the related repository methods are as follows: public void AddQuote(Quote q) { db.AddToQuotes(q); } public void Save() { db.SaveChanges(); }I suppose that perhaps when I assign quote.Organisation to org, quote is being attached and tracked through that object context? Then, when I try to add to to the db through another context, things getting confused and an exception is thrown....
Sergio
How do You set organisation during post? Setting organisation during get is not important, because during post it is not restored. Quote object is built of post data.
LukLed
during get I leave it as null.I have found that I can alter my AddQuote repository method to accept a quote and an organisation id. I can then get the organisation entity in the repository and set it there. not sure if that is good practise - doesnt feel like it. Thanks for your help btw!
Sergio
Repository should be used only to perform basic CRUD operation. You can build additional layer on top of repository to perform business logic. One of the methods of this layer (in my application I call it service layer) can take Quote objects and organisation id and perform additional operations.
LukLed
A: 

The data is lost because it is stateless. Your quote object in the GET is not the same quote object as passed in the POST. It's only partially hydrated due to the native binding in MVC (by property names). You'll either need to setup a CustomModelBinder or requery for your Quote object in the controller.

RailRhoad