mysql - 属性为 null 导致 NullReferenceException 但 Entity Framework 数据库中的主键和外键是正确的并且彼此完全匹配

标签 mysql .net asp.net-mvc entity-framework razor

注意:因为数据库中的 ID 看起来很完美,所以当我尝试引用模型属性的属性时,可能只是我的 razor View 中的错误(在帖子的末尾)。我不擅长 LINQ。


我在 class Person 中有一个 Models.Person.cs,它引用了 Surveys:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace WebApplication2.Models {
    public class Person {
        public int Id { get; set; }
        // MANY PROPERTIES BEETWEEN
        [DisplayName("Surveys")]
        public virtual ICollection<Survey> Surveys { get; set; }

    }
}

我得到了 class Survey,它由 Question 组成,每个 Question 都有一个 Answer. These classes are in Models.Survey.cs`,看起来像:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplication2.Models {
    public class Question {
        public int Id { set; get; }
        public string QuestionText { set; get; }
        public  ICollection<Answer> Answers { set; get; }
        public string SelectedAnswer { set; get; }
        public virtual Survey Survey { get; set; }
    }
    public class Answer {
        public int Id { set; get; }
        public string AnswerText { set; get; }
        public virtual Question Question { get; set; }
    }
    public class Survey {
        public int Id { set; get; }
        public ICollection<Question> Questions { set; get; }

        public virtual Person Person { get; set; }

    }
}

Entity Framework 数据库上下文类如下所示:

 public class ApplicationDbContext : IdentityDbContext<ApplicationUser> {


        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false) {
            System.Diagnostics.Debug.WriteLine("CONSTRUCTOR");

        }

        public DbSet<Person> Persons { get; set; }
        public DbSet<Meeting> Meetings { get; set; }
        public DbSet<Status> Statuses { get; set; }
        public DbSet<Survey> Surveys { get; set; }
        public DbSet<Question> Questions { get; set; }
        public DbSet<Answer> Answers { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder) {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }

        public static ApplicationDbContext Create() {

            return new ApplicationDbContext();

        }
    }

我为数据库播种:

  protected override void Seed(WebApplication2.Models.ApplicationDbContext context) {
            System.Diagnostics.Debug.WriteLine("SEED STARTED");
            var survey = new Survey() { Questions = new List<Question>() };
            if (!context.Surveys.Any()) {


                //the below is hardcoded for DEMO. you may get the data from some  
                //other place and set the questions and answers

                var q1 = new Question() { QuestionText = "What is your favourite language", Answers = new List<Answer>() };
                Answer a1 = new Answer() { AnswerText = "PHP" };
                Answer a2 = new Answer() { AnswerText = "ASP.NET" };
                Answer a3 = new Answer() { AnswerText = "Java" };
                context.Answers.AddOrUpdate(a1);
                context.Answers.AddOrUpdate(a2);
                context.Answers.AddOrUpdate(a3);
                context.Questions.AddOrUpdate(q1);

                q1.Answers.Add(a1);
                q1.Answers.Add(a2);
                q1.Answers.Add(a3);
                survey.Questions.Add(q1);

                var q2 = new Question() { QuestionText = "What is your favourite DB", Answers = new List<Answer>() };
                a1 = new Answer() { AnswerText = "SQL Server" };
                a2 = new Answer() { AnswerText = "MySQL" };
                a3 = new Answer() { AnswerText = "Oracle" };
                q2.Answers.Add(a1);
                q2.Answers.Add(a2);
                q2.Answers.Add(a3);

                context.Answers.AddOrUpdate(a1);
                context.Answers.AddOrUpdate(a2);
                context.Answers.AddOrUpdate(a3);
                context.Questions.AddOrUpdate(q2);

                survey.Questions.Add(q2);

                context.Surveys.AddOrUpdate(survey);
                context.SaveChanges();

            }
            if (!context.Persons.Any()) {
                var persons = new List<Person> { 
                         new Person{FirstName = "John", LastName = "Doe", CellNumber = "123-456-789", SecondaryPhoneNumber = "98873213", Address = "1street 2",BirthDate = DateTime.Now.Date, Pesel = "312312312", Notes = "Annoying", Surveys = new List<Survey>(){survey}},
                         new Person{FirstName = "Anna", LastName = "Doe", CellNumber = "113-456-789", SecondaryPhoneNumber = "98873213", Address = "1street 2",BirthDate = DateTime.Now.Date, Pesel = "548555672", Notes = "Less Annoying", Surveys = new List<Survey>()}
                        };


                persons.ForEach(person => context.Persons.AddOrUpdate(person));
                context.SaveChanges();
            }
}

生成的数据库看起来很不错。我们可以看到 Survey(Id=4) 与 John Doe(Id=6) 相关联,而 Questions(Id=7,8) 与 Survey(Id=4) 等相关联。所以它看起来很棒。

enter image description here

但是 如果我尝试显示(在 Razor View 中)John Doe(Id = 6) 的调查数量,我得到 1,这是正确的,然后是该调查中的问题数量(由 @Html.DisplayFor(x => survey.Questions.Count ) 我得到 A first chance exception of type 'System.NullReferenceException' occurred in System.Web.Mvc.dll 但没有显示任何内容。

观点:

@model WebApplication2.Models.Person
<hr />
<h2>@Html.DisplayNameFor(model => model.Surveys)</h2>

<input type="button" id="Coll" value="Collapse" onclick="javascript:CollapseDiv()" />
<p>
    @Html.DisplayFor(x => Model.Surveys.Count)
</p>
@foreach (var survey in Model.Surveys) {
    <p>
        @using (Html.BeginForm()) {

            <text>ANK</text>
            @Html.DisplayFor(x => survey.Questions.Count)   //HERE I GET NULL POINTER EXCEPTION
            <input type="submit" />
        }
    </p>
}

<hr />

结果:

enter image description here

编辑:

 protected override void OnModelCreating(DbModelBuilder modelBuilder) {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Person>().HasMany(p => p.Answers).WithMany(a => a.Persons);   
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }`

