仅填充相关对象的ID时不加载导航属性

本文关键字:加载 导航 属性 ID 填充 对象 | 更新日期: 2023-09-27 17:57:50

我正在尝试建立多对一关系。表示"多"的实体具有指向父实体的导航属性。它看起来像这样:

public abstract class BaseEntity
{
    /// <summary>
    /// Key Field for all entities
    /// </summary>
    /// 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    /// <summary>
    /// Date entity was created
    /// </summary>
    public DateTime DateCreated { get; set; }
    /// <summary>
    /// Last date Modified
    /// </summary>
    public DateTime DateModified { get; set; }
    /// <summary>
    /// keep track of Row Version used for concurrency
    /// </summary>
    [Timestamp]
    public Byte[] RowVersion { get; set; }
}
public abstract class Document : BaseEntity
{
    #region Primitive Properties   

    /// <summary>
    /// Boolean value to determine if Document is in an active state
    /// </summary>
    public bool IsActive { get; set; }
    /// <summary>
    /// Document comments and information
    /// </summary>
    [Required]
    public string Description { get; set; }
    #endregion
    #region Navigation Properties
    public ICollection<Comment> Comments { get; set; }
    /// <summary>
    /// FK back to User who owns document
    /// </summary>
    //public Guid OwnerId { get; set; }
    public Guid OwnerId { get; set; }
    /// <summary>
    /// Navigation Back to User who owns document
    /// </summary>
    public User Owner { get; set; }
    #endregion
}
public class Project : BaseEntity
{
    public string Name { get; set; }
    public string ProjectNumber { get; set; }
    public string Description { get; set; }
    public string CreatedBy { get; set; }
    public string ModifiedBy { get; set; }
    public string Currency { get; set; }
    #region Navigation Properties
    public virtual Address Address { get; set; }
    public virtual CompanyCode CompanyCode { get; set; }
    public virtual ICollection<Contact> TeamMembers { get; set; }
    #endregion
}    
 public class Rfi : Document
 {
    public string Number { get; set; }
    #region Navigation Properties
    //This points back to a Project Entity
    public virtual Guid ProjectId { get; set; }
    public virtual Project Project { get; set; }
    #endregion
}

因此,当我插入上述实体时,我将ProjectId从应用程序传递到Rfi实体(而不是整个Project实体)。一切都很好。我遇到的问题是,当我从数据库中取出Rfi对象时,ProjectId正在填充,但Project实体为null。默认情况下,我使用的是Lazy Loading。我是否也需要在Project实体上指定导航属性?我真的不想。除非,我可以在我的Rfi上执行映射来实现这一点。

更新:我以为EF 4.1会为我加载我的对象,但似乎有时我需要明确地包括我想要加载的对象。我不完全确定为什么。我正在使用存储库来查询我的实体。以下是我用来查询Rfi对象的方法:

    public IQueryable<TEntity> GetQuery(Expression<Func<TEntity, bool>> predicate)
    {
       return _context.Set<TEntity>().AsQueryable();
    }

我最终做了什么,在我的服务层,我这样称呼它:

public Rfi FindByNumber(string number)
{
     var rfi = rfiRepository.GetQuery(r => r.Number == number).Include(r => r.Project).Single;
     return rfi
}

仅填充相关对象的ID时不加载导航属性

您必须将导航属性设置为virtual才能使Lazy Loading工作。

虽然这在实现方面是有意义的,但EF忽略问题并只返回null的策略是一个糟糕的设计决策。

另一方面,NHibernate默认情况下不允许您使用那些不具有所有虚拟属性的类。

为了避免这个问题,我编写了一个测试,验证每个引用属性都标记为虚拟。这样我就立刻发现了,而不是在路上处理奇怪的虫子。


您也可以尝试显式指定FK/Navigation属性:

public Guid ProjectId { get; set; }
[ForeignKey("ProjectId")]
public virtual Project Project { get; set; }

我为项目创建的映射在数据库中创建了一个重复的ID。例如,我在数据库中有ProjectIdProject_ID。当一个新项目被保存到上下文时,我正在填充ProjectId,但_ID没有被填充。这就是EF 4.1用来关联数据的内容。在我的映射中,我试图设置Project,这样它就不会CascadeOnDelete。这就是我的地图:

HasOptional(rfi => rfi.Project)
    .WithOptionalDependent()
    .WillCascadeOnDelete(false);

此映射在数据库中创建了2个ID。一旦我删除了映射,一切都正常了。我只需要找出正确的映射,这样我就可以删除CascadeOnDelete,使属性可选,并且只有一个ID。

我在EF Power Tools的帮助下找到了答案。您可以将您的数据库反向工程为POCO。我把上面的行改成:

HasOptional(r => r.Project)
    .WithMany()
    .HasForeignKey(r => r.ProjectId)
    .WillCascadeOnDelete(false);

即使使用流畅的接口,映射也有点难以掌握。为了理解EF中的关系是如何映射的,我用我的表和外键分配创建了一个简单的数据库。然后,我首先使用Power Tools的选项进行反向工程代码。明亮的