使用 Entity framework 检索数据时出现异常(代码优先)
Exception while retrieving data using Entity framework (Code first)
我不确定协议是什么 w.r.t。改变你的问题,但我想如果我改变它会更好,因为有很多信息并且提出问题的初衷已经丢失。
原问题:
我最初在使用 EF(代码优先方法/POCO classes)生成数据库时遇到问题。
其中一个问题是我在实体 classes 中使用构造函数来初始化成员。在@RickStahl 建议不需要之后,我更改了我的实现。
为了读者着想,我不希望这些信息丢失,因为一些旧评论旨在解决该问题。
但是,自从最初创建此线程以来,情况发生了变化。我已经能够克服一些问题。
当前问题:
我在从基础数据库表中检索内容时遇到问题。
异常:
对象引用未设置为对象的实例。
异常发生在Program.cs(第21行)的以下语句:
foreach(PhoneNumber p in cd.Phones)
为了方便理解问题,我把整个源码都贴出来了。
这是我的实体的源代码 class。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ConsoleApplication1
{
public class ContactData
{
[Key]
public int ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<PhoneNumber> Phones { get; set; }
public IList<EmailAddress> Emails { get; set; }
}
public class PhoneNumber
{
[Key]
public int PhoneId { get; set; }
public int ContactId { get; set; }
public string Phone { get; set; }
public ContactData ContactData { get; set; }
public PhoneNumber()
{
}
}
public class EmailAddress
{
[Key]
public int EmailId { get; set; }
public int ContactId { get; set; }
public string Email { get; set; }
public ContactData ContactData { get; set; }
public EmailAddress()
{
}
}
}
ContactContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
namespace ConsoleApplication1
{
public class ContactContext : DbContext
{
public ContactContext()
: base("ContactDBContext")
{
Database.SetInitializer<ContactContext>(new DropCreateDatabaseIfModelChanges<ContactContext>());
}
public DbSet<ContactData> Contacts { get; set; }
}
}
ContactManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class ContactManager
{
ContactContext cDbContext = new ContactContext();
public IList<ContactData> GetContactList()
{
IQueryable<ContactData> cContactList = cDbContext.Contacts;
IList<ContactData> cListData = new List<ContactData>();
cListData = cContactList.ToList();
return cListData;
}
}
}
Program.cs(入口点)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
ContactManager cMgr = new ContactManager();
foreach (ContactData cd in cMgr.GetContactList())
{
Console.WriteLine(cd.ContactId);
Console.WriteLine(cd.FirstName);
Console.WriteLine(cd.LastName);
foreach(PhoneNumber p in cd.Phones)
{
Console.WriteLine(p.Phone);
}
foreach (EmailAddress e in cd.Emails)
{
Console.WriteLine(e.Email);
}
}
Console.ReadKey();
}
我终于找到了解决我自己问题的方法。但我想将我的 'Thanks' 扩展到 @SteveGreene 和 @RickStahl,以获得他们的宝贵意见。
@RickStahl 给出了一个很好的输入或建议,建议不要在我的实体 classes 中使用参数化构造函数。 Per Rick,参数化构造函数不适用于 EF。
@SteveGreene - 我终于意识到你为我指明了正确的方向。由于我对 EF 缺乏了解,当时无法获得它。然而,在详细阅读了 EF,特别是关于 Eager loading 和 Lazy loading 的内容后,终于帮助了我。
与 'Object reference not set to an instance of an object' 相关的错误很容易解决,因为我发现我必须在 ContactData class 中实例化 'Phones' 和 'Emails' 的集合属性构造函数。
请参考下面的代码更改。
public class ContactData
{
[Key]
public int ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string BusinessName { get; set; }
public IList<PhoneNumber> Phones { get; set; }
public IList<EmailAddress> Emails { get; set; }
public ContactData()
{
//By instantiating Phones and Emails member collections below, resolved 'Object reference not set to an instance of an object' exception
Phones = new List<PhoneNumber>();
Emails = new List<EmailAddress>();
}
}
下一步是将数据填充到相关实体中,因为到目前为止我只能填充父实体联系人。
为此,我必须从我的研究中发现并了解将数据加载到相关实体的不同方法,例如急切加载、延迟加载等。
这是通过在 ContactManager.GetContactList() 方法中使用以下语句来完成的。据我所知,我使用了预加载方法。对于延迟加载,您必须为 child classes 使用虚拟成员,例如本例中的 Phone 和 Email .
var phones = cDbContext.Contacts.Include("Phones").ToList();
var emails = cDbContext.Contacts.Include("Emails").ToList();
这里是ContactManager的完整代码class。
class ContactManager
{
ContactContext cDbContext = new ContactContext();
public IList<ContactData> GetContactList()
{
ContactData cd = new ContactData();
IQueryable<ContactData> cContactList = cDbContext.Contacts;
IList<ContactData> cListData = new List<ContactData>();
var phones = cDbContext.Contacts.Include("Phones").ToList();
var emails = cDbContext.Contacts.Include("Emails").ToList();
cListData = cContactList.ToList();
return cListData;
}
}
了解了这一点后,我明白@SteveGreene 给我指明了正确的方向。毕竟我 运行 遇到的唯一问题是我使用了带有 Include 方法的 lambda 表达式。但是我得到了一个编译时异常'Include method expects a string'。我尝试将以下 lambda 表达式与 include 方法结合使用。
var phones = cDbContext.Contacts.Include(b => b.Phones).ToList(); // 这导致编译时错误 'Include method expects a string'.
在将参数名称作为字符串传递(如下所示)后,名称为 'Phones' 和 ContactData class 集合成员的 'Emails',它工作正常。
var emails = cDbContext.Contacts.Include("Emails").ToList();
如有任何疑问,请post发表评论。
我不确定协议是什么 w.r.t。改变你的问题,但我想如果我改变它会更好,因为有很多信息并且提出问题的初衷已经丢失。
原问题:
我最初在使用 EF(代码优先方法/POCO classes)生成数据库时遇到问题。 其中一个问题是我在实体 classes 中使用构造函数来初始化成员。在@RickStahl 建议不需要之后,我更改了我的实现。
为了读者着想,我不希望这些信息丢失,因为一些旧评论旨在解决该问题。
但是,自从最初创建此线程以来,情况发生了变化。我已经能够克服一些问题。
当前问题:
我在从基础数据库表中检索内容时遇到问题。
异常: 对象引用未设置为对象的实例。
异常发生在Program.cs(第21行)的以下语句:
foreach(PhoneNumber p in cd.Phones)
为了方便理解问题,我把整个源码都贴出来了。
这是我的实体的源代码 class。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ConsoleApplication1
{
public class ContactData
{
[Key]
public int ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<PhoneNumber> Phones { get; set; }
public IList<EmailAddress> Emails { get; set; }
}
public class PhoneNumber
{
[Key]
public int PhoneId { get; set; }
public int ContactId { get; set; }
public string Phone { get; set; }
public ContactData ContactData { get; set; }
public PhoneNumber()
{
}
}
public class EmailAddress
{
[Key]
public int EmailId { get; set; }
public int ContactId { get; set; }
public string Email { get; set; }
public ContactData ContactData { get; set; }
public EmailAddress()
{
}
}
}
ContactContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
namespace ConsoleApplication1
{
public class ContactContext : DbContext
{
public ContactContext()
: base("ContactDBContext")
{
Database.SetInitializer<ContactContext>(new DropCreateDatabaseIfModelChanges<ContactContext>());
}
public DbSet<ContactData> Contacts { get; set; }
}
}
ContactManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class ContactManager
{
ContactContext cDbContext = new ContactContext();
public IList<ContactData> GetContactList()
{
IQueryable<ContactData> cContactList = cDbContext.Contacts;
IList<ContactData> cListData = new List<ContactData>();
cListData = cContactList.ToList();
return cListData;
}
}
}
Program.cs(入口点)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
ContactManager cMgr = new ContactManager();
foreach (ContactData cd in cMgr.GetContactList())
{
Console.WriteLine(cd.ContactId);
Console.WriteLine(cd.FirstName);
Console.WriteLine(cd.LastName);
foreach(PhoneNumber p in cd.Phones)
{
Console.WriteLine(p.Phone);
}
foreach (EmailAddress e in cd.Emails)
{
Console.WriteLine(e.Email);
}
}
Console.ReadKey();
}
我终于找到了解决我自己问题的方法。但我想将我的 'Thanks' 扩展到 @SteveGreene 和 @RickStahl,以获得他们的宝贵意见。
@RickStahl 给出了一个很好的输入或建议,建议不要在我的实体 classes 中使用参数化构造函数。 Per Rick,参数化构造函数不适用于 EF。
@SteveGreene - 我终于意识到你为我指明了正确的方向。由于我对 EF 缺乏了解,当时无法获得它。然而,在详细阅读了 EF,特别是关于 Eager loading 和 Lazy loading 的内容后,终于帮助了我。
与 'Object reference not set to an instance of an object' 相关的错误很容易解决,因为我发现我必须在 ContactData class 中实例化 'Phones' 和 'Emails' 的集合属性构造函数。
请参考下面的代码更改。
public class ContactData
{
[Key]
public int ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string BusinessName { get; set; }
public IList<PhoneNumber> Phones { get; set; }
public IList<EmailAddress> Emails { get; set; }
public ContactData()
{
//By instantiating Phones and Emails member collections below, resolved 'Object reference not set to an instance of an object' exception
Phones = new List<PhoneNumber>();
Emails = new List<EmailAddress>();
}
}
下一步是将数据填充到相关实体中,因为到目前为止我只能填充父实体联系人。
为此,我必须从我的研究中发现并了解将数据加载到相关实体的不同方法,例如急切加载、延迟加载等。
这是通过在 ContactManager.GetContactList() 方法中使用以下语句来完成的。据我所知,我使用了预加载方法。对于延迟加载,您必须为 child classes 使用虚拟成员,例如本例中的 Phone 和 Email .
var phones = cDbContext.Contacts.Include("Phones").ToList();
var emails = cDbContext.Contacts.Include("Emails").ToList();
这里是ContactManager的完整代码class。
class ContactManager
{
ContactContext cDbContext = new ContactContext();
public IList<ContactData> GetContactList()
{
ContactData cd = new ContactData();
IQueryable<ContactData> cContactList = cDbContext.Contacts;
IList<ContactData> cListData = new List<ContactData>();
var phones = cDbContext.Contacts.Include("Phones").ToList();
var emails = cDbContext.Contacts.Include("Emails").ToList();
cListData = cContactList.ToList();
return cListData;
}
}
了解了这一点后,我明白@SteveGreene 给我指明了正确的方向。毕竟我 运行 遇到的唯一问题是我使用了带有 Include 方法的 lambda 表达式。但是我得到了一个编译时异常'Include method expects a string'。我尝试将以下 lambda 表达式与 include 方法结合使用。 var phones = cDbContext.Contacts.Include(b => b.Phones).ToList(); // 这导致编译时错误 'Include method expects a string'.
在将参数名称作为字符串传递(如下所示)后,名称为 'Phones' 和 ContactData class 集合成员的 'Emails',它工作正常。
var emails = cDbContext.Contacts.Include("Emails").ToList();
如有任何疑问,请post发表评论。