[英]Avoiding ObjectDisposedException with LINQ (LINQ2SQL)
我遇到了Linq的“懒惰IO问题”,我还没有找到一个我很满意的解决方案
假设我们有SQL表,看起来像
create table Person (
id int primary key not null,
name text not null,
)
create table Dog (
name text primary key not null,
ownerid text primary key not null references Person(name)
)
在C#中,我们希望使用LINQ和Entity Framework来处理这个问题。 实体框架类被定义为partial
因此我们可以扩展它们以添加.Get(string)
方法,这使得代码非常干净。
public partial class Dog
{
public static Dog Get(string dogname)
{
using (var db = new MyDataContext())
{
// LINQ is lazy and doesn't load the referenced Person
return db.Dogs.Single(d => d.name == dogname);
}
}
}
现在我们尝试使用Dog
对象
public string DogJson(string dogname)
{
var dog = Dog.Get(dogname);
return JsonConvert.SerializeObject(dog);
}
由于我们的实例dog
包含dog.Owner
因为外键, JsonConvert
当然会尝试将它包含在json字符串中。 但是由于DataContext被ObjectDisposedException
且LINQ是惰性的,因此当然会引发ObjectDisposedException
,因为在我们处理DataContext时没有评估dog.Person
。
在这种情况下,我们根本不关心Owner
对象,我们只想将Dog
序列化为json。 没有这种方法最好的方法是什么?
我有一个解决方案,但我不是特别喜欢它。 使用投影到一个不祥的对象并回滚到Dog
,因为我们不允许在查询中显式构造一个Dog
。
public static Dog Get(string dogname)
{
using (var db = new MyDataContext())
{
var tmpdog = db.Dogs.Where(d => d.name == dogname)
.Select(d => new { name = d.name, ownerid = d.ownerid}).Single();
return new Dog() { name = tmpdog.name, ownerid = tmpdog.ownerid};
}
}
我不喜欢这种解决方案,因为它不能很好地扩展。 这个例子只有两个属性,这很快就会失控。 LINQ通常会生成非常优雅的代码,这根本不是优雅的。 它也很容易受到程序员的影响
有点像我在这里采取错误的方法。
我之前也遇到过这个问题,但幸运的是实体框架提供了一种简单的方法。 您可以在查询之前禁用延迟加载和动态代理的创建。 这将允许json序列化器无异常运行。
public static Dog Get(string dogname)
{
using (var db = new MyDataContext())
{
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.LazyLoadingEnabled = false;
return db.Dogs.Single(d => d.name == dogname);
}
}
真正的问题是你的调用者应该决定DbContext
的生命周期,而不是被调用者,因为DogJson
方法定义了工作单元。 理想情况下,您应该将DbContext
实例传递给静态Get
方法。
所以,你的Get
代码看起来应该更像这样:
public static Dog Get(string dogname, MyDataContext db)
{
var result = db.Dogs.SingleOrDefault(d => d.name == dogname);
return result;
}
然后,您可以在调用者中执行所有DTO修改,因为这确实是您的工作单元:
public string DogJson(string dogname)
{
using (var db = new MyDataContext())
{
var dog = Dog.Get(dogname, db);
var dogDTO = new Dog { name = dog.name, ownerid = dog.ownerid };
return JsonConvert.SerializeObject(dogDTO);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.