实体框架:如何在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; }
}

实体框架:如何在DbContext被处理之前从其他方法中查询模型

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.aspx

UPDATED:

如果您想保持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范围