在我的网站中,有很多对sql数据库的调用,每次调用时都会传递请求数据的用户ID。我试图建立一个单例类,该类只需要对数据库进行一次调用即可获取该人的ID以及仅需获取一次的其他用户属性。
我以为我所有的设置都正确,并且似乎可以正常工作,所以我将代码更改投入生产,并接到了一些用户的电话,说他们登录时都被识别为我。这是基于我主页顶部的“欢迎”消息,每个人的用户名都显示为我。
我的单身人士在下面。接到电话之后,我开始调试,发现是我认为从未设置过设置值的formValues()方法。唯一被调用的是公共实例方法。我想这对知道他们在做什么的每个人都是显而易见的:)。
我认为这无关紧要,但是变量的实例正在我的代码中被调用,例如:formValues.Instance.firstName。
那么我有多近?这东西可救吗?
public sealed class formValues : System.Web.Services.WebService
{
static readonly formValues instance = new formValues();
public string userName;
public string firstName;
public string personID;
public string secBlur;
public int admin;
public int fafsa;
public int staff;
static formValues()
{
}
formValues()
{
//This retrieves the person logged into windows/active directory
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
userName = id.Name;
// Grab this user's firstname, personID, and Admin status
string mySQL = "exec get_userData @userName";
string cf = System.Configuration.ConfigurationManager.ConnectionStrings["DistrictAssessmentDWConnectionString"].ConnectionString;
SqlConnection connection = new SqlConnection(cf);
SqlCommand command = new SqlCommand(mySQL, connection);
command.Parameters.AddWithValue("@userName", userName);
connection.Open();
SqlDataReader dr = command.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
personID = dr["personID"].ToString();
firstName = dr["firstName"].ToString();
admin = Convert.ToInt32(dr["admin"]);
secBlur = dr["secBlur"].ToString();
fafsa = Convert.ToInt32(dr["FAFSA"]);
staff = Convert.ToInt32(dr["staffSec"]);
}
}
connection.Close();
}
public static formValues Instance
{
get
{
return instance;
}
}
}
答案 0 :(得分:1)
问题在于这些属性(实际上是字段)处于单例状态:
public string userName;
public string firstName;
public string personID;
public string secBlur;
public int admin;
public int fafsa;
public int staff;
...以及在构造函数中填充它们的事实。这意味着您第一次创建该类时,它将被填充。如果您将同一类实例作为单例重用,则构造函数将永远不会再被调用,这意味着填充的值将被设置一次并永久保留。
换句话说,您的用户数据是单例。除非您只有一个用户,否则那不是很好。
首先,我将检索数据的类与包含数据的类分开。
数据可能看起来像这样:
public class UserData
{
public string UserName { get; set; }
public string FirstName { get; set; }
// ..etc...
}
该模型包含数据。它不包含用于填充数据的代码。
然后,创建一个检索数据的类。它不应在构造函数中检索数据。构造函数用于创建类。这不是我们要放置类实际所做的事情的地方。
该类可能具有这样的方法:
public UserData GetUserData()
...将创建UserData
的实例并返回它。
对于它的价值,在大多数情况下,我们不需要创建单例。
假设您有此类:
public class SqlUserDataProvider
{
UserData GetUserData()
{
...
}
}
如果构造函数不执行任何“繁重的工作”(例如读取数据或文件),则每次需要一个实例时,您就可以创建一个新实例。它的效率不如使用单个实例,但是差异通常很小,因此不值得考虑。
或者,您可以创建一个实例并重新使用它。在那种情况下,您将其用作单例,但从技术上讲,它不是一个。单例是类编写的,因此只能创建它的单个实例。大多数时候,没有理由这样做。严格执行关于如何使用该类的限制是额外的代码行。它可能使代码的可维护性降低并且更难调试。因此,这是无益或消极的额外工作。
答案 1 :(得分:0)
基本上,您想进行缓存。对于http请求,您需要检查值是否已经在缓存中,如果不是,请从数据库中读取,否则请使用缓存。 您可以从内置的Cache
开始对于单例,最简单的解决方案是使用Lazy实现它们。这是good article
答案 2 :(得分:0)
实例对象在应用程序生存期内仅创建一次。 因此,您获得私有FormsIdentity的私有构造函数formValues()实际上是在应用程序首次启动后才执行一次。
之后,对于所有传入请求,将给出已填充的实例。 因此,对于其他任何请求,您都会看到相同的用户名。
由于需求是基于每个用户的,而不是整个应用程序中的全局需求,因此“单个”可能无济于事。谢谢。