插入到具有外键关系的两个表中

Insert Into two Tables with Foreign Key relationship

在我的 MVC 应用程序中,我有两个名为 TicketAttachment 的实体,当插入新的工单记录时,我还想插入新的附件记录 先前插入的票证 ID 的 FK。

我查看了一些示例作为 this 页面,但我需要在一个方法中为多个附件使用一个循环,以便用户在创建新工单时可以附加多个文件。你能给Entity Framework的示例存储过程或示例方法来解决这个问题吗?

这是这两个实体:

门票:

public class Ticket
{
    [Key] 
    public int ID { get; set; }

    public string Comment { get; set; }

    //Navigation Property
    public virtual ICollection<Attachment> Attachments { get; set; }

}


附件:

public class Attachment
{
    [Key]
    public int ID { get; set; }

    //Foreign key for Ticket
    public int TicketID { get; set; }   

    public byte[] FileData { get; set; }

    public string FileMimeType { get; set; }

    //Navigation Property 
    public virtual Ticket Ticket { get; set; }
}

看看 Entity Framework 中的 AssociationAttribute。它将允许您将对象设置为 属性 以设置外键。如果您添加如下内容:

public class Attachment {
    ...
    [Association(Name = "ticket", ThisKey = "TicketId", OtherKey = "Id", IsForeignKey = true)]
    public Ticket Ticket { get; set;}
    [Column(DBType = "INT NOT NULL" ...]
    public int TicketId { get; set; }
    ...
}

到您的 class,那么您应该能够像这样将票证对象分配给附件对象的 "Ticket" 属性:

public UploadTicket(string ticketComment, List<Attachment> attachments) {
    (using db = new DataContext()) {
        var ticket = new ticket();
        ticket.Comment = ticketComment;
        db.Tickets.InsertOnSubmit(ticket);
        foreach (var att in attachments) {
            var attachment = new attachment();
            attachment.Ticket = ticket; // <- this will assign the TicketId property automatically upon insert
            attachment.FileData = att.FileData;
            attachment.FileMimeType = att.FileMimeType;
            db.Attachments.InsertOnSubmit(attachment);
        }
        db.SubmitChanges();
    }
}

尝试这样的事情(当然这是简化的 - 但它显示了应该使用的基本机制 - 实例化对象并通过它们的导航属性连接它们,并且只为整个对象图保存一次):

// establish the DbContext
using (TicketModel ctx = new TicketModel())
{
    // create a ticket
    Ticket t1 = new Ticket
    {
        Comment = "This is ticket #1"
    };

    // add two attachments to it
    Attachment a1 = new Attachment { FileMimeType = "text/json" };
    t1.Attachment.Add(a1);

    Attachment a2 = new Attachment { FileMimeType = "application/octet-stream" };
    t1.Attachment.Add(a2);

    // add the ticket to the context
    ctx.Ticket.Add(t1);

    // save everything
    ctx.SaveChanges();
}

有了这个,您的数据库中应该有一张票,以及两个连接的附件(它们的 TicketID 列设置为票的正确值)

通过改进 marc_s 建议的机制,我解决了问题。对于那些需要这种解决方案的人,我发布了最终代码:

控制器中的方法:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _Create([Bind(Exclude = null)] IssueViewModel ticketViewModel, IEnumerable<HttpPostedFileBase> files)
{
    try
    {
        if (ModelState.IsValid)
        {
            ticketViewModel.FileAttachments = new List<FileAttachment>();
            foreach (var upload in files)
            {
                if (upload != null && upload.ContentLength > 0)
                {
                    if (upload.ContentType == "application/pdf" 
|| upload.ContentType == "application/vnd.openxmlformats-officedocument.word" 
|| upload.ContentType == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
                    {
                        FileAttachment fileAttachment = new FileAttachment
                        {
                            Created = DateTime.Now,
                            FileMimeType = upload.ContentType,
                            FileData = new byte[upload.ContentLength]
                        };
                        upload.InputStream.Read(fileAttachment.FileData, 0, upload.ContentLength);
                         ticketViewModel.FileAttachments.Add(fileAttachment);
                    }
                    else
                    {
                        return PartialView("_Create");
                    }
                }
            }
            repository.SaveTicket(ticketViewModel.Issue, ticketViewModel.FileAttachments);
            return RedirectToAction("Completed");
        }
    }
    catch (RetryLimitExceededException /* dex */)
    {
        //Log the error (uncomment dex variable name and add a line here to write a log.)
        ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
    }      
    return View(ticketViewModel);
}


数据层中的方法:

public void SaveTicket(Ticket ticket, IEnumerable<FileAttachment> fileAttachment)
{
    context.Tickets.Add(ticket);
    foreach (FileAttachment f in fileAttachment)
    {
        context.FileAttachments.Add(f);
    }
    context.SaveChanges();
}