2013-02-06 109 views
1

将项目从EntityObject生成器切换到DbContext后,我遇到了一个问题,在新对象上使用了一些导航属性。我花了大量的时间来研究这个问题,并且我没有接近一个理想的解决方案。EF 4.4中的DbContext和导航属性

首先,生成的类定义:

public partial class Category 
{ 
    public Category() 
    { 
     this.Limits = new HashSet<Limit>(); 
    } 

    public int CategoryId {get; set;} 
    public string Name {get; set;} 
    public virtual ICollection<Limit> Limits { internal get; set; } 
} 

public partial class Limit 
{ 
    public int CategoryId {get; set;} 
    public string Description {get; set;} 
    internal virtual Category Category { get; set; } 
} 

我使用下面的代码集成测试期间创建的测试数据:

using (GFCAMDataContext db = new GFCAMDataContext()) 
{ 
    limit = new Limit() 
    { 
     CategoryId = testData.CategoryId, 
     Description = "SignerController.Update" 
    }; 

    db.Limits.Add(limit); 
    db.SaveChanges(); 
} 

没有任何其他的变化,在Limit.Category财产我新创建的Limit对象不返回任何东西。但是,如果在调用SaveChanges之前从DbContext查询所需的类别,则新限制的导航属性开始返回关联的类别。使用ObjectContext,Category属性在没有任何干预的情况下进行更新。

我想与ObjectContext具有相同的行为,但我似乎无法找到实现此目标的方法。我见过几种建议的解决方案:

  • 使导航属性公开。这具有相同的行为,并且不可取,因为公共导航属性可能会在序列化期间导致问题,并且在我的业务层之外不需要。

  • 使所有属性公开为虚拟并使用DbSet.Create确保代理创建。这导致了相同的行为,并不一定需要,因为我有代码动态创建实例(即我在创建实体实例时没有访问DbSet)。

有没有人有任何解决这个问题的建议?

+0

这似乎是懒惰加载不踢英寸什么是Limit类的CategoryId?它是主键还是外键还是两者?如何为此类配置主键 - EF将无法使用约定来发现此类的键,并且您应该会收到一个异常,表明实体类型没有键属性。 – Pawel

+0

只是要说得很清楚:你说SaveChanges()调用Category属性后没有填充? –

回答

0

一个解决办法是显式地加载嵌套实体:

db.SaveChanges(); 
db.Entry(person).Reference(z => z.Category).Load(); 

另一种选择,当代理启用,的确叫DbSet.Create<T>()。如果您在创建实体时无法访问DbSet实例,则可能希望在存储库接口中公开一个允许实现的方法。例如:

public interface IRepository<T> 
{ 
    T Add(T entity); 

    T GetById(...); 

    void SaveChanges(); 

    ... 

    T CreateInstance(); // Concrete implementation have access to DbSet and uses DbSet.Create<T>() 
}