LINQ to SQL -> 访问已释放的对象。对象名称:“在Dispose后访问的DataContext”。

3

假设我有两个表,一个是学生表,一个是学校表。在我的学生表中,我有一个外键fkSchoolId链接到一个学校记录。然而,如果我按照以下方式检索我的记录:

public static List<Student> GetByType(string connString, int type)
{
    using (mydb_DataContext db = new mydb_dbDataContext(connString))
    {
        return (from t1 in db.Students
                where t1.type = type
                select t1).ToList();
    }
}

我将拥有学生对象列表,并且可以在foreach循环中访问它。但是当我按照下面的方法操作时,当检索学校名称时会出现错误。

foreach(Student student in DAL.StudentLogic.GetByType(5))
{
    string schoolName = student.School.Name;
}

System.ObjectDisposedException:“无法访问已处理的对象。对象名称:“DataContext accessed after Dispose.”。

请问我该如何获取存储在返回对象中的外部信息,以便我可以访问它们?或者更好的方法是,如果我可以指定仅加载学校名称呢?

更新: 如果我按照以下方式进行操作,它可以正常工作,但不确定它会对性能产生多大影响。我将进行基准测试,并在下周再次更新此主题。

public static List<Student> GetByType(string connString, int type)
{
    using (mydb_DataContext db = new mydb_dbDataContext(connString))
    {
        List<Student> students = (from t1 in db.Students where t1.type = type select t1).ToList();

        foreach(Student student in students)
        {
            student.School.Name = db.Schools.Where(q => q.SchoolId == student.fkSchoolId).FirstOrDefault().Name;
        }
    }
}

我将能够在我的返回对象中访问student.School.Name。

这个解决方案将为每个返回的学生执行单独的查询。这样多次访问数据库有些浪费。 - Gilad Green
@GiladGreen 我同意..不是最佳性能..我想知道为什么LINQ to SQL没有一个简单的方法来指定我想要带回哪个..我尝试使用了DeferredLoadingEnabled,但我仍然得到null外键对象。我不想使用C#7.如果我使用Entity Framework,那里有一个.Include,它会与EF一起解决我的问题吗? - TPG
但是在LINQ to SQL中,include不可用,对吗? - TPG
2个回答

5

DeferredLoadingEnabled属性设置为false

获取或设置一个值,指示是否延迟加载一对多或一对一关系。

因此,在实例化查询时检索相关数据,而不是在后续阶段检索(在上下文被释放之后)。

public static List<Student> GetByType(string connString, int type)
{
    using (mydb_DataContext db = new mydb_dbDataContext(connString))
    {
        db.DeferredLoadingEnabled = false;
        return (from t1 in db.Students
                where t1.type = type
                select t1).ToList();
    }
}

然而,考虑到整体设计/程序要求和负载情况,可以考虑在此函数所在的类的生命周期内保持上下文保持打开状态(似乎是DAL类)。然后实现IDisposable接口并在其中处理上下文的释放。(请记住必须显式调用Dispose)。
如果您只想获取学校名称,并且使用的是C# 7.0,您可以使用命名元组来实现:
public static List<(Student Student, string SchoolName)> GetByType(string connString, int type)
{
    using (mydb_DataContext db = new mydb_dbDataContext(connString))
    {
        return (from t1 in db.Students
                join school in db.Schoold on t1.SchoolId equals school.Id
                where t1.type = type
                select (t1, school.Name)).ToList();
    }
}

如果您遇到编译错误 CS8137,则需要安装System.ValueTuple的Nuget包。

谢谢您的建议。我会尝试一下。我刚刚更新了我的问题,使用了另一种方法。我会测试性能并在此线程中更新。 - TPG
1
@teapeng - 抱歉,我错过了Linq to SQL而不是EF。请看这里以设置关系,并且您也可以执行连接以获取数据。 - Gilad Green
@teapeng - 已更新加入可能的样式 - Gilad Green

2

使用Linq2Sql,您可以使用LoadWith语句,例如:

using (mydb_DataContext db = new mydb_dbDataContext(connString))
{
    DataLoadOptions op = new DataLoadOptions();
    op.LoadWith<Student>(o => o.School);

    db.LoadOptions = op;
    return (from t1 in db.Students
        where t1.type = type
        select t1).ToList();
}

唯一的缺陷是,这将检索学校表中的所有列。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接