最佳答案

尝试在 Questions 集合中添加虚拟关键字。只要上下文仍然存在,这将启用延迟加载。您可能还需要将其添加到 Answers 集合中。

public virtual ICollection<Question> Questions { set; get; }

或者您可以使用预先加载。

var model = db.Persons.
    Include(p => p.Questions).FirstOrDefault(p => p.Id == xx);

附言

加载导航属性的方法有几种。

  • 延迟加载

    必填

    • virtual 导航属性上的关键字
    • 启用延迟加载,db.Configuration.LazyLoadingEnabled = true;
    • 启用代理,db.Configuration.ProxyCreationEnabled = true;
    • DbContext 未释放,如果释放,将抛出对象释放异常
    • -

    只有在访问该属性时才会加载相关导航。例如:

    // Questions is not loaded yet.
    var person = db.Persons.FirstOrDefault();
    // Questions will be loaded.
    var questions = person.Questions;
    // Questions will be loaded even though you only ask for the count.
    var qCount = person.Questions.Count;
    
  • 预加载

    必需

    • 包含方法
    • -

    这将在生成的查询中使用连接语句加载导航属性作为主查询的一部分。

    // Questions will be loaded together with the main query.
    var person = db.Persons.Include(p => p.Questions).FirstOrDefault();
    
  • 显式加载

    必需

    • db.Entry(entity).Reference(/* reference */).Load();方法
    • db.Entry(entity).Collection(/* collection */).Load(); 方法
    • DbContext
    • -

    这将显式加载每个导航属性。

    // Loads the main entity first.
    var person = db.Persons.FirstOrDefault();
    // Explicitly load the Questions.
    db.Entry(person).Collection(p => p.Questions).Load();
    

    此外,如果需要,您可以过滤问题

    db.Entry(person)
       .Collection(p => p.Questions)
       .Query() 
       .Where(q => q.QuestionText.Contains("Entity Framework"))
       .Load();
    
  • 关系修正

    必需

    • Select 匿名类型中每个导航属性的子句
    • -

    这将自动链接主实体和导航属性,也可用于过滤导航属性。生成的查询将生成连接语句。

    var person = db.Persons.Select(p => new
    {
        Person = p,
        Questions = p.Questions
            .Where(q => q.QuestionText.Contains("Entity Framework"))
    }).AsEnumerable().Select(t => t.Person).FirstOrDefault();
    

    上面的查询在第一个 Select 子句中将 PersonQuestions 选择为匿名类型,然后将其转换为可枚举类型(延迟执行)和然后第二个 Select 子句只选择 Person 属性,但结果会将 Questions 属性链接到每个 Person .最后通过 FirstOrDefault 方法执行查询。

如果没有上述任何方法,导航属性将不会自动加载。

更多:

关于mysql - 属性为 null 导致 NullReferenceException 但 Entity Framework 数据库中的主键和外键是正确的并且彼此完全匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25467443/

相关文章:

php - Delete from inner join mysql查询-两表多条件

.net - Base64 编码数据最大大小

.net - LinqToSql 和 HashBytes

asp.net-mvc - ASP.NET MVC HttpPostedFIleBase 为空

mysql - 将 2 个表合并为 1 个

mysql - 请问如何通过sql查找季度stemp差异?

c# - WebClient() 可以同时下载多个字符串吗?

jquery - 复选框不适用于 datatable.js 分页的第二页

regex - 如何限制多行文本框只接受一个数字?

MYSQL查询同一个字段两个不同的id