Leron
Leron

Reputation: 9876

How to save records in two tables with1 to 1 relation in EF 5

So I am working on this ASP.NET MVC 4 project and I get to this point where I think I can't get my head around the problem. I am using Entity Framework 5 and Code first workflow. I have those two entities:

public class Document
{
    public int DocumentID { get; set; }
    public string Name { get; set; }
    public string Description
    public int UserFileID { get; set; }
    public UserFile UserFile { get; set; }
}

and respectively

public class UserFile
{
    public int UserFileID { get; set; }
    public string FileName { get; set; }
}

Now I have an admin part where I allow the admin to create new Document and most of the time the user will want to add some kind of file to the document but I want to manage the user uploaded files separately so I have an explicit entity where I plan to store all the uploaded files.

Something that seem very standard but I really can't figure out is this:

I have a form:

@using (Html.BeginForm("Documents", "Admin",
                    FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.TextBoxFor(m => m.Name)
    @Html.TextBoxFor(m => m.Description)
    <input name="file" type="file" />
    <input type="submit" value="Upload File" id="btnSubmit" />
}

Then in my Controller Action I would like to copy the file and create the records in Document and UserFile tables but I just don't see how I'm supposed to do it. I use repositories and UnitOfWork so in my controller I could first:

UserFile item = new UserFile();
//take the name of the uploaded file and set it for item.Name
unitOfWork.UserFileRepository.Add(item);

But then I have to save the Document where I can begin again with :

Document entity = new Document();
entity.Name = model.Name;
entity.Description = model.Description;
entity.UserFile = ???
unitOfWork.DocumentRepository.Add(entity);

What I really don't know is how to deal with the foreign key. I have a little experience but as far as I remember in other scenarion I just need to pass object of type UserFile like:

var entityUserFile =  unitOfWork.UserFileRepository.GetById(Id);

and then:

entity.UserFile = entityUserFile;

But I don't see a way to get the ID of the newly created record in UserFile table. I can think of workaround by setting unique name for each file, but I was wondering is there some way to deal with this. Maybe some Code First approach where I could create the two entity instances and let the Entity Framework deal with setting the relation, maybe some other way? Or I am obligate to save the UserFile entity then to get it back and pass it as value for my Document entity?

Upvotes: 0

Views: 80

Answers (1)

Colin
Colin

Reputation: 22595

Have you tried this?

UserFile item = new UserFile();
Document entity = new Document();
entity.Name = model.Name;
entity.Description = model.Description;
entity.UserFile = item;
unitOfWork.DocumentRepository.Add(entity);
unitOfWork.SaveChanges();

The DbSet.Add() method marks all objects in the graph as "Added", so the UserFile should be Added at the same time as Document.

Reference:

Why does Entity Framework Reinsert Existing Objects into My Database?

Alternatively, EF should fix up your ID when you SaveChanges(). So this should work too :

UserFile item = new UserFile();
unitOfWork.UserFileRepository.Add(item);
unitOfWork.SaveChanges();//Database generates key 
                         //and EF fixes its in-memory version

Document entity = new Document();
entity.Name = model.Name;
entity.Description = model.Description;
entity.UserFileID = item.ID; //use the foreign key to avoid duplicate
unitOfWork.DocumentRepository.Add(entity);
unitOfWork.SaveChanges();

You may wish to enclose this in TransactionScope because there are now 2 calls to SaveChanges()

Upvotes: 1

Related Questions