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

时间:2015-08-02 19:25:13

标签: c# linq entity-framework

我有以下方法在调用时接受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对象或目录,以便我可以在方法之外执行查询。

像这样:

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

最后,这是目录模型。

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

4 个答案:

答案 0 :(得分:1)

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()可以强制查询实现,结果将存储在内存中。

更新:为了让答案更加完整,正如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();
}

像这样,当上下文仍然“未被曝光”时,您将实现查询。您可以将数据吐出到您需要的任何地方并进行处理。

答案 1 :(得分:1)

更新

如果您希望保持与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();
    }
}   

答案 2 :(得分:1)

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

答案 3 :(得分:0)

您需要一个依赖注入库来为您控制。看看Autofac及其生命周期。我将它用于Web应用程序,并将创建的对象的生命周期(例如DbContext)设置为整个HTTP请求的生命周期,并且工作正常。

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