这个连接已经有一个打开的DataReader,必须先关闭它 + asp.net mvc。

7
我有一个mysql数据库,其中包含一个名为“entites”的表,其中有多个字段,例如entity_title、entity_description等。在该表中还有3个外键user_id、region_id和category_id。
在我的Index View页面中,我希望以表格形式显示所有实体(显示标题、描述等),用户名称、地区名称和类别名称也要一并展示。
以下是我在控制器中的操作:
public ActionResult Index()
{
    var model = this.UnitOfWork.EntityRepository.Get();
    return View(model);
}

在我的代码仓库中,我做了这个操作:
public virtual IEnumerable<TEntity> Get(
    Expression<Func<TEntity, bool>> filter = null,
    Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
    string includeProperties = "")
{
    IQueryable<TEntity> query = _dbSet;

    if (filter != null)
    {
        query = query.Where(filter);
    }

    foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
    {
        query = query.Include(includeProperty);
    }

    if (orderBy != null)
    {
        return orderBy(query).ToList();
    }
    else
    {
        return query.ToList();
    }
}

我经常在最后一个规则(return query.ToList())中遇到错误信息Input string was not in a correct format
但是,当我检查了规则IQueryable<TEntity> query = _dbSet;后,它已经出现了错误:There is already an open DataReader associated with this Connection which must be closed first.
这可能是因为我想从多个表中选择。 但是我该如何解决呢? 我尝试将MultipleActiveResultSets=True"添加到我的ConnectionString中,就像这样:
<connectionStrings>
<add name="reuzzeCS" connectionString="server=localhost;uid=root;pwd=*****;Persist Security Info=True;database=reuzze;MultipleActiveResultSets=True"" providerName="MySql.Data.MySqlClient" />

但是这给了我一个错误,说关键词不存在,因为我使用的是 MySql.Data.MySqlClient ..

执行的查询是:

{SELECT Extent1.entity_id, Extent1.entity_title, Extent1.entity_description, Extent1.entity_starttime, Extent1.entity_endtime, Extent1.entity_instantsellingprice, Extent1.entity_shippingprice, Extent1.entity_condition, Extent1.entity_views, Extent1.entity_created, Extent1.entity_modified, Extent1.entity_deleted, Extent1.user_id, Extent1.region_id, Extent1.category_id FROM entities AS Extent1}

但是当他想要执行查询并且我想要扩展结果时,我得到了错误 已经有一个与此连接关联的打开的 DataReader,必须先关闭

