从具有LINQ语句/表达式

时间:2017-08-09 09:23:59

标签: c# entity-framework linq

我是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是一个包含对数据库实例的引用的字段。

在select user方法中,我理解有一个cp_user类型的局部变量的创建,它由语句定义:

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

  2. 我完全理解语句的其余部分,方法中的用户名和密码参数必须等于表中的数据。并且它将返回数据库对象。但是再次混淆了你,在最后一部分说“选择你”。

  3. 我的另一个问题是另一个名为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语法,如果是这样的话是什么意思?有人有解释这个的链接吗?
    2. 我很抱歉,如果我做了任何错误的陈述,请纠正我,如果我刚接触编程,一般只用过MySQL。如果有人能回答我的3个问题,我将不胜感激。

      提前致谢

3 个答案:

答案 0 :(得分:0)

  1. u中的from u in _db.cp_user是对列表中与条件匹配的每个项目的引用(即u.username == user && u.password == passw)。

  2. select u返回匹配项。

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

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

答案 1 :(得分:0)

你提到的“你”只是一个临时变量,表示你的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且密码等于密码的用户。

从剩下的集合中取第一个元素,如果没有第一个元素,则返回null(更确切地说:返回默认值(User),对于类为null)。

我从C#world进入SQL世界,我发现方法语法更具可读性。如果将集合命名为复数并将集合中的每个元素命名为单数,则会有所帮助。标识符太短会减少打字时间,但通过输入较短的名称来增加理解时间远远超过保存时间

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

从cp_User中的用户集合中,仅使用userName等于userName且密码等于passWord的用户。从剩余的集合中获取第一个元素,如果集合为空,则返回null。

如果您想要所选用户的所有属性,则无需执行选择。但是,如果您只想要一些属性,则需要使用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集合中的每个用户,只需使用userName等于“U1”且密码等于“P1”的用户。返回剩余的集合是否为空。

很容易看出myUsers中的第一个元素与Where匹配,因此其余的集合不为空。

结果是真的;

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

myUsers中没有元素匹配Where。其余的集合是空的。结果是错误的。

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

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

请参阅:Extension methods demystified

答案 2 :(得分:0)

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 =&gt; u.username == user&amp;&amp; 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;
}

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

我希望你现在已经说服并有足够的动力来学习更多关于lambdas的知识。