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

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

public abstract class BaseEntity { ///  /// Key Field for all entities ///  /// [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; } ///  /// Date entity was created ///  public DateTime DateCreated { get; set; } ///  /// Last date Modified ///  public DateTime DateModified { get; set; } ///  /// keep track of Row Version used for concurrency ///  1541567432 public Byte[] RowVersion { get; set; } } public abstract class Document : BaseEntity { #region Primitive Properties ///  /// Boolean value to determine if Document is in an active state ///  public bool IsActive { get; set; } ///  /// Document comments and information ///  [Required] public string Description { get; set; } #endregion #region Navigation Properties public ICollection Comments { get; set; } ///  /// FK back to User who owns document ///  //public Guid OwnerId { get; set; } public Guid OwnerId { get; set; } ///  /// Navigation Back to User who owns document ///  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 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 GetQuery(Expression<Func> predicate) { return _context.Set().AsQueryable(); } 

我最终做了什么,在我的服务层我称之为:

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

您必须使您的导航属性virtual以使延迟加载工作。

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

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

为了避免这个问题,我编写了一个测试,validation每个引用属性是否标记为虚拟。 这样我立即发现,而不是在路上处理奇怪的错误。


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

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

结果我为proeprty创建的映射是在数据库中创建一个重复的ID。 例如,我在数据库中有ProjectIdProject_ID 。 当一个新项目保存到上下文时,我正在填充ProjectId ,但没有填充_ID 。 这就是EF 4.1用于关联数据的内容。 在我的映射中,我想要设置项目,以便它不会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的选项进行逆向工程代码。 辉煌!