gpt4 book ai didi

c# - 用集合EntityFramework连接表

转载 作者:太空狗 更新时间:2023-10-29 22:12:02 24 4
gpt4 key购买 nike

也许是重复的,但我找不到正确遵循以下方法的正确方法。

通常,我想从Employee表中检索与List相关的所有数据。类型MyEmployee包含用于与EmployeeID映射的EntitySourceID。因此,我想检索在列表集合中具有匹配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的对象。

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

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

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

最佳答案

IQueryable与IEnumerable
解决您的一些更深层次的问题的一个好的开始将是花一些时间来发现两者之间的差异。

  • IQueryable IEnumerable<T>

  • 也许也在
  • “常规代表”(例如 Func<T> )和“表达式”(例如 Expression<T> )

  • 因为尽管它们具有相似的形式,但它们的目的和行为却有所不同。
    现在回到您的问题
    首先,让我们列举一些事情:
  • 我们将RAM托管的MyEmployee实例集合称为 THE LIST
  • 让我们叫数据库表(最有可能叫做“Employee(s)”) THE TABLE

  • 遗憾的是,您在编写问题时没有指定一些非常重要的细节。
    这使我提出了4个不同的答案。
    答案将基于以下两个问题的真实值进行分类:
  • THE LIST 很大吗?
  • 表格很大吗?

  • 我们有4种非常不同的情况:
  • 不,不
  • 否,是
  • 是,否
  • 是,是

  • 您现在可以想象到,第四个也许是最丑陋的。
    当 list 不大时
    在情况1和2中,您可以从不同的角度考虑问题:
    假设您需要根据作为ID的精确1参数从数据库中获取一条(或零条)记录。您应该执行JOIN吗?
    答案是:绝对不会。
    看一下这段代码:
    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 扩展方法。
    它与EntityFramework无关(单击以查找它)。
    现在,回到我们的故事:如果您想带与15个ID相关的记录怎么办?
    停止。这要去哪里我是否要求您为每个可能的ID数对一个不同的查询进行硬编码?
    当然不是。
    只要id的数量“相对较小”(意味着您被某人允许,或者您自己就可以使用该请求大小轰炸数据库),则可以很好地使用“列IN参数列表” SQL构造。
    在SQL方面,如何指示LINQ to SQL或EF转换为“x IN y”操作而不是“x = y”操作?
    通过使用相应类型的原始数组和 Contains方法。
    换句话说,获得以下负载:
    var query = from employee in _context.Employee
    where listOfIds.Contains( employee.EmployeeId )
    select employee;
    var results = query.ToArray();
    但是您需要一个“Ids列表”,而不是一个“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。
    因此,这只是一个折衷的游戏。
    关于剩余案例的方式
    如果THE TABLE和THE LIST都很大,那么您会感到很震惊。
    不,我只是在开玩笑。
    没有人听说有人要求别人做奇迹,而实际上他们做不到。
    如果是这种情况,则必须将问题简化为大量较小的问题。
    我建议将其转换为TABLE HUGE + LIST NOT SO SOGE HUGE乘以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);

    }
    现在您可以说,这只是一种欺骗数据库而认为数据库几乎没有工作的方法,而实际上我们仍在进行大量工作,这可能会使其他并发客户端的工作变得更加艰辛。
    是的,但是至少您可以放慢脚步。
    您可以在各节之间使用 Thread.Sleep ...您可以使用 iterators(查找它们),而实际上不会向RAM填充记录,无论如何这些记录都将花费很长时间,而是“流式处理”。
    您可以更好地控制这种情况。
    祝你好运!

    关于c# - 用集合EntityFramework连接表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26068939/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com