我正在努力建立多对一的关系。表示“many”的实体具有指向父实体的导航属性。它看起来像这样:
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
}
答案 0 :(得分:13)
您必须使Lazy Loading的导航属性virtual
生效。
虽然这在实施方面是有道理的,但EF忽略问题而只是返回null
的策略是一个糟糕的设计决策。
为了避免这个问题,我写了一个测试,验证每个引用属性是否标记为虚拟。这样我立刻就会发现,而不是在路上处理奇怪的错误。
您还可以尝试明确指定FK / Navigation属性:
public Guid ProjectId { get; set; }
[ForeignKey("ProjectId")]
public virtual Project Project { get; set; }
答案 1 :(得分:3)
原来我为proeprty创建的映射是在数据库中创建一个重复的ID。例如,我在数据库中有ProjectId
和Project_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的选项进行逆向工程代码。辉煌!