我发现了很多其他帖子,但他们面临着完全相同的问题。他们使用的代码略有不同。所以我觉得值得回顾一下。
我首先使用EF6代码,然后创建了一个具有一些导航属性的客户端实体。
我会发布相关代码,考虑还有一些属性和外键,但与问题无关。模型正在生成。
public class Client
{
public Client()
{
JobsExperiences = new Collection<JobsExperience>();
CapacitationCourses = new Collection<CapacitationCourse>();
ScholarLevelDetails = new Collection<ScholarLevelDetail>();
Relatives = new Collection<Relative>();
}
public long ClientID { get; set; }
public virtual ICollection<ScholarLevelDetail> ScholarLevelDetails { get; set; }
public virtual ICollection<JobsExperience> JobsExperiences { get; set; }
}
现在我创建了一个ClientServices类,我将所有获取或发送数据的方法放到数据库中。我有这个代码,随机工作,我会尝试清楚地解释。
internal Client GetClient(string userId, bool lazyLoadingEnabled = true)
{
using (var context = new ApplicationDbContext())
{
context.Configuration.LazyLoadingEnabled=lazyLoadingEnabled;
var client = (from _client in context.Client
where _client.ApplicationUserId == userId
select _client).FirstOrDefault();
return client;
}
}
我的目标有些情况是只检索客户端属性,有时还包括所有属性,包括导航属性。
在我的控制器中,我有一条这样的行
var client = uuc.GetClient(user.Id, false);
或者
var client = uuc.GetClient(user.Id);
当我运行第一个句子时,导航属性被初始化但是所有都有Count = 0,即使我的DB有记录关联。我认为,如果禁用延迟加载,则表示启用了加载加载,但似乎没有。但是,导航属性中没有Load()方法来强制加载。
当我运行第二句时,导航属性抛出异常'client.ScholarLevelDetails'抛出了类型'System.ObjectDisposedException'的异常。这句话后面的一行抛出,盯着手表中的导航属性。但是,这是最奇怪的部分,如果我回到句子并调试步进方法,所有导航属性都会正确加载。
为什么一次运行代码的行为与运行单步方法的行为不同? 我假设using语句范围在导航属性加载之前完成,但是为什么禁用lay加载doe snot会检索它们呢? 我如何对此进行编码以保持一致的行为?
答案 0 :(得分:6)
我在Linq中更改了查询代码Ihad。
internal Client GetClient(string userId, bool lazyLoadingEnabled = true)
{
using (var context = new ApplicationDbContext())
{
context.Configuration.LazyLoadingEnabled = lazyLoadingEnabled;
var client = context
.Client
.Include(s => s.ScholarLevelDetails)
.Include(s => s.JobsExperiences)
.Include(s => s.CapacitationCourses)
.Include(s => s.Relatives)
.FirstOrDefault(s => s.ApplicationUserId == userId);
return client;
}
}
现在它有效。但是我仍然有一些问题需要与读者和同事讨论。
为什么简单的Linq不起作用? 为什么无论是否启用延迟加载都无关紧要,这段代码每次都能正常工作吗?
答案 1 :(得分:3)
问题是,在加载导航属性之前,您的上下文超出了范围。
要执行您想要的操作,您需要更改使用上下文的方式,或者只需使用您的查询语法通过表join
急切加载您需要的实体如果使用lambda查询语法,则使用或通过.Include()
lambda表达式。
using (var context = new ApplicationDbContext())
{
context.Configuration.LazyLoadingEnabled=lazyLoadingEnabled;
var client = (from _client in context.Client
where _client.ApplicationUserId == userId
select _client).FirstOrDefault();
return client; //at this point, your context is gone, and no
//navigational properties will be loaded onto your client object,
//even if you try to navigate them. You may even get exceptions if
//attempting to navigate to some properties.
}
这是一个连接示例:
var client = (from _client in context.Client
join t in context.Table on _client.Val equals t.val //this will eager load Table property on client.
where _client.ApplicationUserId == userId
select _client).FirstOrDefault();
答案 2 :(得分:2)
您应该对属性使用Include方法。
_context.Client.Include(c=>c.JobsExperiences) ... and all props like this
但是你最好不要使用延迟加载。 从方法返回后,原因上下文变为非活动状态。
答案 3 :(得分:1)
使用EF 6,我必须使用(lamba&#39; s和Client关键字不可用):
using (var context = new SyntheticData.EF.DBContext())
{
var item = (from t in context.TEMPLATEs
.Include("DATASET")
.Include("COLUMNs")
.Include("SORTs")
.Include("FILTERs")
where t.USERID == identityname && t.ID == id select t).FirstOrDefault();
return item;
}
这填充了关系类,语法如下:
&#34;使用(var context&#34;构造是一种很好的做法,因为它确保你与数据库的连接将被释放回池中。如果你不这样做,你最终可能会用尽繁忙系统的结论。
答案 4 :(得分:0)
以防这有助于某人我没有得到任何导航属性,我的问题似乎是EF没有正确地连接属性,因为我使用接口作为导航属性类型,我需要使用实际类型。除非有人知道如何使用注释或其他东西来告诉EF属性映射到的实际类型。