我有多种通用方法可以从数据库表中读取模型/实体。 一种重要的方法如下:
public static async Task<IList<T>> GetModelsAsync<T>(string query, params DbParameter[] parameters)
{
IList<T> models;
using (SqlConnection con = new SqlConnection(Builder.ConnectionString))
using (SqlCommand command = Db.GetCommand(query, CommandType.Text, parameters))
{
await con.OpenAsync();
command.Connection = con;
using (SqlDataReader dr = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess))
models = ReadModels<T>(dr);
}
return models;
}
GetCommand()
正在建立SqlCommand
。
为了将查询结果转换为C#
类,我使用了DataContext.Translate<T>()
方法,该方法工作得很好,除了我现在遇到的问题。
我有这样的User
-班:
[DataContract]
[Table(Name = "User")]
public class User
{
private int _id;
public User()
{
}
public User(int id)
{
Id = id;
}
[Column(Name = "ID", IsPrimaryKey = true, Storage = "_id")]
[DataMember]
public int Id
{
get => _id;
protected set => _id = value;
}
[Column(Name = "Uname")]
[DataMember] public string Uname { get; set; }
[Column(Name = "Pword")]
[DataMember] public string Pword { get; set; }
}
还有一个User
-Manager类,其中包含以下方法。
该方法将给定的用户名和密码与用户表的内容进行比较。
public async Task<User> GetModelAsync(string username, string password)
{
//For debug
var users = await _userRepo.GetModelsAsync();
//for debug
foreach (var u in users)
{
//The second time this gets executed, the password is null
_logger.Log($"found: {u.Uname} - {u.Pword}");
}
//here, the exception gets thrown.
var result =
(from m in users
where m.Uname.Equals(username, StringComparison.InvariantCulture)
&& m.Pword.Equals(password, StringComparison.InvariantCulture)
select m).ToList();
//... goes on
}
因此,执行此操作时发生了什么。 第一次执行(工作正常):
public async Task<User> GetModelAsync(string username, string password)
被呼叫。
_userRepo.GetModelsAsync()
被调用。
此方法调用public static async Task<IList<T>> GetModelsAsync<T>(string query, params DbParameter[] parameters)
方法。
如您所见,在此方法中,models = ReadModels<T>(dr);
被调用,该方法执行return Dc.Translate<T>(dr).ToList();
执行用户名/密码检查
返回找到的User
对象或null。
第二次执行时,我的LINQ
语句中出现一个异常,您可以在下面的编辑中看到该异常,其中比较了用户名和密码:
上面发布的所有代码都在WCF
-环境中执行。
此服务在WPF
-应用程序中使用。
我的“第一次”执行是发布我的WCF
服务或等待几分钟(例如5分钟)之后的执行。然后启动我的WPF
应用程序,并通过HttpClient
发送请求。我现在尝试登录,这就是为什么要在服务端代码中比较用户名和密码的原因。
“第二次”执行是当我关闭我的WPF
应用程序并重新启动它时,无需等待几分钟,也无需再次发布我的服务。只是重新启动我的应用程序。
我传递给服务的参数正确且完整地到达了它。我通过一些日志知道。
我真的不知道这是怎么回事。 我在网上找不到类似的东西。 也许有些人可以告诉我,为什么我的“第二次”执行失败?为什么将此特定字段设置为null?
列Pword
是我的VARCHAR
数据库上的MSSQL
类型。
仅供参考:尽管Pword
列/字段是字符串,但不是明文。
编辑:
在WCF环境中收到的消息和堆栈跟踪:
消息:
对象引用未设置为对象实例
Stacktrace:
在MediaPlayer3.Logic.ServerManagement.UserManager中。<> c__DisplayClass6_0.b__0(用户m)在D:\ TFS2018 \ MediaPlayer3 \ MediaPlayer3.Logic.ServerManagement \ UserManager.cs:第67行中。 位于System.Linq.Enumerable.WhereListIterator
1.MoveNext() at System.Collections.Generic.List
1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable
1源)处 在D:\ TFS2018 \ MediaPlayer3 \ MediaPlayer3.Logic.ServerManagement \ UserManager.cs:Line 65中的MediaPlayer3.Logic.ServerManagement.UserManager.d__6.MoveNext()中。
编辑:
GetCommand()
internal SqlCommand GetCommand(string query, CommandType commandType = CommandType.Text, params DbParameter[] parameters)
{
var command = new SqlCommand(query);
if (parameters != null)
command.Parameters.AddRange(parameters);
command.CommandType = commandType;
return command;
}
编辑24.09.2018:
这与如何解决NullReferenceException
或事实有关,我不知道我在这里有这个。
这是关于为什么我遇到这个异常。
我发送到数据库的查询始终是相同的,因为我在服务器端代码中将where
用LINQ
进行了处理。我只是执行SELECT * FROM ...
。
我将尝试注释中提到的@usr。 然后我将发布我的command.CommandText。因为没有参数,所以我不需要发布参数。
为什么我对此文章持反对态度?
编辑25.09.2018
我们正在接近实际发生的情况。
我现在很确定,我没有发布代码的一部分,这就是我遇到问题的原因。
当我在User
中找到LINQ
时,下一步是在序列化之前清除Pword
并将其发送回客户端,因为我从不希望{{ 1}}字段在我的客户端代码上。该字段仅用于将Pword
发送到服务,而不是相反。
我现在正在考虑的是,我的服务将Pword
和清除的IList<User>
保留在内存中,并在不执行新的SQL查询的情况下下次使用它。
这是完整的方法:
Pword
那又如何呢?你们有什么感想?也许这使一些事情很清楚。我的public async Task<User> GetModelAsync(string username, string password)
{
var result =
(from m in await _userRepo.GetModelsAsync()
where m.Uname.Equals(username, StringComparison.InvariantCulture)
&& m.Pword.Equals(password, StringComparison.InvariantCulture)
select m).ToList();
if (result.Any() && result.Count == 1)
{
var user = result.First();
user.Pword = null;
return user;
}
return null;
}
服务是否将此WCF
保留在内存中以再次使用?请记住,只是List<User>
无效,重新启动服务后第二次调用此方法。
没有执行任何逻辑,以使列表在执行一次后便在内存中保持显式。 Pword
正在执行一个sql查询,第一个代码示例。
答案 0 :(得分:0)
我现在在想的是,我的服务将我的IList和清除的Pword保留在内存中,并下次使用它而不执行新的SQL查询。
LINQ to SQL(和EF)重复使用主键上键入的相同实体对象。这是非常重要的功能。
Translate
将为您提供预先存在的对象,如果您使用它来查询实体类型。您可以通过使用DTO类型(例如class UserDTO { public string UserName; }
)进行查询来避免这种情况。
最佳做法是将实体对象视为数据库的同步镜像。请勿对其进行临时编辑。
请确保您的DataContext
具有正确的范围。通常,每个HTTP请求需要一个上下文。一个请求中的所有代码应共享一个上下文,并且任何请求之间都不应共享上下文。
所以也许有两个问题:您修改实体,并在请求中重用DataContext
。