将表与集合 EntityFramework 连接起来

2023-11-21

也许它是重复的,但我找不到正确的方法来正确执行以下操作。

一般来说,我想从 Employee 表中检索与 List 相关的所有数据。 MyEmployee 类型包含 EntitySourceID,我用它来与 EmployeeID 进行映射。因此,我想检索列表集合中 EmployeeID 与 EntitySourceID 匹配的所有员工。

MyEmployee 类型如下所示:

public class MyEmployee 
    {
        public long PersonID { get; set; }
        public string ConnectionString { get; set; }
        public long EntitySourceID { get; set; }
        public int EntitySourceTypeID { get; set; }
    }

我的查询如下所示:

internal IEnumerable<Person> GetPersons(List<MyEmployee> myEmployees)
    {
            return (from p in _context.Employee
                join pList in myEmployees on p.EmployeeID equals pList.EntitySourceID
                select new Person 
                {
                    PersonID = pList.PersonID,
                    FirstName = p.FirstName,
                    LastName = p.LastName,
                    Name = p.Name,
                    Suffix = p.Suffix,
                    Title = p.Title
                }).ToList();
    }

您可以在查询中看到,当我创建新的 Person 对象时,我使用 List myEmployees 集合中的 pList.PersonID 来填充 Person 的。

所以,我的问题是如何有效地从 Employee 表中检索与 List 集合匹配的数据,并使用 pList.PersonID (来自集合)来创建返回结果?

我使用 EF 6,数据库优先方法。

另外,我没有提到。此查询产生以下异常: 无法创建“MyEmployee”类型的常量值。此上下文中仅支持基本类型或枚举类型。


IQueryable 与 IEnumerable

解决一些更深层次问题的一个好的开始是花一些时间发现之间的差异

  • IQueryable andIEnumerable<T>

也许也在之间

  • “常规代表”,例如Func<T>和“表达式”,例如Expression<T>

因为虽然它们具有相似的形式,但它们的目的和行为不同。

现在回到你的问题

首先,让我们举几件事:

  • 我们将 RAM 托管集合称为MyEmployee实例THE LIST
  • 让我们调用数据库表(最有可能的标题是“Employee(s)”)桌子

遗憾的是,您在撰写问题时没有指定一些非常重要的细节。 这导致我提出 4 个不同的答案。 答案将根据以下 2 个问题的真值进行分类:

  • Is THE LIST huge?
  • Is 桌子 huge?

我们有 4 个截然不同的案例:

  1. No, No
  2. No, Yes
  3. Yes, No
  4. Yes, Yes

现在你可以想象第四个可能是最丑的。

当列表不是很大时

对于情况 1 和 2,您可以从不同的角度思考您的问题:

假设你需要获取ONE(或零)来自数据库的记录基于正是 1参数是一个ID。如果您要表演JOIN?

答案是:绝对NOT。 看一下这段代码:

var query = from employee in _context.Employee
            where employee.EmployeeId == 23
            select employee;
var found = query.FirstOrDefault();

如果我想获取与以下内容关联的记录怎么办正是 2参数? 我可以用类似的方式实现这一点:

var query = from employee in _context.Employee
            where employee.EmployeeId == 23 || employee.EmployeeId == 24
            select employee;
var results = query.ToArray();

if (results.Length == 0)
   // didn't find anyone of the presumably existing records

else if (results.Length == 1) {
   if (results[0].EmployeeId == 23)
      // then we found the 23
   else
      // the other one

} else if (results.Length == 2)
   // found both, look inside to see which is which

我特意写了算法的收尾工作(if部分)以一种愚蠢的方式,以避免额外的混乱。

这将是一种更人性化的收尾方式:

...
var results = ... got them (see above)

var map = results.ToDictionary(keySelector: x => x.EmployeeId);
var count = map.Count; // this gives you the number of results, same as results.Length
var have23 = map.ContainsKey(23); // this tells you whether you managed to fetch a certain id
var record23 = map[23]; // this actually gives you the record
foreach (var key in map.Keys) { .. } // will iterate over the fetched ids
foreach (var record in map.Values) { .. } // will iterate over the fetched values

不用担心ToDictionary扩展方法。 它有NOTHING与 EntityFramework 相关(通过单击进行查找)。

现在..回到我们的故事:如果您想获取与 15 个 id 关联的记录怎么办? 停止。这是要去哪里?我是否要求您为每个可能的 id 数量硬编码一个不同的查询?

当然不是。 只要 id 的数量“相对较小”(意味着某人或您自己允许您以该请求大小轰炸数据库),您就可以很好地使用“参数列表中的列”SQL 构造。

如何指示 LINQ to SQL 或 EF 在 SQL 端转换为“x IN y”操作而不是“x = y”操作?

通过使用相应类型的原始数组和Contains方法。 换句话说,获得以下负载:

var query = from employee in _context.Employee
            where listOfIds.Contains( employee.EmployeeId )
            select employee;