编辑:
我的完整存储库:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace App.Data.orm.repositories
{
// REPO FROM TEACHER
public class GDMRepository<TEntity> where TEntity : class
{
    internal GDMContext _context;
    internal DbSet<TEntity> _dbSet;

    public GDMRepository(GDMContext context)
    {
        this._context = context;
        this._dbSet = _context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = _dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual TEntity GetByID(object id)
    {
        return _dbSet.Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        _dbSet.Add(entity);
    }

    public virtual void Delete(object id)
    {
        TEntity entityToDelete = _dbSet.Find(id);
        Delete(entityToDelete);
    }

    public virtual void Delete(TEntity entity)
    {
        if (_context.Entry(entity).State == EntityState.Detached)
        {
            _dbSet.Attach(entity);
        }
        _dbSet.Remove(entity);
    }

    public virtual void Update(TEntity entity)
    {
        _dbSet.Attach(entity);
        _context.Entry(entity).State = EntityState.Modified;
    }
}
}

GDMContext class:

using App.Data.orm.mappings;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace App.Data.orm
{
public class GDMContext:DbContext
{
    public GDMContext() : base("reuzzeCS") { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        //REMOVE STANDARD MAPPING IN ENTITY FRAMEWORK
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        //REGISTER MAPPERS
        modelBuilder.Configurations.Add(new UserMapping());
        modelBuilder.Configurations.Add(new PersonMapping());
        modelBuilder.Configurations.Add(new RoleMapping());

        modelBuilder.Configurations.Add(new EntityMapping());
        modelBuilder.Configurations.Add(new MediaMapping());
        modelBuilder.Configurations.Add(new BidMapping()); 
        modelBuilder.Configurations.Add(new CategoryMapping());
        modelBuilder.Configurations.Add(new AddressMapping());
        modelBuilder.Configurations.Add(new RegionMapping()); 
        modelBuilder.Configurations.Add(new MessageMapping());
    }
}
}

我的实体模型:

public class Entity
{
    public Int64 Id { get; set; }
    [Required(ErrorMessage = "Title is required")]
    [StringLength(255)]
    [DisplayName("Title")]
    public string Title { get; set; }
    [Required(ErrorMessage = "Description is required")]
    [DisplayName("Description")]
    public string Description { get; set; }
    [Required]
    public DateTime StartTime { get; set; }
    [Required]
    public DateTime EndTime { get; set; }
    /*[Required(ErrorMessage = "Type is required")]
    [StringLength(16)]
    [DisplayName("Type")]
    public string Type { get; set; }*/
    [Required]
    public decimal InstantSellingPrice { get; set; }
    public Nullable<decimal> ShippingPrice { get; set; }

    public Condition? Condition { get; set; }
    public Nullable<Int64> Views { get; set; }

    [Required]
    public DateTime CreateDate { get; set; }
    public Nullable<DateTime> ModifiedDate { get; set; }
    public Nullable<DateTime> DeletedDate { get; set; }

    public Int32 UserId { get; set; }

    public Int32 RegionId { get; set; }

    public Int16 CategoryId { get; set; }

    public virtual User User { get; set; }
    public virtual Region Region { get; set; }
    public virtual Category Category { get; set; }
    //public virtual ICollection<Category> Categories { get; set; }
    public virtual ICollection<User> Favorites { get; set; }
    public virtual ICollection<Bid> Bids { get; set; }
    public virtual ICollection<Media> Media { get; set; }
}

public enum Condition
{
    New = 1,
    Used = 2
}

我的实体映射:

internal class EntityMapping : EntityTypeConfiguration<Entity>
{
    public EntityMapping()
        : base()
    {
        this.ToTable("entities", "reuzze");

        this.HasKey(t => t.Id);
        this.Property(t => t.Id).HasColumnName("entity_id").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        this.Property(t => t.Title).HasColumnName("entity_title").IsRequired().HasMaxLength(255);
        this.Property(t => t.Description).HasColumnName("entity_description").IsRequired();
        this.Property(t => t.StartTime).HasColumnName("entity_starttime").IsRequired();
        this.Property(t => t.EndTime).HasColumnName("entity_endtime").IsRequired();
        //this.Property(t => t.Type).HasColumnName("entity_type").IsRequired();
        this.Property(t => t.InstantSellingPrice).HasColumnName("entity_instantsellingprice").IsRequired();
        this.Property(t => t.ShippingPrice).HasColumnName("entity_shippingprice").IsOptional();
        this.Property(t => t.Condition).HasColumnName("entity_condition").IsRequired();
        this.Property(t => t.Views).HasColumnName("entity_views").IsOptional();
        this.Property(t => t.CreateDate).HasColumnName("entity_created").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
        this.Property(t => t.ModifiedDate).HasColumnName("entity_modified").IsOptional();
        this.Property(t => t.DeletedDate).HasColumnName("entity_deleted").IsOptional();

        this.Property(t => t.UserId).HasColumnName("user_id").IsRequired();
        this.Property(t => t.RegionId).HasColumnName("region_id").IsRequired();
        this.Property(t => t.CategoryId).HasColumnName("category_id").IsRequired();

        //FOREIGN KEY MAPPINGS
        this.HasRequired(t => t.User).WithMany(p => p.Entities).HasForeignKey(f => f.UserId).WillCascadeOnDelete(false);
        this.HasRequired(t => t.Region).WithMany(p => p.Entities).HasForeignKey(f => f.RegionId);
        this.HasRequired(t => t.Category).WithMany(p => p.Entities).HasForeignKey(f => f.CategoryId);

        //MANY_TO_MANY MAPPINGS
        this.HasMany(t => t.Favorites)
            .WithMany(t => t.Favorites)
            .Map(mc =>
            {
                mc.ToTable("favorites");
                mc.MapLeftKey("entity_id");
                mc.MapRightKey("user_id");
            });
    }
}

这里是stacktrace图像的链接!

更新:

  • 基础 {选择 Extent1.entity_id, Extent1.entity_title, Extent1.entity_description, Extent1.entity_starttime, Extent1.entity_endtime, Extent1.entity_instantsellingprice, Extent1.entity_shippingprice, Extent1.entity_condition, Extent1.entity_views, Extent1.entity_created, Extent1.entity_modified, Extent1.entity_deleted, Extent1.user_id, Extent1.region_id, Extent1.category_identities 中选取 AS Extent1} System.Data.Entity.Internal.Linq.InternalQuery {System.Data.Entity.Internal.Linq.InternalSet}

你有没有其他地方查询数据库?MySQL不支持MARS。你需要确保在开始新的查询之前始终调用ToList(),以便查询执行。(即:您不能使用MySQL一次执行多个查询)。 - Kenneth
我不这么认为,我修改了我的起始帖子,这可能是问题吗? - nielsv
如果您直接运行该查询,它是否有效? - Paddy
在此之前是否运行了其他查询?_dbSet是如何实例化的? - Paddy
当我在phpmyadmin中运行查询时,它可以正常工作!我在我的帖子中贴出了代码以展示如何实例化_dbSet。 - nielsv
显示剩余7条评论
4个回答

4
您的问题是:
我认为 MySql 连接器可能不支持多个活动结果集,因此连接字符串中的设置对您没有帮助。
所以请尝试使用以下方法替代您的代码。
编辑:
query.Include("User").Include("Region").Include("Category").ToList(); 

如果您在更改后仍然遇到相同的错误,请告诉我。

更新:

我已经为您更改了一些内容,请使用此代码替换您的方法。

 public virtual IEnumerable<TEntity> Get(
    Expression<Func<TEntity, bool>> filter = null,
    Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
    string includeProperties = "")
        {
            IQueryable<TEntity> query = _dbSet;

            if (filter != null)
            {
                query = query.Where(filter);
            }


            if (orderBy != null)
            {
                return orderBy(query.Include("User").Include("Region").Include("Category").ToList()).ToList();
            }
            else
            {
                return query.Include("User").Include("Region").Include("Category").ToList(); 
            }
        }

更新2:
EF正确处理连接,问题不在于关闭连接。我对这个问题的理解是,在单个连接上执行多个数据检索命令(或单个命令有多个选择)时,下一个DataReader在第一个DataReader完成读取之前被执行。避免异常的唯一方法是允许多个嵌套的DataReaders = 打开MultipleActiveResultSets。另一个场景是当你迭代查询结果(IQueryable)并且你将触发迭代内已加载实体的延迟加载时,总是发生这种情况。
而且stackoverflow上有很多人得到了关于你的问题的解决方案:
1:Entity Framework:存在与此命令关联的打开的DataReader 2:如何避免"MySql/net connector中已经有与此连接关联的打开的DataReader"? 3:错误:存在与此命令关联的打开DataReader 我的个人建议是,我认为你不应该花更多时间来解决这个错误,因为时间和精力浪费,并且你可以通过手动查询来完成它。所以请尝试不同的方法。
你不需要拆分和格式化查询以避免 "输入字符串格式不正确" 错误。
你可以用这种方式来代替 return query.ToList();
return _dbSet.Users
    .Include(x => x.Region)
    .Include(x => x.Category).ToList();

我认为您可以通过使用我上面的SO链接来完成它。

我的主要问题是:

Entity Framework可以支持ORM概念,那么为什么不尝试这种方式呢?您可以改变使用ORM概念的想法。这可能会解决这个问题。这是一个链接,请参考这个教程


当我在includeProperties中添加所有的外键时,仍然会出现错误。我已经将我的实体模型和映射添加到帖子中。 - nielsv
@nielsv 嘿,我不是指外键,我是指外部表。 - Ramesh Rajendran
是的,已添加。我是这样做的:var model1 = this.UnitOfWork.EntityRepository.Get(includeProperties: "User, Region, Category");(也尝试过分开)。实体模型可以在我的帖子中找到(您可以看到用户、地区、类别)。 - nielsv
是的,你的foreach循环创建了那个问题。因为你的查询没有正确获取包含的值。请注意我已经更新了我的答案,请检查一下。 - Ramesh Rajendran
@nielsv,请分享您的解决方案,因为这有助于其他人。 - Ramesh Rajendran
显示剩余6条评论

3

更新

好的,从您的堆栈跟踪中看来,"open DataReader associated ...blah" 似乎是一个误导。也许那是 Visual Studio 和它的智能感知可视化调试工具试图向您展示 dbset 中包含的值,但连接仍然打开或类似的情况。

对我来说,EF 的 MySqlDatareader 正在执行枚举结果并将其映射到 POCO(Plain Old CLR Object)。

也许您的数据库中有一个表上的列是 varchar(..) 或类似的东西,并且在您的 POCO 中,它的映射属性是 oftype(Int32)。因此,如果数据库中存在空字符串或不是数字的值,则在尝试将 null 或空字符串值转换为 Int 时应该会出现 Input string was not in a correct format 异常。我现在刚刚尝试了一下:

enter image description here


我认为问题在于 MySql 不支持 MARS,也可能不支持 Lazy Loading。虽然我找不到任何官方声明这是问题的原因,但我发现了几篇与您相同的问题的帖子。

http://www.binaryforge-software.com/wpblog/?p=163

MySQL + Code First + Lazy Load problem !

http://forums.mysql.com/read.php?38,259559,267490

直到最近,我认为在 IQueryable 上调用 ToList() 会将结果加载到内存中,并且任何导航属性都不会被 LazyLoaded,但这并不完全正确。虽然结果将被持久化到内存中,但该结果的任何虚拟导航属性仍将在尝试访问它们时进行懒加载。

从高层次上讲,LazyLoading 的工作原理是因为 Entity Framework 覆盖 了您的“虚拟”导航属性,并使用其自己的实现从数据库加载实体。

我的猜测是,在您的视图或代码的其他地方,您必须访问一个未经明确加载(使用 Include)的属性。我猜 EF 可能正在尝试在单个连接上执行此操作,这就是为什么您会看到:

There is already an open DataReader associated with this Connection which must be closed first

我会通过以下步骤关闭图片懒加载:

我会通过以下步骤关闭图片懒加载:

public class GDMContext:DbContext
{
    public GDMContext() : base("reuzzeCS") 
    {
        base.Configuration.LazyLoadingEnabled = false; 
    }
}

希望这可以帮到您。

好的...嗯,你能发一下错误的堆栈跟踪吗? - SimonGates
在帖子中添加了堆栈跟踪链接! - nielsv
有没有办法找到导致问题的列?我重新检查了我的模型/映射,但仍然找不到任何问题:/ - nielsv
你能否提供你的表模式及其映射的POCO和映射配置?这可能有点冒险,但也许可以尝试一下... http://msdn.microsoft.com/en-us/library/cc667410.aspx? - SimonGates

2
根据您的堆栈跟踪,框架似乎存在将字符串转换为整数的问题。引用另一个SO答案,“每当您在模型中设置与表不同的类型时,EF都会抛出错误。”
您有几个选择。
如果您使用的是代码优先方法,建议重新生成数据库。
如果您使用的是“代码第二”方法(将数据库表映射到POCO类),则建议重新生成数据库。
如果您以上两种方法均未成功,您可以通过测试每个基于整数的列来缩小出现问题的列的范围,例如:
public ActionResult Index()
{
    var model1 = this.UnitOfWork.EntityRepository.Get(
        includeProperties: "category_id");
    // Did that produce an error? If not, try another column:
    var model2 = this.UnitOfWork.EntityRepository.Get(
        includeProperties: "region_id");
    // etc.

    // If you get to your original code, then try testing other columns
    var model = this.UnitOfWork.EntityRepository.Get();
    return View(model);
}

如果上述方法不起作用怎么办?可能存在连接字符串的问题,如此SO答案中所述。鉴于您的堆栈跟踪似乎没有遇到创建连接的问题,这可能只是一个小概率事件,但值得注意的是,在MARS的连接字符串中似乎多了一个双引号(虽然我确定这可能只是一个抄写错误)。无论如何,如果您无法使任何查询起作用,请确保您的连接字符串看起来正常,像以下内容:
<connectionStrings>
    <add name="reuzzeCS"
        connectionString=
        "server=localhost;database=Reuzze;User Id=root;password=P4ssw0rd"
        providerName="MySql.Data.MySqlClient" />
</connectionStrings>

如果上述方法无效怎么办?请检查您使用的 EntityFramework 版本是否与 MySQL 版本兼容。


我正在使用能够将我的模型映射到数据库的流畅 API。很奇怪,有时我会遇到“输入字符串不正确”的错误,有时则会出现“已经存在...”的错误。这只在一个表格中出现问题。 - nielsv
我可以给你一个在Github上的存储库链接吗?如果你愿意,我可以付费...我真的被这个问题卡住了,而且这很重要。 - nielsv
将我的实体模型和映射添加到帖子中。 - nielsv

0

让我们简化问题。除非你想要,否则没有人能帮助你。首先,我必须提到根据MSDN,在你的connectionString中设置MultipleActiveResultSets=True

这是一个与SQL Server一起使用的功能,允许在单个连接上执行多个批处理。当启用MARS与SQL Server一起使用时,每个使用的命令对象都会向连接添加一个会话。

所以这不适用于MySQL!

我认为你需要在你的connectionString中指定端口号,例如:

<connectionStrings>
    <add name="reuzzeCS" connectionString="server=localhost;uid=root;pwd=*****;Persist Security Info=True;database=reuzze;" providerName="MySql.Data.MySqlClient" />
</connectionStrings>

编辑: 并且,您需要使用Connector/Net,这是一个完全托管的MySQL ADO.NET驱动程序(在此页面中)。它适用于大多数基本的数据库交互场景。它还具有基本的Visual Studio集成。根据此页面,您也需要连接器。

希望对您有所帮助。敬礼。


谢谢您的帮助,但是添加端口号没有任何效果。 - nielsv
将我的实体模型和映射添加到帖子中。 - nielsv
@nielsv 我添加了一些额外的信息。可能会有用。 - Amirhossein Mehrvarzi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接