下面是我的原始 web 项目的精简版。我有以下数据访问项目的类
public class DbContextFactory : IDbContextFactory
{
private readonly DbContext dbContext;
public DbContextFactory()
{
dbContext = new Db();
}
public DbContext GetContext()
{
return dbContext;
}
}
public interface IDbContextFactory
{
DbContext GetContext();
}
public class Entity
{
public int Id { get; set; }
}
public class Customer : Entity
{
public string CustomerName { get; set; }
public string Telephome { get; set; }
public string Comment { get; set; }
public IList<Site> Sites { get; set; }
}
public class Site : Entity
{
public string SiteNumber { get; set; }
public string Address { get; set; }
public string PostCode { get; set; }
public Customer Customer { get; set; }
[ForeignKey("Customer")]
public int Customer_Id { get; set; }
}
客户将站点实体作为一对多关系。服务类使用 windsor IoC 容器注册。 问题是如果我使用 IoC 解析 DBContext,导航属性也会默认加载。 如果我们加载 Customer,Customer.Sites 有列表值,但预期值为空,因为我没有启用延迟加载或包含在查询中。
我正在使用 IoC 容器生活方式配置作为 PerWebrequest(为了测试,我正在使用单例)。但是如果我们使用Transient配置Customer.sites为null
public class EFDataAcessTest
{
private IWindsorContainer iocContainer;
IDbContextFactory iocCtxFactory;
[SetUp]
public void initializer()
{
iocContainer = new WindsorContainer();
iocContainer.Register(Component.For<IDbContextFactory>().ImplementedBy<DbContextFactory>().LifeStyle.Singleton);
//iocContainer.Register(Component.For<IDbContextFactory>().ImplementedBy<DbContextFactory>().LifeStyle.Transient);
}
[Test]
public void TestCustomerCreation()
{
//Creating customer
var Customer = new Customer() { CustomerName = "Customer 1", Telephome = "78-676-121212", Sites = new List<Site>() };
Customer.Sites.Add(new Site() { Address = "Site 1", PostCode = "001", SiteNumber = "ST01" });
Customer.Sites.Add(new Site() { Address = "Site 2", PostCode = "002", SiteNumber = "ST02" });
iocCtxFactory = iocContainer.Resolve<IDbContextFactory>();
var iocDBContext = iocCtxFactory.GetContext();
//adding customer to database
var sotredCustomer = iocDBContext.Set<Customer>().Add(Customer);
iocDBContext.SaveChanges();
var customerId = sotredCustomer.Id;
//Test
var nonIoCContext = new DbContextFactory().GetContext();
var customerFrom_IOC_Context = iocCtxFactory.GetContext().Set<Customer>().Where(c => c.Id == customerId).SingleOrDefault();
var customerNon_IOC_Context = nonIoCContext.Set<Customer>().Where(c => c.Id == customerId).SingleOrDefault();
Assert.IsNull(customerNon_IOC_Context.Sites);
//Expecting empty but having values if IOC lifestyle is singleton or PerWebRequest :(
//transient is working as expected
Assert.IsNull(customerFrom_IOC_Context.Sites);
}
}
使用的依赖项: CaSTLe.Windsor 版本=“3.3.0” EntityFramework 版本="6.1.3"
请指出如何使 IoC 解析上下文禁用预先加载或有任何解决方法。 Project in github
最佳答案
我认为您的主要问题是实体模型“客户”的结构 具有属性
public IList<Site> Sites { get; set; }
对于延迟加载,我认为你需要使用“Virtual”关键字,我通常使用 ICollection<> 而不是 IList<>
private ICollection<Site> _sites;
public virtual ICollection<Site> Sites
{
get{ return _sites ?? (_sites = new HashSet<Site>()); }
set{ _sites = value; }
}
更新 1:
看到您不想要延迟加载或代理:
当使用 Transient 时,IOC 会在您每次要求解析它时创建一个新的 DB 上下文实例,然后为您提供使用 Get 时预期的结果,因为这是一个没有加载任何数据的新上下文在添加客户期间。
当使用 Singleton 时,相同的数据库上下文实例用于您的添加和获取。因此,当您在测试开始时添加带有站点的新客户记录时,上下文会为您提供相同的设置,并且已经填充了导航属性“站点”。
关于c# - IoC 容器解决了 DbContext(EF) 导致实体中子对象的急切加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34027013/