DataContext.Translate <t>在第二次执行时返回空列/字段

时间:2018-09-22 12:00:28

标签: c# .net linq wcf

我有多种通用方法可以从数据库表中读取模型/实体。 一种重要的方法如下:

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
}

因此,执行此操作时发生了什么。 第一次执行(工作正常):

  1. public async Task<User> GetModelAsync(string username, string password)被呼叫。

  2. _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();

  3. 执行用户名/密码检查

  4. 返回找到的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(IEnumerable 1 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或事实有关,我不知道我在这里有这个。 这是关于为什么我遇到这个异常。

我发送到数据库的查询始终是相同的,因为我在服务器端代码中将whereLINQ进行了处理。我只是执行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查询,第一个代码示例。

1 个答案:

答案 0 :(得分:0)

  

我现在在想的是,我的服务将我的IList和清除的Pword保留在内存中,并下次使用它而不执行新的SQL查询。

LINQ to SQL(和EF)重复使用主键上键入的相同实体对象。这是非常重要的功能。

Translate将为您提供预先存在的对象,如果您使用它来查询实体类型。您可以通过使用DTO类型(例如class UserDTO { public string UserName; })进行查询来避免这种情况。

最佳做法是将实体对象视为数据库的同步镜像。请勿对其进行临时编辑。

请确保您的DataContext具有正确的范围。通常,每个HTTP请求需要一个上下文。一个请求中的所有代码应共享一个上下文,并且任何请求之间都不应共享上下文。

所以也许有两个问题:您修改实体,并在请求中重用DataContext