【问题标题】:Selecting User from a table with LINQ statements/expression使用 LINQ 语句/表达式从表中选择用户
【发布时间】:2017-08-09 09:23:59
【问题描述】:

我是 C#、Entity Framework 和 LINW 的新手,希望有人可以在代码中解释一些关于 LINQ 的内容。我的程序中有一个从表中选择用户的方法。那个方法是:

 public static cp_user SelectUser(string user, string passw)
    {
        try
        {
            cp_user entityUser = (from u in _db.cp_user
                                  where u.username == user && u.password == passw
                                  select u).FirstOrDefault();

            return entityUser;
        }
        catch (System.Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

        return null;
    }

cp_user 是与我的数据库中的表对应的类。 _db 是一个包含对数据库实例的引用的字段。

在选择用户方法中,我知道创建了 cp_user 类型的局部变量,它由以下语句定义:

 (from u in _db.cp_user
                              where u.username == user && u.password == passw
                              select u).FirstOrDefault();
  1. 我对声明的第一部分感到困惑。 “来自 _dp.cp_user 中的你”。 到目前为止,我一直在使用 MySQL,所以看到这个“来自 u”令人困惑。在 MySQL 中,这个“u”指的是一个表。但在 Linq 中,我对它的作用感到困惑。

  2. 我确实大致理解了语句的其余部分,方法中的用户名和密码参数必须等于表中的数据。并且它将返回数据库对象。但再次对 u 感到困惑,在最后一部分说“选择 u”。

我的另一个问题是另一种称为 checkany 的方法,它检查用户登录是否正确:

 public static bool CheckAny(string user, string passw)
    {
        bool itIsAlredy = _db.cp_user.Any(u => u.username == user && u.password == passw);
        return itIsAlredy;
    }

我了解 CheckAny 方法采用用户名和密码并创建一个布尔变量,该变量可以根据语句返回 true 或 false。这是我不明白的部分。

  1. 对我来说这个语句“(u => u.username == user && u.password == passw);”看起来这意味着方法参数中的用户名和密码必须存在于数据库中。但是学校有人告诉我,这意味着用户名和密码必须正确对应;你不能有一个连接到另一个用户名的密码。那么这个声明实际上说的是什么。而且我也不明白整个“u => u.username”。比如这个你代表什么。如果是,它是特殊的 linq 语法是什么意思?任何人都有解释这一点的链接?

非常抱歉,如果我有任何错误的陈述,请纠正我,如果我是编程新手,通常只使用 MySQL。如果有人能回答我的 3 个问题,将不胜感激。

提前致谢

【问题讨论】:

  • 一般来说,您需要开始使用 Linq to SQL 或 Linq to Anything。这是太基本的东西,无法在这里解释。
  • @niksofteng 好的,非常感谢你,在提出另一个这样的问题之前,我会记住这一点。问候

标签: c# entity-framework linq


【解决方案1】:

您提到的“u”只是一个临时变量,代表您的 cp_user 集合中的一个元素。事实上它说:

for each u in the collection of elements in cp_user do ...

Linq 有两种语法形式:query syntax and method syntax。你的陈述是两者的结合。方法语法具有更多功能,正如您在仅存在于方法语法中的函数 FirstOrDefault 中看到的那样。

如果将语句分成两个语句,您将看到包含查询语法的部分和包含方法语法的部分。

顺便说一句,多年来我发现正确的变量命名可以大大提高可读性。

(假设 cp_user 是一个 DbSet)

IQueryable<User> myUsers = from user in db.cp_user
    where user.username == userName && user.password == password
   select user;
User myUser = myUsers.FirstOrDefault();

换句话说:从 cpUser 集合中的所有用户中,只取那些 UserName 等于 userName 并且 Password 等于 password 的用户。

从剩余的集合中取出第一个元素,如果没有第一个元素,则返回 null(更准确地说:返回 default(User),对于类而言为 null)。

我从 C# 世界进入 SQL 世界,发现方法语法更具可读性。如果您将集合命名为复数并将集合中的每个元素命名为单数,这会有所帮助。标识符太短会减少输入时间,但会增加理解时间,而不是输入较短的名称所节省的时间

User user = db.cp_users
    .Where(user => user.userName == userName && user.password == password)
    .FirstOrDefault();

从cp_User的用户集合中,只取userName等于userName、password等于passWord的用户。从剩余的集合中取出第一个元素,如果集合为空,则为 null。

如果您想要所选用户的所有属性,则无需执行 Select。但是,如果您只需要某些属性,则需要使用 Select 进行“投影”

db.cp_users
    .Where(user => user.userName == userName && user.password == password)
    .Select(use0r => new
    {
        Id = user.Id,
        Name = user.userName,
    })
    .FirstOrDefault();
  • 对于集合 cp_users 中的所有用户,只取 userName 等于 userName 且 password 等于 password 的用户。
  • 为结果集合中的每个用户创建一个具有两个属性的新匿名类型的对象:
    • Id 应该是 user.Id 的值
    • 名称应具有 user.UserName 的值
  • 从剩余的匿名类型集合中,只取第一个元素,如果集合为空,则取 null。

任何()

Enumerable.Any 有两个版本,一个带参数,一个不带参数。

带参数的那个:

bool result = _db.cp_user.Any(user => user.username == userName && user.password == password);

等价于:

bool result = _db.cp_users
    .Where(user => user.username == userName && user.password == password)
    .Any();

言辞:

对于 cp_users 中的所有用户,只取那些 userName 等于 userName 并且 password 等于 password 的用户。如果集合中至少有一个元素,则返回 true,如果集合为空,则返回 false。

Any 比 Count() != 0 快,因为 Any 会在找到一个元素后立即停止,而 Count() 必须在将结果与 0 进行比较之前枚举整个集合。

你写道:

貌似是说方法参数中的用户名和密码必须存在于数据库中。但是学校有人告诉我,这意味着用户名和密码必须正确对应;你不能有一个连接到另一个用户名的密码。

假设您有一个包含两个用户的集合:

ICollection<User> myUsers = new User[]
{
     new User{ Name = "U1", Password = "P1"},
     new User{ Name = "U2", Password = "P2"},
};

很容易看出有一个用户名为“U1”,密码为“P1”,但没有用户名为“U1”,密码为“P2”。

bool result = myUsers
    .Where(user => user.username == "U1" && user.password == "P1")
    .Any();

换句话说:对于 myUsers 集合中的每个用户,只取用户名等于“U1”且密码等于“P1”的用户。返回剩余集合是否不为空。

很容易看出myUsers中的第一个元素与Where匹配,所以剩下的集合不为空。

结果为真;

bool result = myUsers
    .Where(user => user.username == "U1" && user.password == "P2")
    .Any();

myUsers 中没有任何元素与 Where 匹配。剩余的集合是空的。结果是假的。

您会发现使用正确的变量名称可以大大提高可读性。而不是“u”写“用户”,该语句几乎是正常的语言。

如果您打算大量使用 linq,请考虑使用方法语法而不是查询语法。方法语法比查询语法有更多的功能。方法语法是更基本的 C#。使用方法语法,您还可以添加自己的类似 LINQ 的函数。因此,如果您将大量使用 Linq,请考虑学习 Method 语法。

见:Extension methods demystified

【讨论】:

    【解决方案2】:
    1. from u in _db.cp_user 中的u 是对列表中与条件匹配的每个项目的引用(即u.username == user &amp;&amp; u.password == passw)。

    2. select u 返回匹配项。

    3. 仅当数据库中存在用户名和密码都与提供的参数匹配的条目时,该语句才会返回 true。

    这里是开始学习 LINQ 的好地方:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/getting-started-with-linq

    【讨论】:

    • 非常感谢我马上开始!
    【解决方案3】:
    from u in _db.cp_user
    where u.username == user && u.password == passw
    select u
    

    LINQ 有自己的语法,就像任何其他东西一样,您最终必须学习并习惯它。不要混淆 SQL 和 LINQ 查询语法。此查询中的u 是一个范围变量。您可以将u 视为我们在应用where 子句的SQL 查询中使用的表别名。请注意,我这样说只是为了让您更容易理解。这并不意味着上述代码在转换为等效 SQL 时实际上使用 u 作为别名。

    _db.cp_user.Any(u => u.username == user && u.password == passw)

    Any 函数内部的代码是 lambda 表达式。你也需要了解它们。它们很漂亮,可以像任何东西一样减少你的代码。见下文

    Any是一个扩展方法,定义为:

    static bool Any<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
        foreach (T element in source) {
            if (predicate(element)) {
                return true;
            }
        }
        return false;
    }
    

    这里的predicate参数是代表一个方法的委托,该方法代表一个接受T类型的输入参数并返回bool的方法。因此,如果您想编写没有 lambda 表达式的相同代码,则必须定义这样的方法

    private bool CheckUser(cp_user user, string user, string passw) {
        if (user.username == user && cp_user.password == passw) {
            return true;
        }
        return false;
    }
    

    并使用此方法作为谓词过滤掉无效用户。这是很多不必要的工作。

    我希望你现在有足够的信心和动力去学习更多关于 lambda 的知识。

    【讨论】:

      猜你喜欢
      • 2022-06-11
      • 1970-01-01
      • 2014-06-16
      • 2021-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-22
      • 1970-01-01
      相关资源
      最近更新 更多