【问题标题】:LINQ to SQL -> Cannot access a disposed object. Object name: 'DataContext accessed after DisposeLINQ to SQL -> 无法访问已释放的对象。对象名称:'Dispose 后访问的 DataContext
【发布时间】:2017-09-09 11:15:23
【问题描述】:

假设我有 2 张桌子,即学生和学校。在我的学生表中,我有一个链接到学校记录的 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();
    }
}

我将拥有 Student 对象的列表,我可以在 foreach 循环中访问它。但是当我按如下操作时,检索学校名称时会出错。

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

System.ObjectDisposedException: '无法访问已处置的对象。 对象名称:'在 Dispose 之后访问的 DataContext。'。'

我可以知道如何获取存储在返回对象中的外国信息以便我可以访问它们吗?或者更好的方法,如果我可以指定只加载学校名称?

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

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。

【问题讨论】:

  • 此解决方案将为每个返回的学生执行单独的查询。很遗憾去DB这么多次..
  • @GiladGreen 我同意.. 不是最好的性能.. 我想知道为什么 LINQ to SQL 没有一个简单的方法来统计我想带回来.. 我试过 DeferredLoadingEnabled 但我仍然得到空的异物。我不想步入 C#7。如果我使用实体框架,那里有一个 .Include,它会与 EF 一起解决我的问题吗?
  • 但是包含在 LINQ to SQL 中不可用,对吧?

标签: c# linq linq-to-sql


【解决方案1】:

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,则可以这样使用 named tuples

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();
    }
}

如果你得到compilation error CS8137那么你需要安装System.ValueTuple的Nuget包

【讨论】:

  • 感谢您的建议。我会试试看。我刚刚更新了我正在尝试的另一种方法的问题。我将测试性能并更新回此线程。
  • @teapeng - 错过了 linq to sql 而不是 EF。对不起。看看here for setting the relationships,否则你可以执行join来获取数据
  • @teapeng - 更新了加入的样子
【解决方案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();
}

一个缺点是这是检索学校表中的所有列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 2020-04-23
    • 2017-12-24
    • 1970-01-01
    相关资源
    最近更新 更多