【问题标题】:Entity Framework returning IQueryable of join of two tables实体框架返回两个表连接的 IQueryable
【发布时间】:2017-02-15 17:36:10
【问题描述】:

我想使用 Entity Framework 从 2 个表中返回数据,以及从 2 个表中选择的列,起初我对一些简单的事情不太幸运,比如返回 int 和字符串(即@987654321 @,因为在目的地(目的地是我的 winform)强制转换匿名类型很麻烦,所以我想到了只返回两个表行的想法......

所以是这样的:

  public static IQueryable<{Table1,Table2}> byRecID(Guid recID, MyContext DBContext)
  {
      return (from i1 in DBContext.Table1
             join j1 in DBContext.Table2 on i1.GroupID equals j1.GroupID
             where i1.RecID.Equals(RecID)
             select new { i1, j1 }).SingleOrDefault();
  }

这一切都很好,除了方法的返回类型不正确。我尝试了几种组合。不幸的是,当我从 winform 调用“byRecID”时,“SingleOrDefault”不可用,但在“byRecID”方法中可用,所以我不能只返回IQueryable,需要输入IQueryable&lt;SOMETHING IN HERE&gt;(因为@ 987654325@ 不是IQueryable 的扩展,只有IQueryable&lt;T&gt;)。

我的问题... 'SOMETHING IN HERE' 的语法是否可以让我指定它的两个表行的连接?

我想知道...为什么 SingleOrDefault 是方法内部的选项,而不是从我的 winform 调用时方法结果的选项?

基本上,我希望能够从我的 winforms 中调用干净的数据,而不是转换为可怕的匿名类型然后使用反射(比如当我返回匿名类型的原语时),但也不想仅仅为通过我的byRecID 方法使用。

【问题讨论】:

  • 你不能从方法中返回匿名类型。你需要一个具体的类型
  • 你可以,它们只是很难使用,这是我的观点,我想要一种将自己描述为其他两种类型的连接的类型。
  • 另外,你执行查询,所以结果不是某事的 IQueryable,它是某事
  • 抱歉@George,您的意思是匿名类型不能在方法签名中吗?因为我认为 untyped iqueryable 基本上是匿名类型的列表,略有不同。
  • 因为您可以做某事并不意味着您应该做。请记住,您只需编写一次,但您(更重要的是其他人)将阅读代码多年。我认为您应该选择最干净的设计,即结果的新模型类

标签: c# linq entity-framework-6


【解决方案1】:

在 c# 中,匿名类型最好在您投影它们的同一方法的范围内使用。正如您所见,它们不能在定义方法之外使用。所以你不能从方法中返回匿名类型(并保留它们的结构,你可以将它们作为对象返回,但这不是一个好主意),这会使你的方法的语法无效。 p>

最好的选择是将结果投影到根据您的需要指定的类。

public class TableJoinResult
{
   public Table1 Table1 { get; set; }
   public Table2 Table2 { get; set;}
}

您的查询:

 public static IQueryable<TableJoinResult> byRecID(Guid recID, MyContext DBContext)
  {
      return (from i1 in DBContext.Table1
             join j1 in DBContext.Table2 on i1.GroupID equals j1.GroupID
             where i1.RecID.Equals(RecID)
             select new TableJoinResult { Table1= i1, Table2 = j1 }).SingleOrDefault();
  }

更多关于匿名类型的信息:https://msdn.microsoft.com/en-us/library/bb397696.aspx

【讨论】:

  • Aaarggg,我正在从旧式 sql 使用转换,他们在代码中编写 sql,并且可以选择他们喜欢的任何字段。将不得不重新考虑我的方法。我试图通过制作可以编译为 sql 的 iqueryables 来保持性能,但是制作数百个这些“TableJoinResult”类型听起来并不干净或有趣,但是几个 linq 表达式更干净但性能不高(单个 linq 表达式让我们更好编译发生)
  • 是的,这不好玩,不幸的是,这是我认为的最佳选择。使用 Visual Studio 2017 附带的 c# 7(3 月 7 日),语言中有一个新概念(实际上更好的支持,因为语言中已经存在元组,但它们不是很有用)-> 解决这种情况的元组
【解决方案2】:

1)创建一个描述结果的特定类。

2)见 1

【讨论】:

    【解决方案3】:

    我想避免创建特定的类或结构。 下面是避免创建结构/类的冗长方法。 所以我在我的服务类中这样做了:-

     List<KeyValuePair<string,int>> IWorkflowService.GetServiceRetention()
            {
               var serviceRetention =  from y in _context.SERVICES
                         join z in _context.SERVICE_SETTINGS on y.ID equals z.SERVICEID
                         select new { Service= y.SERVICE, Retention=z.RETENTION };//new KeyValuePair<string,int?>( y.SERVICE, z.RETENTION ));
                var list = new List<KeyValuePair<string, int>>();
                foreach (var obj in serviceRetention)
                {
                    list.Add(new KeyValuePair<string, int>(obj.Service,Convert.ToInt32(obj.Retention)));
                }
                return list;
            }
    

    我必须在我的控制器类中这样做:

    List<KeyValuePair<string, int>> c = _service.GetServiceRetention();
    
                foreach (var obj in c)
                {
                     //The key contains service and value contains Rtention.
                      RecurringJob.AddOrUpdate(DELETE_SERVICE + obj.Key, () =>
                      Delete(obj.Key), //this is my function that does the actual process
                   Cron.DayInterval(Convert.ToInt32(obj.Value)));
                }
    

    我不确定这是否是最好的方法,但对我有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-01
      相关资源
      最近更新 更多