目前我正在使用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上线并且多个用户同时使用时也会发生这种情况。
有谁知道如何解决上述错误?请检查我上面的实现示例,可能不是最佳:)
提前致谢!
答案 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;
}
}