实体框架:如何在DbContext被处理之前从其他方法中查询模型
本文关键字:其他 方法 模型 查询 处理 框架 DbContext 实体 | 更新日期: 2023-09-27 18:05:54
我有以下方法,该方法在调用时接受DataTime
参数并根据传递的日期返回记录。
方法:
public static void GetVehicleByReleasedDate(DateTime parameter)
{
using (EntityDataModel context = new EntityDataModel())
{
var query =
from vehicle in context.Catalog
where vehicle.ReleaseDate >= parameter.Date
select new
{
VehicleMake = vehicle.VehicleMake,
ManufactureID = vehicle.ManufactureID,
ManufactureDate = vehicle.ManufacturedDate,
VehicleIdentificationNumber = vehicle.VehicleIdentificationNumber
};
foreach (var vehicle in query)
{
Console.WriteLine("Format and write result to Console",
vehicle.ManufactureID,
vehicle.ManufactureDate,
vehicle.VehicleIdentificationNumber,
vehicle.VehicleMake);
}
}
}
与上述不同,我需要返回一个IQueryable
对象或Catalog,以便我可以在方法之外执行查询。
:
public static IQueryable<Catalog> GetVehicleByReleasedDate()
{
using (EntityDataModel context = new EntityDataModel())
{
return context.Catalog;
}
}
然后像这样调用方法:
static void Main(string[] args)
{
var query = from vehicle in GetVehicleByReleasedDate()
where vehicle.ReleaseDate >= DateTime.Now
select new
{
VehicleMake = vehicle.VehicleMake,
ManufactureID = vehicle.ManufactureID,
ManufactureDate = vehicle.ManufacturedDate,
VehicleIdentificationNumber = vehicle.VehicleIdentificationNumber
};
foreach (var vehicle in query)
{
Console.WriteLine("{0} {1:d} {2} {3}",
vehicle.ManufactureID,
vehicle.ManufactureDate,
vehicle.VehicleIdentificationNumber,
vehicle.VehicleMake);
}
Console.ReadKey();
}
可以看出,我得到了一个错误,因为在GetVehicleByReleasedDate()
中的使用处理了上下文。
错误信息:
The operation cannot be completed because the DbContext has been disposed.
我如何写这个,以便我可以简单地通过查询从另一个方法使用返回类型的方法在Context
被处置之前?
更新:
下面是EntityDataModel类:
public partial class EntityDataModel : DbContext
{
public EntityDataModel()
: base("name=EntityDataModel")
{
}
public virtual DbSet<Catalog> Catalog { get; set; }
public virtual DbSet<Model> Model { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Catalog>()
.Property(e => e.VehicleIdentificationNumber)
.IsFixedLength();
}
}
最后是Catalog模型。
[Table("Automobile.Catalog")]
public partial class Catalog
{
[Key]
public long ManufactureID { get; set; }
[Required]
[StringLength(100)]
public string VehicleMake { get; set; }
[Required]
[StringLength(17)]
public string VehicleIdentificationNumber { get; set; }
[Column(TypeName = "date")]
public DateTime ManufacturedDate { get; set; }
[Column(TypeName = "date")]
public DateTime ReleaseDate { get; set; }
}
IQueryable接口非常懒惰。它只在真正需要的时候计算查询。我建议在查询结束时使用。tolist()来实现它:
var query =
(from vehicle in context.Catalog
where vehicle.ReleaseDate >= parameter.Date
select new
{
VehicleMake = vehicle.VehicleMake,
ManufactureID = vehicle.ManufactureID,
ManufactureDate = vehicle.ManufacturedDate,
VehicleIdentificationNumber = vehicle.VehicleIdentificationNumber
}).ToList();
否则,由于您的using
语句,当IQueryable最终计算查询时,上下文将已经被处置。使用ToList()
,您强制实现查询,结果将存储在内存中。
UPDATE:为了使答案更完整,正如Gert Arnold指出的:
// YourStaticClass.cs
public static IEnumerable<Catalog> GetVehicleByReleasedDate(DateTime parameter)
{
using (var context = new EntityDataModel())
{
return context.Catalog
.Where(x => parameter.Date <= x.ReleaseDate)
.ToList();
}
}
// Main.cs
static void Main(string[] args)
{
var vehicles = YourStaticClass.GetVehicleByReleasedDate(DateTime.Today);
foreach (var vehicle in vehicles)
{
Console.WriteLine("{0} {1:d} {2} {3}",
vehicle.ManufactureID,
vehicle.ManufactureDate,
vehicle.VehicleIdentificationNumber,
vehicle.VehicleMake);
}
Console.ReadKey();
}
像这样,当上下文仍然"未处理"时,您实现查询。您可以将数据输出到任何需要的地方并对其进行处理。
GetVehicleByReleaseDate可以将上下文作为参数,因此它不控制上下文的生存期,而只是控制模型在返回之前如何被操作。我强烈建议仍然保持上下文的生命周期较短。
public static IQueryable<Catalog> GetVehicleByReleasedDate(EntityDataModel context)
{
//Do whatever data manipulations you need here.
}
然而,如果GetVehcileByReleaseDate除了从上下文返回实体之外没有做太多事情,你还需要它吗?
你签出仓库模式了吗?您可以为存储库对象的生命周期创建上下文。像这样:
http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspxUPDATED:
如果您想保持EF和静态方法的耦合,请尝试这样的回调设置:
public static void GetVehicleByReleasedDate(Func<DbSet<Catalog>, IQueryable<dynamic>> query, Action<IQueryable<dynamic>> useQuery)
{
using (EntityDataModel context = new EntityDataModel())
{
useQuery(query(context.Catalog));
}
}
public static T GetVehicleByReleasedDate<T>(Func<DbSet<Catalog>, IQueryable<dynamic>> query, Func<IQueryable<dynamic>, T> useQuery)
{
using (EntityDataModel context = new EntityDataModel())
{
return useQuery(query(context.Catalog));
}
}
,并像这样命名:
static void Main(string[] args)
{
GetVehicleByReleasedDate
(
catalog=>
from vehicle in catalog
where vehicle.ReleaseDate >= DateTime.Now
select new
{
VehicleMake = vehicle.VehicleMake,
ManufactureID = vehicle.ManufactureID,
ManufactureDate = vehicle.ManufacturedDate,
VehicleIdentificationNumber = vehicle.VehicleIdentificationNumber
},
query=>
{
foreach (var vehicle in query)
{
Console.WriteLine("{0} {1:d} {2} {3}",
vehicle.ManufactureID,
vehicle.ManufactureDate,
vehicle.VehicleIdentificationNumber,
vehicle.VehicleMake);
}
}
);
Console.ReadKey();
}
更新2 :
如果你有兴趣从EF解耦,那么试试这个:
public class IEntityRepository : IDisposable
{
IQueryable<Catalog> GetVehicleByReleasedDate();
}
public class EFEntityRepository : IEntityRepository
{
private EntityDataModel context = new EntityDataModel():
public IQueryable<Catalog> GetVehicleByReleasedDate()
{
return this.context.Catalog;
}
public void Dispose()
{
this.context.Dispose();
this.context = null;
}
}
public class Consumer
{
private Func<IEntityRepository> createRepository;
public Consumer(Func<IEntityRepository> createRepository) { this.createRepository = createRepository; }
public void OutputData()
{
using (var repository = this.createRepository())
{
var query = from vehicle in repository.GetVehicleByReleasedDate()
where vehicle.ReleaseDate >= DateTime.Now
select new
{
VehicleMake = vehicle.VehicleMake,
ManufactureID = vehicle.ManufactureID,
ManufactureDate = vehicle.ManufacturedDate,
VehicleIdentificationNumber = vehicle.VehicleIdentificationNumber
};
foreach (var vehicle in query)
{
Console.WriteLine("{0} {1:d} {2} {3}",
vehicle.ManufactureID,
vehicle.ManufactureDate,
vehicle.VehicleIdentificationNumber,
vehicle.VehicleMake);
}
}
}
}
public class Program
{
static void Main(string[] args)
{
var consumer = new Consumer(()=>new EFEntityRepository());
consumer.OutputData();
}
}
您需要一个依赖注入库来控制它。看看Autofac和它的生命周期。我将它用于web应用程序,并将创建的对象(例如DbContext)的生命周期设置为整个HTTP请求的生命周期,它工作得很好。
http://docs.autofac.org/en/stable/lifetime/index.htmlhttp://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac范围