1

我有三个简单的表——用户组、员工和称呼。都有 ID、Name/Desc 和 Active 列。用户组也被分配了一个可选的员工 ID,而员工被分配了一个非可选的称呼 ID。我希望查询这些表以返回所有活动用户组的完整列表,以及他们相关的工作人员(是任何),以及他们的相关称呼。

一个有效的 SQL 查询如下:

        SELECT grp.ID, grp.Desc, grp.Active, sub.Name, sub.Desc
        FROM Tbl_UserGroup AS grp
        LEFT JOIN (
            SELECT st.ID, st.Name, sal.Desc
            FROM PrmTbl_Staff AS st
            LEFT JOIN PrmTbl_Salutation AS sal ON st.SalutationID = sal.ID
            WHERE 1
        ) AS sub ON grp.StaffID = sub.ID
        WHERE grp.Active = TRUE
        ORDER BY grp.ID DESC 

我有一个 ViewModel 如下:

public class StaffUserGroup
{
    public int GroupID { get; set; }
    public string GroupDesc { get; set; }
    public bool GroupActive { get; set; }

    public int? StaffID { get; set; }
    public string StaffName { get; set; }

    public string SalutationName { get; set; }

    public List<PrmTbl_Staff> StaffsList { get; set; }

}

并尝试 LINQ 查询:

IEnumerable<Tbl_UserGroup> grpsQuery;

grpsQuery = from grp in db.Tbl_UserGroups
            join sub in(
                from st in db.PrmTbl_Staffs
                join sal in db.PrmTbl_Salutations on st.SalutationID equals sal.ID
                select new { StID = st.ID, st.Name, Salt = sal.Desc }
            ) on grp.StaffID equals sub.StID
            where grp.Active = true
            orderby grp.ID descending
            select new { grp.ID, grp.Desc, grp.Active, sub.Name, sub.Salt, sub.StID };

在我的控制器中加载:

        var viewModel = grpsQuery.Select(group =>
            new StaffUserGroup
            {
                GroupID = group.GroupID,
                GroupDesc = group.GroupDesc,
                GroupActive = group.GroupActive,

                StaffID = group.StaffID,
                StaffName = group.StaffName,

                SalutationName = group.SalutationName,

                StaffsList = rtrnStaff
            }
        );

请注意,智能感知在子查询和主查询之间标记了同名的列,因此我引入了一些别名。我还希望将所有可用员工的下拉列表传递给视图,因此视图模型中的列表。

我在 LINQ 语句中的 select 调用中遇到错误:Cannot implicitly convert type 'System.Linq.IQueryable<AnonymousType#4>' to '<...StaffUserGroup> An explicit conversion exists. Are you missing a cast?

我不知道

  • 当我可以直接向控制器查询我需要的数据时,为什么我需要一个 ViewModel
  • 然后 ViewModel 类实际上从查询中检索到的数据做了什么——它会过滤吗?从中构造一个对象?从我在 PHP 和 MySQL 的背景来看,有什么比较?
  • 如何从表中查询特定列。我使用select new {},因为我假设这是等效的?
  • 为什么上面的 LINQ 语句不起作用。

如果需要,我可以发布模型、视图或控制器。非常感谢任何帮助和建议!

4

2 回答 2

6

问题 1

当我可以直接向控制器查询我需要的数据时,为什么我需要一个 ViewModel

ViewModel 是您编写的POCO,它准确定义了视图需要什么才能正确显示自身。

例如,假设您有一个欢迎用户的页面(视图)。

欢迎,鲍勃。您上次访问是2013-10-11

ViewModel 是一个简单的类,它准确地定义了视图需要的东西。

  1. 用户名
  2. 用户的最后一次访问

所以:

public class UserDetailsViewModel
{
    public string FirstName { get; set; }
    public DateTime LastVisit { get; set; }
}

(通常)控制器负责创建 ViewModel,确保它被填充,将其提供给视图并最终返回视图。控制器没有做太多其他事情。它的职责是有限的,并且动作中的代码应该相当小。

你这样做的原因是因为它是一种很好的做法。但这还不够好,让我解释一下。

可以简单地运行查询,返回某个域对象的 IEnumerable(例如用户列表)并将其提供给视图。这是在许多 MVC 演示中完成的。问题是它非常有限/限制性。如果您想更改视图稍后显示的内容,会发生什么?如果域模型发生轻微变化会发生什么?当事物组织得井井有条并且关注点分开时,管理和更改事物会更容易。

问题2

然后 ViewModel 类实际上对从查询中检索到的数据做了什么——它会过滤吗?从中构造一个对象?从我在 PHP 和 MySQL 的背景来看,有什么比较?

ViewModel 是某些架构模式(例如MVCMVVM)的原生(或至少是通用的)概念。ViewModel 并没有真正“做”任何事情。它没有任何逻辑;它没有方法。它只包含一个属性(和属性)列表,这些属性定义了使用这个 ViewModel 的视图需要什么。

由于 ViewModel 不是特定于 .NET 的,因此没有完全对应的 PHP。它只是一个与 MVC、MVVM 等相关的概念。PHP 等效项是 PHP MVC ViewModel。请记住,ASP.NET MVC 只是 MVC 模式的一个实现。PHP 有自己的 MVC 实现。

问题 3

如何从表中查询特定列。我使用 select new {},因为我假设这是等效的?

这取决于你是怎么做的。EntityFramework是一个对象关系映射器,经常在 ASP.NET MVC 应用程序中使用。这样,您就不会直接查询底层存储或列。相反,EF 会将表和列映射到 .NET 对象并由您操作它们。

我建议您尝试继续处理对象,而不是随时创建匿名类型并尝试获取特定列。请记住LINQ 不是 SQL。方法不应该是“查询这个表,抓取这些列,where this 子句”,而应该是“从这组对象中,抓取这里的对象,这个子句”。

例如:

var query = from user in Users
            where user.FirstName == "Bob"
            select user;

问题 4

为什么上面的 LINQ 语句不起作用。

正如描述所说,您正在尝试为 StaffUserGroup 的 IEnumerable 提供匿名的 IEnumerable。我相信这是因为您选择事物以填充 ViewModel 的方式。如果不了解事物的结构,就很难修复代码。我的建议是去看看其他人是如何在 MVC 中做 LINQ/EntityFramework 的。只需进行一些练习,直到您对事物的工作方式感到满意为止。

于 2013-10-11T01:13:10.863 回答
0

看来您可能正在尝试放置新类型的项目

select new { grp.ID, grp.Desc, grp.Active, sub.Name, sub.Salt, sub.St }

进入用于类型项目的集合

IEnumerable<Tbl_UserGroup> grpsQuery;

于 2013-10-11T02:06:38.143 回答