EntityFramework因来自MVC Web Api的多个SELECT请求而失败

时间:2013-01-02 09:25:15

标签: sql-server asp.net-mvc entity-framework asp.net-web-api dbcontext

目前我正在使用MVC4的Web Api功能构建api,使用EntityFramework 4,禁用延迟加载和代理创建。由于我正在迁移现有的MySQL数据库,因此我使用了数据库优先策略。

我的服务器在带有IIS 8和Microsoft SQL Server 2012的Windows Server 2012(目前仍为数据中心RC)上运行。

我认为我遇到的问题不是“功能”类别,而是“性能”类别。在示例中,我有一个Person对象。此对象具有子项列表和城市对象(具有城市的基本信息):

[DataContract(IsReference = true)]
public partial class Person
{
    public Person()
    {
        this.Children = new HashSet<Children>();
    }

    [DataMember]
    public int ID { get; set; }
    [DataMember]
    public int ParentID { get; set; }
    [DataMember]
    public int CityID { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public int Age { get; set; }

    [DataMember]
    public virtual ICollection<Person> Children { get; set; }
    [DataMember]
    public City City { get; set; }
}

[DataContract(IsReference = true)]
public partial class City
{
    [DataMember]
    public int ID { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public int Residents { get; set; }
}

Note: These classes are generated by EntityFramework/DBContext

这些类在PersonsController中使用,以使用httpget:

从人员检索信息
public class PersonsController : ApiController
{
    private MyEntities db = new MyEntities();

    [HttpGet]
    public Person Get(int id, bool getChildren = false, bool getCity = false)
    {
        Person person = this.db.Persons.SingleOrDefault(p => p.ID == id);
        if (person == null)
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
        }

        if (getChildren)
        {
            person.Children = this.db.Persons.Where(c => c.ParentID == person.ID)
        }

        if (getCity)
        {
            person.Customer = this.db.Cities.SingleOrDefault(r => r.ID == person.CityID);
        }

        return person;
    }
}

首先,我希望有人可以给我一些信息,如果这是在Web Api中使用EntityFramework的正确方法,尤其是db对象的创建。我已经阅读了很多关于创建所谓的存储库类的文章,但我选择不这样做。

现在我正在创建这个问题的问题; 当我执行请求获取ID为1的Person的信息时,一切顺利。同时将GetChildren和getCity参数设置为true。 (这适用于数据库中的所有人员)。 但是,这是在当时执行一个请求时。当我使用Fiddler在彼此之后快速执行相同的请求时,在一对请求之后开始出现500错误。然后有几个请求再次没问题,然后失败了几次等等。

当请求失败时,它会出现以下错误消息之一:     不允许新事务,因为会话中正在运行其他线程。 要么     无法执行事务操作,因为存在处理此事务的待处理请求。

所以这实际上是说他无法创建一个新事务,因为此会话中还有其他线程,并且它也无法向事务添加请求,因为已经有队列已经完成。

希望你明白这真的很烦人,因为当api上线并且多个用户同时使用时也会发生这种情况。

有谁知道如何解决上述错误?请检查我上面的实现示例,可能不是最佳:)

提前致谢!

1 个答案:

答案 0 :(得分:0)

您可以通过在连接字符串中添加“MultipleActiveResultSets = True”来启用MARS来解决此问题。你必须启用MARS的原因是你在一个连接上执行多个查询,即DbContext。

替代和更好的方法是不启用MARS并通过执行此操作来优化您执行单个查询的操作(Entityframework eager loading)。这具有调用单个查询与3个查询(最坏情况)的优势。

public class PersonsController : ApiController
{
    private MyEntities db = new MyEntities();

    public Person Get(int id, bool getChildren = false, bool getCity = false)
    {
        var people = this.db.Persons;

        if(getChildren)
        {
            people = people.Include("Children");
        }

        if(getCity)
        {
            people = people.Include("City");
        }

        Person person = people.SingleOrDefault(p => p.ID == id);
        if (person == null)
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
        }

        return person;
    }
}