【问题标题】:Cant' get EF6 to load related entities无法让 EF6 加载相关实体
【发布时间】:2016-05-17 10:49:35
【问题描述】:

我正在使用 VS2012 在 C# 中创建一个 Web 应用程序来跟踪对客户的联系尝试。我正在保存联系尝试,其中包含 2 个用于联系尝试类型的参考表和联系尝试结果,因为这些始终是固定值。我遇到的问题是,当我从数据库中检索 App_ContactAttempt 时,它将带回 App_ContactAttempt 实体而没有附加的 Ref_ContactOutcome 和 Ref_ContactType 实体。我在上下文文件中启用了延迟加载和代理创建,并且所有参考表属性都设置为虚拟。但是当我从数据库中获得 App_ContactAttempt 时,没有附加参考表。有人知道我能做什么吗?如果您需要更多信息,我可以提供。

更新 对,我有一个服务设置来获取 App_ContactAttempt,如下所示:

    public App_ContactAttempt GetContactAttempt(int contactAttemptId)
    {
        using (var logger = new MethodLogger(contactAttemptId))
        {
            var contactAttempt = new App_ContactAttempt();
            try
            {
                contactAttempt = _unitOfWork.ContactAttempts.Get(contactAttemptId);
            }
            catch (Exception e)
            {
                logger.LogException(e.InnerException);
            }
            return contactAttempt;
        }
    }

当我使用该服务时,我调用该服务时返回 App_ContactAttempt,但 Ref_ContactType 和 Ref_ContactOutcome 为空。但是当我使用 db 上下文从控制器内部调用 db 时,如下所示:

    var db = new ParsDatabaseContext();

    var contactAttemptTest1 = _clientService.GetContactAttempt(contactAttempt.ContactAttemptId);

    var contactAttemptTest2 = db.App_ContactAttempt.Where(x => x.ContactAttemptId == contactAttempt.ContactAttemptId);

contactAttemptTest1 返回 App_ContactAttempt,其中 Ref_ContactType 和 Ref_ContactOutcome 都为空。但是,contactAttemptTest2 返回 App_ContactAttempt,同时填充了 Ref_ContactType 和 Ref_ContactOutcome。希望这有助于缩小我的问题,因为我不知道..

更新 2 以下是上下文和类,如果它们有帮助的话:

Context.cs

public partial class ParsDatabaseContext : DbContext
{
    public ParsDatabaseContext()
        : base("name=ParsDatabaseContext")
    {
        this.Configuration.LazyLoadingEnabled = true;
        this.Configuration.ProxyCreationEnabled = true;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public DbSet<App_Client> App_Client { get; set; }
    public DbSet<App_ContactAttempt> App_ContactAttempt { get; set; }
    public DbSet<Ref_ContactOutcome> Ref_ContactOutcome { get; set; }
    public DbSet<Ref_ContactType> Ref_ContactType { get; set; }

    public virtual ObjectResult<GetClient_Result> GetClient(Nullable<int> clientID)
    {
        var clientIDParameter = clientID.HasValue ?
            new ObjectParameter("ClientID", clientID) :
            new ObjectParameter("ClientID", typeof(int));

        return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<GetClient_Result>("GetClient", clientIDParameter);
    }
}

App_ContactAttempt.cs

public partial class App_ContactAttempt
{
    public int ContactAttemptId { get; set; }
    public int ClientId { get; set; }
    public Nullable<System.DateTime> ContactDate { get; set; }
    public Nullable<int> ContactType { get; set; }
    public Nullable<int> ContactOutcome { get; set; }
    public string Notes { get; set; }

    public virtual Ref_ContactOutcome Ref_ContactOutcome { get; set; }
    public virtual Ref_ContactType Ref_ContactType { get; set; }
}

Ref_ContactOutcome.cs

public partial class Ref_ContactOutcome
{
    public Ref_ContactOutcome()
    {
        this.App_ContactAttempt = new HashSet<App_ContactAttempt>();
    }

    public int ContactOutcomeId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<App_ContactAttempt> App_ContactAttempt { get; set; }
}

Ref_ContactType.cs

public partial class Ref_ContactType
{
    public Ref_ContactType()
    {
        this.App_ContactAttempt = new HashSet<App_ContactAttempt>();
    }

    public int ContactTypeId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<App_ContactAttempt> App_ContactAttempt { get; set; }
}

【问题讨论】:

  • there are not ref tables attached - 你是什么意思?在调试时你看到属性Ref_ContactOutcome 是空还是什么?
  • 您要么必须在存储库模式中使用Include 扩展,要么启用延迟加载。
  • 要使延迟加载工作,在您访问导航属性时,上下文您从中加载实体的位置 必须可用(并且未释放)。如果您想使用非常短暂的上下文,请使用急切加载(例如,Include
  • 我如何知道上下文被释放的位置?我调用了相同的服务以在控制器的 index 方法中获取 ContactAttempt,它带回了附加的关联 Refs,但是当我在该控制器上的另一个方法中调用相同的服务时,它们没有附加。上下文将在哪里处理,我该如何阻止它?
  • @necrofish666 请不要破坏您的帖子。

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


【解决方案1】:

问题在于延迟加载仅在用于创建代理类的 DBContext 可用时才有效。在您的情况下,代理已分离,因为用于创建 App_ContactAttempt 类型的代理对象 contactAttempt 的 DBContext 已被处置。

还要确保:

dbContext.Configuration.ProxyCreationEnabled = true;

你可以检查对象是否是代理

public static bool IsProxy(object type)
{
    return type != null && ObjectContext.GetObjectType(type.GetType()) != type.GetType();
}

https://msdn.microsoft.com/en-us/library/ee835846%28v=vs.100%29.aspx

请参阅this answer 以检查您的代理实体是否附加到 DBContext。

您可以将现有的分离实体附加到另一个现有上下文并使其再次延迟加载:

db.App_ContactAttempts.Attach(contactAttemptTest1);

如果您知道某个实体已存在于数据库中,但 当前没有被上下文跟踪,那么你可以告诉 使用 DbSet 上的 Attach 方法跟踪实体的上下文。这 实体将在上下文中处于未更改状态。

here

所以在你的例子中:

using (var db = new ParsDatabaseContext())
{
   var contactAttemptTest1 = _clientService.GetContactAttempt(contactAttempt.ContactAttemptId);     
   db.App_ContactAttempts.Attach(contactAttemptTest1);    
   Debug.Print(contactAttemptTest1.Ref_ContactType.Description);
}

应该可以。

【讨论】:

    【解决方案2】:

    使用包括。

    例如:

    var contactAttemps = db.App_ContactAttempts
                           .Includes("Ref_ContactOutcome")
                           .Includes("Ref_ContactTypes")
                           .ToList();
    

    【讨论】:

    • 我正在使用存储库模式从数据库中获取实体。我有一个服务设置,我将 ContactAttemptId 传递给该设置,这会将我带回该记录,但 Ref_ContactOutcome 和 Ref_ContactTypes 均为空。
    【解决方案3】:

    您是返回实体本身还是 DTO(数据传输对象)?

    如果您要返回 DTO,请确保正确完成映射。

    发布您的实体对象。

    【讨论】:

      猜你喜欢
      • 2017-12-20
      • 1970-01-01
      • 1970-01-01
      • 2019-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-23
      • 1970-01-01
      相关资源
      最近更新 更多