【问题标题】:Way to load navigation properties after saving object to database将对象保存到数据库后加载导航属性的方法
【发布时间】:2014-06-24 16:11:04
【问题描述】:

将对象保存到数据库后,有什么方法可以“绑定”相关属性?例如: 从 html 表单我发布票对象。它已填充所有属性,并且外键正确。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Ticket ticket)
{
    if (ModelState.IsValid)
    {
        db.Tickets.Add(ticket);
        db.SaveChanges();

        //here i want to use ticket.ResponsibleEmployee property

        return RedirectToAction("Index");
    }

    return View(ticket);
}


public class Ticket
{
    public int TicketID { get; set; }
    public string Title { get; set; }

    [ForeignKey("ResponsibleEmployee")]
    public int ResponsibleEmployeeID { get; set; }

    public virtual Employee ResponsibleEmployee { get; set; }
}

public class Employee
{
    public int EmployeeID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }

    public virtual IList<Ticket> Tickets { get; set; }
    public Employee()
    {
        this.Tickets = new List<Ticket>();
    }
}

有没有简单的方法来获取这些相关的属性? 通过db.Tickets.Find(ticket.TicketID) 保存后,我尝试再次获取属性,但返回的票证没有分配导航属性。我也试过db.Entry(ticket).CurrentValues.SetValues(ticket),但也没用。

【问题讨论】:

  • 如果您单步执行您的代码,该票证对象在您将其持久化到上下文之前是否有一个责任雇员?
  • 尝试将 [Key] 属性添加到 Ticket.TicketID 和 Employee.EmployeeID 以便 EF 知道您的主键是什么。默认情况下,它会查找 TicketId 和 EmployeeId,但我怀疑这是区分大小写的,它不会自动创建它们。

标签: c# asp.net-mvc entity-framework


【解决方案1】:

将对象保存到数据库后,有什么方法可以“绑定”相关属性?

取决于很多假设

首先,通过查看以下代码:

if (ModelState.IsValid)
{
  db.Tickets.Add(ticket);
  db.SaveChanges();

无法判断ticket.ResponsibleEmployeeID 是否已填充。如果它未填充或与数据库中相关ResponsibleEmployee.(id/key) 的值不匹配,您将永远无法使用导航属性。

其次,导航属性只能在多种情况下物化

导航属性的请求必须存在于上下文中:

Ticket ticket;
string employeeName;
using (var db = new MyContext())
{
  // assume 1 exists
  ticket = db.Tickets.Where(t => t.id = 1).First();

  // this is possible (see below why it may not be)
  employeeName = person.ResponsibleEmployee.Name;
}

// this is never possible, the context does not exist
employeeName = person.ResponsibleEmployee.Name;

接下来,上下文必须有MyContext.Configuration.LazyLoadingEnabled = true

最后,据我所知,MyContext.Configuration.ProxyCreationEnabledneeds to be true。如果不正确,则该对象与 Entity Framework 断开连接,并且延迟加载不知道该对象(以及您尝试执行的任何操作,例如加载相关实体)。

如果您不使用代理对象或不使用延迟加载(我都不使用),那么您必须explicitly load the related entities

using (var context = new BloggingContext()) 
{ 
  var post = context.Posts.Find(2); 

  // Load the blog related to a given post 
  context.Entry(post).Reference(p => p.Blog).Load(); 

  // Load the blog related to a given post using a string  
  context.Entry(post).Reference("Blog").Load(); 

  var blog = context.Blogs.Find(1); 

  // Load the posts related to a given blog 
  context.Entry(blog).Collection(p => p.Posts).Load(); 

  // Load the posts related to a given blog  
  // using a string to specify the relationship 
  context.Entry(blog).Collection("Posts").Load(); 
}

【讨论】:

  • “无法判断ticket.ResponsibleEmployeeID 是否已填充。” - 是的,它已填充并匹配相关属性。它是从下拉列表中选择的。对不起,我没有提到这一点,我补充了我的问题。另外,据我所知,LazyLoading 默认启用,所以我正在使用它。
【解决方案2】:

我在这里看不到任何有关 ResponsibleEmployeeID 的信息。但我认为它是对象的一部分。然后你可以试试这样的:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Ticket ticket)
{
    if (ModelState.IsValid)
    {
        ticket.ResponsibleEmployee = db.Employees.Find(ResponsibleEmployeeID);
        db.Tickets.Add(ticket);
        db.SaveChanges();

        return RedirectToAction("Index");
    }

    return View(ticket);
}

【讨论】:

  • 它工作正常,但如果我有 5、10 或 15 个相关属性怎么办?有没有办法“加载”所有真实的属性? PS。 ResponsibleEmployeeID 设置正确并且是有效的外键。
  • 那么我的理解是你必须在保存更改之前连接它们中的每一个。所以如果你有很多,你通常会在保存之前创建一个私有方法来处理这个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多