简体   繁体   English

添加到包含列表的类的dbset时,实体框架代码首先出现NullReferenceException

[英]Entity Framework Code First NullReferenceException when adding to a dbset of class that contains a list

Firstly, I'm relatively new to Entity Framework stuff and WebAPI but, I'm currently writing a Web API for fun that involves a person being able to create a master "business" account that's able to create 'Businesses' and create and attach child accounts to them. 首先,我对Entity Framework和WebAPI相对较新,但是,我目前正在编写一个有趣的Web API,其中涉及一个人能够创建一个主“业务”帐户,该帐户可以创建“业务”并创建并附加孩子向他们交代。 There are separate tables that keep track of the businesses created under business accounts and a list of Workers that are attached to those businesses. 有单独的表可跟踪在业务帐户下创建的业务以及与这些业务关联的工作人员列表。

Given the following classes/code: 给定以下类/代码:

Business Class: 商务课程:

public class Business
{
    public int Id { get; set; }

    public string BusinessAccount { get; set; }
    public string BusinessName { get; set; }                

    public List<Worker> Workers { get; set; }
}

SchedulerDbContext: SchedulerDbContext:

public class SchedulerDbContext : DbContext
{
    public SchedulerDbContext()
        : base("SchedulerDbContext")
    {

    }

    public virtual DbSet<Business> Businesses { get; set; }
    public virtual DbSet<Worker> Workers { get; set; }

}

BusinessController: (only relevant section shown) BusinessController :(仅显示相关部分)

[Route("Create")]        
public IHttpActionResult Create(string name)
{
    if (String.IsNullOrWhiteSpace(name))
    {
        ModelState.AddModelError("BusinessNameError", "Invalid Business Name Entered.");
        return BadRequest(ModelState);
    }

    Business business = new Business()
    {
        BusinessName = name,
        BusinessAccount = User.Identity.Name,
        Workers = new List<Worker>() //<----a
    };

    using (var db = new SchedulerDbContext())
    {
        db.Businesses.Add(business); //<----b
        db.SaveChanges();
    }

    return Ok(business);
}

UserController: (only relevant section) UserController :(仅相关部分)

[Route("Register")]
public async Task<IHttpActionResult> Register(UserModel userModel)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    AccountUser user = new AccountUser
    {
        UserName = userModel.UserName,
        Email = userModel.Email,
        BusinessAccount = User.Identity.Name
    };

    IdentityResult result = await this.SchedUserManager.RegisterUser(user, userModel);
    IHttpActionResult errorResult = GetErrorResult(result);
    if (errorResult != null)
    {
        return errorResult;
    }

    result = await this.SchedUserManager.AddToRoleAsync(user.Id, defaultRole);
    errorResult = GetErrorResult(result);
    if (errorResult != null)
    {
        return errorResult;
    }


    using (var db = new SchedulerDbContext())
    {
        var query = from record in db.Businesses
                    where record.Id == userModel.BusinessId
                    select record;
        var business = query.First();

        var worker = new Worker()
        {
            FirstName = userModel.FirstName,
            LastName = userModel.LastName,
            Email = userModel.Email
        };

        if (business.Workers == null) { business.Workers = new List<Worker>(); } //<----c

        business.Workers.Add(worker); //<----d
        db.SaveChanges();
    }

    return Ok();
}

Now with the code out of the way. 现在,将代码排除在外了。 There were multiple spots that I marked with arrows. 我用箭头标记了多个斑点。 Now the questions I have are... 现在我的问题是...

When creating a Busines in the Create() function of the BusinessController, I assigned the Workers property a new List as seen at //<----a. 在BusinessController的Create()函数中创建商务时,我为Workers属性分配了一个新列表,如// <---- a所示。 So after that, it is added to the SchedulerDbContext at //<----b and changes saved. 因此,在此之后,将其添加到// <---- b处的SchedulerDbContext并保存更改。

Now, when creating a user account to attach to that business in the UserController's Register() function I ran into an issue. 现在,当在UserController的Register()函数中创建要附加到该业务的用户帐户时,我遇到了一个问题。 If running the line at arrow //<----d is done without the line at //<----c existing, I get a NullReferenceException. 如果运行箭头/////////////////////////////////////// c //////////// c ////////// c ////////////////////上的行,则得到了NullReferenceException。

What I'm curious about is why the line at //<----a didn't fix this? 我很好奇的是为什么// <---- a处的行没有解决这个问题? I'm pretty sure there isn't technically a record to assign to, but is checking to see if it's null (like at //<----c) the cleanest way to handle it? 我很确定在技术上没有记录要分配,但是正在检查它是否为空(例如// <---- c)是否是最干净的处理方式? Part of me imagined EF to magically handle this for me. 我的一部分想到了EF可以为我神奇地解决这个问题。 Is there a better way? 有没有更好的办法? It just seems to me an odd spot to assign a new List if it's empty, like it should be done somewhere else. 在我看来,分配一个新列表(如果它是空的)似乎很奇怪,就像应该在其他地方执行的一样。

Because EF does not load all foreign rows by default. 因为默认情况下,EF不会加载所有外部行。 You either need to explicitly tell it to load the workers, or enable lazy loading for that property. 您要么需要明确地告诉它加载工作程序,要么对该属性启用延迟加载。

Explicitly loading: 显式加载:

var query = from record in db.Businesses
                where record.Id == userModel.BusinessId
                select record;
var business = query.Include("Workers").First();
//                   ^^^^^^^^^^^^^^^^^^

Allow lazy loading to kick in for that relationship: 允许延迟加载启动该关系:

public virtual List<Worker> Workers { get; set; }
//     ^^^^^^^

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM