【问题标题】:Getting specific columns from an INCLUDE statement with EF使用 EF 从 INCLUDE 语句中获取特定列
【发布时间】:2015-04-06 02:42:08
【问题描述】:

在使用 INCLUDE 语句时,我只想从 EF 中的查询中获取特定列,而不是带回所有列。

此外,如果我还想从我的客户对象中带回更短的结果集怎么办。

有没有办法做到这一点?

这是我的查询:

void Main()
{
    IEnumerable<Customer> customerProjectsList = GetCustomerProjects();
    customerProjectsList.Dump();
}

public List<Customer> GetCustomerProjects()
        {
            try
            {
                using (YeagerTech DbContext = new YeagerTech())
                {
                    var customer = DbContext.Customers.Include("Projects");

                    return customer;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

编辑

我一直在尝试使用以下查询,但收到“无法将类型 'System.Linq.IQueryable' 隐式转换为 'System.Collections.Generic.ICollection' 的错误。存在显式转换(您是否缺少演员表?)”

这是查询: 无效的主要() { 列出 customerProjectsList = GetCustomerProjects(); customerProjectsList.Dump(); }

public List<CustomerDTO> GetCustomerProjects()
        {
            try
            {
                using (YeagerTech DbContext = new YeagerTech())
                {
                    var customerlist = DbContext.Customers.Select(s =>
                        new CustomerDTO()
                        {
                            CustomerID = s.CustomerID,
                            Projects =
                                from p in Projects
                                where p.CustomerID == s.CustomerID && p.Quote != null
                                select new Project { Description = p.Description, Quote = p.Quote }
                        }).ToList<Project>();

                    return customerlist.ToList();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

如果我在 LINQPad 中将同样的查询作为 C# 语句而不是 C# 程序运行,则查询结果会很好地生成。

我只是想通过这种简单的方法来尝试获取带有特定列的层次结构列表。

var result = (from c in Customers
select new
{
    c.CustomerID,
    Projects =
        from p in Projects
        where p.CustomerID == c.CustomerID && p.Quote != null
        select new { p.Description, p.Quote }
});
result.Dump();

【问题讨论】:

  • 你可以使用投影来做到这一点
  • 替换 ToList();与 ToList();
  • Phillip,恕我直言,必须有一个非常简单的解释,为什么我能够以 C# 语句的形式执行查询,但不能以 C# 程序的形式执行。
  • Philip,我已经用 ToList() 走了那条路,并且遇到了同样的错误.....
  • 完全删除 ToList(),最后应该只有一个。您有 2。顺便说一句,您现在已将问题更改为完全不同的问题。您应该从一开始就提供此详细信息或创建一个新问题。您使用 ToList 的那一刻,它就变成了一个普通的 linq 查询,它不再是 IQueryable 了。因此出现错误。

标签: c# linq entity-framework


【解决方案1】:

您不一定需要包含;如果您在 CustomersProjects 之间有导航属性,则可以投影到新对象:

  var customers = (from c in DbContext.Customers
                   select new
                   {
                       FirstName = c.FirstName,
                       ProjectName = c.Project.Name

                   }).ToList().Select(x => new Customer
                   {
                       FirstName = x.FirstName,
                       Project = new Project()
                       {
                           Name = x.ProjectName
                       }
                   }).ToList();

这将返回一个Customers 列表,其中仅填充了名字,每个客户将包含一个填充了名称的Project 属性。这对性能很有好处,因为 EF 向您的数据库发送的查询会很短,并且会快速返回结果集。

编辑

考虑到ProjectsICollection,我认为最可维护的做法是创建一对DTOs

public CustomerDTO
{
     public int CustomerId;
     public List<ProjectDTO> projects;
}

public ProjectDTO
{
     public string Description;
     public string Quote;
}

然后像这样向他们投射:

var qry = (from c in context.Customers
                       select new CustomerDTO()
                       {
                           CustomerId = c.CustomerId,
                           Projects = (from pr in context.Projects
                                       where c.ProjectId equals pr.Id
                                       select new ProjectDTO
                                       { 
                                            Description = pr.Description,
                                            Quote = pr.Quote
                                       }).ToList()
                       });

【讨论】:

  • Circular,如果您在我的第一篇文章中查看我的 EDIT,您会注意到查询在 C# 语句中运行良好,但在带有 LINQPad 的 C# 程序中却没有。我所有的模型都设置正确。我将编辑您的帖子并向您展示我的模型。感谢您的帮助。
  • Circular,我想我明白了...当我能够发布我的编辑时,请查看它以获取有关恢复所有列的更多帮助。你会在我的编辑中看到我在说什么......
  • Circular,我敢打赌,我知道为什么会出现额外的列(即使它们没有填充)。这是因为我的模型中包含该类的所有属性!如果我只在模型中包含我想要的属性,那么只会返回那些!非常感谢您帮助我指出正确的方向。非常感谢。
【解决方案2】:

您必须使用投影来限制检索到的列。网上有很多投影的例子,一个简短的例子是这样的:

DateTime twoDaysAgo = DateTime.Now.AddDays(-2);
var groupSummaries = _recipeContext.Groups.OrderBy(g => g.Name)
    .Select(g => new GroupSummaryModel{
        Id = g.Id,
        Name = g.Name,
        Description = g.Description,
        NumberOfUsers = g.Users.Count(),
        NumberOfNewRecipes = g.Recipes.Count(r => r.PostedOn > twoDaysAgo)
    });

我从这里拿走了它: http://www.davepaquette.com/archive/2013/02/09/writing-efficient-queries-with-entity-framework-code-first-part-2.aspx

关键是如果需要多次使用新机制。在这里它与新的 GroupSummaryModel 一起使用。

编辑

var qry = (from c in context.Customers
                       select new CustomerDTO()
                       {
                           CustomerId = c.CustomerId,
                           Projects = (from pr in context.Projects
                                       where c.ProjectId equals pr.Id
                                       select new ProjectDTO
                                       { 
                                            Description = pr.Description,
                                            Quote = pr.Quote
                                       }) //--> no tolist here
                       }).ToList(); //--> only here

【讨论】:

  • 如果CustomerDTO 包含List&lt;ProjectDTO&gt;,则不会编译
  • hm,但应该避免使用 toList,否则会将 iqueryable 与普通 linq 混淆。您希望由服务器而不是客户端处理查询。
猜你喜欢
  • 2021-11-06
  • 1970-01-01
  • 2016-11-05
  • 1970-01-01
  • 1970-01-01
  • 2015-07-30
  • 2016-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多