【问题标题】:Exception while retrieving data using Entity framework (Code first)使用实体框架检索数据时出现异常(代码优先)
【发布时间】:2015-07-30 16:27:06
【问题描述】:

我不确定协议是什么 w.r.t。改变你的问题,但我想如果我改变它会更好,因为有很多信息并且提出问题的初衷已经丢失。

原问题:

我最初在使用 EF(代码优先方法/POCO 类)生成数据库时遇到问题。 问题之一是我在实体类中使用构造函数来初始化成员。在@RickStahl 建议不需要之后,我改变了我的实现。

为了读者,我不希望信息丢失,因为一些老的 cmets 打算解决这个问题。

但是,自从最初创建此线程以来,情况发生了变化。我已经能够克服一些问题。

当前问题:

我在从基础数据库表中检索内容时遇到问题。

例外: 对象引用未设置为对象的实例。

异常发生在 Program.cs 的以下语句(第 21 行):

foreach(PhoneNumber p in cd.Phones)

为了便于理解问题,我粘贴了整个源代码。

这是我的 Entity 类的源代码。

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();

    }

【问题讨论】:

  • 好吧,正如消息所说,您在 ContactData 上没有无参数构造函数,您在创建集合时调用它。如果您想简化设置,您可能需要查看 automapper。
  • @SteveGreene 当您为实体对象提供参数化构造函数时,使用 O/RM 是否过于复杂?
  • 要使 EF 工作,您的实体需要有一个无参数构造函数。无论如何,当您可以使用更加灵活的参数分配语法时,所有这些参数都是多余的。
  • 你可以做到,但你想达到什么目的?您上面的代码不需要它们。我喜欢我的 POCO 最小化,然后我在控制器中构建一个视图模型并使用 AutoMapper 来回传输数据。有点学习曲线,但效果很好。 lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models
  • 试试 IQueryable cContactList = cDB.Contacts.Include(c => c.Phones).Include(c => c.Emails);

标签: asp.net-mvc-4 c#-4.0 ef-code-first entity-framework-6 poco


【解决方案1】:

我终于找到了解决我自己问题的方法。但我想向@SteveGreene 和@RickStahl 表达我的“感谢”,感谢他们提供的宝贵意见。

@RickStahl 给出了一个很好的建议或建议,即不要在我的实体类中使用参数化构造函数。根据 Rick,参数化构造函数不适用于 EF。

@SteveGreene - 我终于意识到你给我指明了正确的方向。由于我对EF缺乏了解,我当时无法得到它。然而,在详细阅读了 EF 之后,特别是关于 Eager loading 和 Lazy loading 的内容最终帮助了我。

在我发现必须在 ContactData 类构造函数中实例化“电话”和“电子邮件”的集合属性后,与“对象引用未设置为对象实例”相关的错误很容易解决。

请参考下面的代码更改。

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() 方法中使用以下语句来完成的。据我所知,我使用了急切加载方法。对于延迟加载,您必须为 子类 使用虚拟成员,例如在这种情况下的电话和电子邮件。

 var phones = cDbContext.Contacts.Include("Phones").ToList();

 var emails = cDbContext.Contacts.Include("Emails").ToList();

这是 ContactManager 类的完整代码。

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 表达式。但是我得到了一个编译时异常'包含方法需要一个字符串'。我尝试将以下 lambda 表达式与 include 方法一起使用。 var phone = cDbContext.Contacts.Include(b => b.Phones).ToList(); // 这导致编译时错误“包含方法需要一个字符串”。

在将参数名称作为字符串传递(如下所示)后,使用 ContactData 类的 'Phones' 和 'Emails' 集合成员的名称,它工作正常。

var emails = cDbContext.Contacts.Include("Emails").ToList();

如有任何疑问,请发表评论。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 2021-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多