简体   繁体   English

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

[英]Entity Framework: How to query a model from other methods before DbContext is disposed?

I have the following Method which accepts a DataTime argument when called and returns records according to the date passed. 我有以下方法在调用时接受DataTime参数,并根据传递的日期返回记录。

Method: 方法:

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

Instead of the above, I need to return the an IQueryable object or the Catalog so that I can perform the query outside of the method. 而不是上面,我需要返回一个IQueryable对象或目录,以便我可以在方法之外执行查询。

Like this: 像这样:

    public static IQueryable<Catalog> GetVehicleByReleasedDate()
    {
        using (EntityDataModel context = new EntityDataModel())
        {
            return context.Catalog;
        }
    }

Then call the method like this: 然后调用这样的方法:

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

As you can tell, I get an error because the using in the GetVehicleByReleasedDate() disposes of the context. 正如你所知,我得到一个错误,因为在GetVehicleByReleasedDate()处理了上下文。

Error message: 错误信息:

The operation cannot be completed because the DbContext has been disposed.

How do I write this so that I can simply pass queries to the method from another method using the return type before the Context is disposed? 我如何编写这个,以便我可以简单地在处理Context之前使用返回类型从另一个方法向该方法传递查询?

Update: 更新:

Here is the EntityDataModel Class: 这是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();
        }
    }

Finally, here is the Catalog model. 最后,这是目录模型。

[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; }
}

The IQueryable interface is very lazy. IQueryable界面非常懒惰。 It only evaluates the query when it really needs to. 它只在真正需要时才评估查询。 I would suggest using .ToList() on the end of your query to materialize it: 我建议在查询结尾处使用.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();

Otherwise, because of your using statement, the context will already have been disposed when IQueryable finally evaluates the query. 否则,由于您的using语句,当IQueryable最终评估查询时,上下文已经被处理掉了。 With ToList() you force the query to be materialized and the result will be stored in memory. 使用ToList()可以强制查询实现,结果将存储在内存中。

UPDATE: To make the answer more complete, as Gert Arnold pointed out: 更新:为了使答案更加完整,格特阿诺德指出:

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

Like this, you materialize the query when the context is still 'undisposed'. 像这样,当上下文仍然“未被曝光”时,您将实现查询。 You can spit out the data to wherever you need it and process it. 您可以将数据吐出到您需要的任何地方并进行处理。

UPDATED : 更新

If you want to remain coupled to EF and static methods, try a callback setup like this: 如果您希望保持与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));
        }
    }

and call it like this: 并称之为:

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

UPDATE 2 : 更新2

If you are interested in decoupling from EF, then try this: 如果您有兴趣从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();
    }
}   

GetVehicleByReleaseDate can take a context as a parameter, so it doesn't control the lifetime of the context, just how the model is manipulated before it is returned. GetVehicleByReleaseDate可以将上下文作为参数,因此它不控制上下文的生命周期,只是控制模型在返回之前的操作方式。 I would strongly recommend still keeping the lifetime of the context short. 我强烈建议仍然保持上下文的生命周期。

public static IQueryable<Catalog> GetVehicleByReleasedDate(EntityDataModel context)
{
    //Do whatever data manipulations you need here.
}

However, if GetVehcileByReleaseDate doesn't do much besides return entities from the context, do you even need it? 但是,如果GetVehcileByReleaseDate除了从上下文中返回实体之外没有做太多,你甚至需要它吗?

Have you checked out the repository pattern? 你检查了存储库模式吗? You can create the context for the lifetime of the repository object. 您可以为存储库对象的生命周期创建上下文。 Something along the lines of this: 有点像这样:

http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspx http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspx

You need a dependency injecttion library that controls this for you. 您需要一个依赖注入库来为您控制它。 Look at Autofac and its life time. 看看Autofac及其生命周期。 I use it for web applications and set the life time of objects created (eg DbContext) to the lifetime of the whole HTTP request and it works fine. 我将它用于Web应用程序并将创建的对象的生命周期(例如DbContext)设置为整个HTTP请求的生命周期,并且它工作正常。

http://docs.autofac.org/en/stable/lifetime/index.html http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac#scope http://docs.autofac.org/en/stable/lifetime/index.html http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac#scope

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 实体框架dbContext处理为时过早 - Entity Framework dbContext is disposed too early 实体框架 DbContext 不使用依赖注入进行处置 - Entity Framework DbContext is NOT disposed using dependency injection 是否可以在调用DbContext.SaveChanges之前查询Entity Framework? - Is it possible to query Entity Framework before calling DbContext.SaveChanges? 处置上下文后,如何从实体框架(数据库优先)返回包含导航属性的模型? - How do I return a Model from Entity Framework (Database First) that includes the Navigation Properties after the context is disposed? 在异步方法完成之前处理EF Core DbContext - EF Core DbContext being disposed of before Async methods are complete 实体框架 6.1.3 当 dbContext 处理的分离对象为空时 - Entity Framework 6.1.3 when dbContext disposed detached objects are null 实体框架DbContext在查询中 - Entity Framework DbContext Where In Query 如何在DbContext之外使用Entity Framework之前创建数据库? - How to make Entity Framework create database before using it outside DbContext? 从Entity Framework 6 Model中分离POCO Object类和DBContext - Separate POCO Object classes and DBContext from Entity Framework 6 Model 如何在实体框架中识别DbContext? - How To identify DbContext in entity framework?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM