我正在尝试使用Entity Framework向我的DbContext添加单例模式。我总是使用单例模式,之前从未遇到过这个错误。 我知道单身人士是最佳做法 (显然不是),但是如果你们有空闲时间,请解释为什么单身人士是最佳做法?
问题
除此之外,我收到了这个错误:
底层提供程序在打开时失败
让我们来看看我的代码
DAO.cs
public class DAO
{
private static HourRegistrationEntities hourRegInstance;
public static HourRegistrationEntities HourRegInstance { get { return hourRegInstance = hourRegInstance ?? new HourRegistrationEntities(); } }
}
Service.cs(示例方法)
/// <summary>
/// Return a list of all denied Hour Registration for the Login with the given stringId
/// </summary>
/// <param name="stringId"></param>
/// <returns>A list of HourRegistrationDTO</returns>
public List<HourRegistrationDTO> GetAllDeniedHoursForLogin(string stringId)
{
var id = Int32.Parse(stringId);
using (var db = DAO.HourRegInstance)
{
var dbHours = db.HourRegistration.Where(x => x.LoginProject.Login.ID == id && x.Denied == true).ToList();
var returnList = new List<HourRegistrationDTO>();
foreach (var item in dbHours)
{
returnList.Add(new HourRegistrationDTO()
{
Id = item.ID,
Hours = item.Hours,
Date = item.Date.ToShortDateString(),
Comment = item.Comment,
CommentDeny = item.CommentDeny,
LoginProject = new LoginProjectDTO()
{
Project = new ProjectDTO()
{
Title = item.LoginProject.Project.Title
}
}
});
}
return returnList;
}
}
如上所述,我总是使用单例模式,但从不之前有过此错误。造成这种情况的原因是什么?为什么?
更新
我基本上喜欢这样(下面的代码),因为这解决了问题。现在我对导致错误的原因更加好奇。
Service.cs
using (var db = new HourRegistrationEntities())
答案 0 :(得分:8)
它不起作用的原因是你的using
子句在首次使用后处理你的单例实例。在那之后,它变得无用,处置但仍然不为空。
你坚持要求你总是使用单身人士这一事实并不总是有效。将单例用于数据上下文被认为是一种非常糟糕的习惯,会导致许多问题,包括内存,并发和事务问题。
我的猜测是,在你总是使用单线程桌面应用程序之前,单例仍然存在风险,但不会导致直接问题。然而,在这里,在Web服务的并发世界中,它将无法工作。
另一方面,每次wcf调用创建一个新实例是完全有效的,不同的实例不会干扰,并且在使用后你可以正确处理它们。
答案 1 :(得分:3)
我建议您使用“锁定”功能来访问您的单件对象:
public sealed class XModelInstance
{
private static XDBEntities edmx = null;
private static readonly object padlock = new object();
private XModelInstance() { }
public static XDBEntities Edmx
{
get
{
lock (padlock)
{
if (edmx == null)
{
edmx = new XDBEntities();
}
return edmx;
}
}
}
}
这将避免并发访问您的上下文。 当然,不要再使用“using”子句来访问你的上下文了:)
致电示例:
var dbHours = XModelInstance.Edmx.HourRegistration.Where(...);
答案 2 :(得分:2)
确保您将此代码作为构造函数:
public HourRegistrationEntities()
: base("ConnectionStringName")
{
}
然后在名为App.config
web.config
/ ConnectionStringName
中定义连接字符串
这很可能会解决您的问题。
现在关于单身人士:您在每次调用HourRegistrationEntities
时创建GetAllDeniedHoursForLogin
的新实例,这不是单身模式,它的工作单元模式是最佳实践的EntityFramework。继续使用它并忘记单身DbContext,除非你真的知道你做了什么。由于EF跟踪实体及其关系,长期存在的单身DbContext将随着时间的推移变慢。还会有许多其他奇怪的问题,例如未保存的事务,副作用以及许多其他难以调试的问题。