var results = query.ToArray();

但是您需要一个“Id 列表”而不是“MyEmployee 实例列表”。 你可以很容易地做到这一点,如下所示:

List<MyEmployee> originalList = new List<MyEmployee>();
// ... say you populate this somehow, or you've received it from elsewhere

int[] listOfIds = (from employee in originalList
                   select employee.EntityId).ToArray();

// .. and then carry on with the EF query

请注意对集合的查询表现为IEnumerable<T>实例,而不是作为IQueryable<T>实例,与 EF 或 LINQ to SQL 或任何其他数据库或外部数据服务无关。

如果桌子不是很大

然后,您可以避免实际使用 EF 进行复杂查询,仅将其用于“全表获取”,将结果临时存储在 .NET 进程中,并根据您的喜好使用常规 LINQ。

这个故事的关键是从头开始获取整个表。 在你的问题中你写道:

return (from p in _context.Employee
            join pList in myEmployees on p.EmployeeID equals pList.EntitySourceID
            select new Person 
            {
                PersonID = pList.PersonID,
                FirstName = p.FirstName
                ... etc

只需用以下方法来增强它:

var entityList = _context.Employee.ToArray();

return (from p in entityList  // PLEASE NOTE THIS CHANGE ALSO
        join pList in myEmployees on p.EmployeeID equals pList.EntitySourceID
        select ...

总结一下

您可以:

  • 指示数据库完成工作,但在这种情况下,您无法在此过程中向其发送精美的 .NET 实例
  • 自己在楼上用 .NET 完成这项工作

一侧或另一侧(数据库或 .NET 进程)需要拥有所有卡(需要具有另一侧的克隆)才能执行JOIN.

所以这只是一个妥协的游戏。

剩下的情况怎么样

If both 桌子 and THE LIST太大了,那你就完蛋了。 不——我只是开玩笑。

没有人听说有人要求别人创造奇迹,而实际上却无法做到。

If this既然如此,那么你就得把问题简化成大量更小的问题。 我建议转变为桌子很大 + 清单不是那么大问题乘以N。

那么你该怎么做呢?

List<MyEmployee> original = ...
// you take your list
// and you split it in sections of .. say 50 (which in my book is not huge for a database
// although be careful - the pressure on the database will be almost that of 50 selects running in parallel for each select)

// how do you split it?
// you could try this

public static IEnumerable<List<MyEmployee>> Split(List<MyEmployee> source, int sectionLength) {
    List<MyEmployee> buffer = new List<MyEmployee>();
    foreach (var employee in source) {
        buffer.Add(employee);
        if (buffer.Count == sectionLength) {
            yield return buffer.ToList(); // MAKE SURE YOU .ToList() the buffer in order to clone it
            buffer.Clear(); // or otherwise all resulting sections will actually point to the same instance which gets cleared and refilled over and over again
        }             
    }
    if (buffer.Count > 0)   // and if you have a remainder you need that too
       yield return buffer; // except for the last time when you don't really need to clone it
}

List<List<MyEmployee>> sections = Split(original, 50).ToList();

// and now you can use the sections
// as if you're in CASE 2 (the list is not huge but the table is)
// inside a foreach loop

List<Person> results = new List<Person>(); // prepare to accumulate results

foreach (var section in sections) {

    int[] ids = (from x in section select x.EntityID).ToArray();

    var query = from employee in _context.Employee
                where ids.Contains(employee.EmployeeId) 
                ... etc;

    var currentBatch = query.ToArray();

    results.AddRange(currentBatch);

}

现在你可以说,这只是欺骗数据库的一种方式,让它相信它几乎没有什么工作可做,而实际上我们仍然在向它注入大量工作,并且maybe让其他并发客户端的生活变得困难。

嗯-是的,但至少你可以放慢速度。 你可以Thread.Sleep各部分之间...你可以使用iterators(查找它们),实际上并不是用需要很长时间才能处理的记录淹没 RAM,而是“流式传输”。

你对局势有更多的控制权。

祝你好运!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将表与集合 EntityFramework 连接起来 的相关文章

  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • C# 异步等待澄清?

    我读了here http blog stephencleary com 2012 02 async and await html that 等待检查等待的看看它是否有already完全的 如果 可等待已经完成 那么该方法将继续 运行 同步
  • 根据属性的类型使用文本框或复选框

    如果我有这样的结构 public class Parent public string Name get set public List
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 如何定义一个可结构化绑定的对象的概念?

    我想定义一个concept可以检测类型是否T can be 结构化绑定 or not template
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 为什么使用小于 32 位的整数?

    我总是喜欢使用最小尺寸的变量 这样效果就很好 但是如果我使用短字节整数而不是整数 并且内存是 32 位字可寻址 这真的会给我带来好处吗 编译器是否会做一些事情来增强内存使用 对于局部变量 它可能没有多大意义 但是在具有数千甚至数百万项的结构
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat

随机推荐