在选择语句中具有列表的实体。

huangapple go评论66阅读模式
英文:

Entity with List in Select statement

问题

开始考虑以下可能不可行,由于逻辑中存在错误和缺乏支持证据,但想要确认。

我们使用 LINQ 构建实体 SQL 语句,但需要在 Select 语句中使用 List 收集额外的数据。这些数据来自应用程序内存中先前的实体集合。直接使用 Entity 进行相同操作时没有问题。

伪代码如下:

List<ParticipationStatus> lstStatuses = GetStatuses();

var data = (
    from user in dbContext.User
    where user.JoinDate >= *date*
    select new CustomObject 
    {
        Name = user.FullName,
        ParticipationStatus = lstStatuses
            .Where(m => m.ParticipationStatusID == user.ParticipationStatusID)
            .Select(x => x.Label)
            .FirstOrDefault() + " Some string here"
    } )
    .ToList();
英文:

Beginning to think the below is not possible due to errors and lack of supporting evidence in logic but wanted to confirm.

We're using LINQ to build an entity SQL statement but need to use a List in the Select statement to gather additional data. This data is from a previous Entity collection in app memory. Doing the same thing straight up with Entity works without issue.

The pseudo-code looks like:

List&lt;ParticipationStatus&gt; lstStatuses = GetStatuses();

var data = (
    from user in dbContext.User
	where user.JoinDate &gt;= *date*
	select new CustomObject 
	{
		Name = user.FullName,
		ParticipationStatus = lstStatuses
			.Where(m =&gt; m.ParticipationStatusID == user.ParticipationStatusID)
            .Select(x =&gt; x.Label)
			.FirstOrDefault() + &quot; Some string here&quot;
	} )
	.ToList();

Just wanted some confirmation of this possibility.

答案1

得分: 1

假设您已经设置了一个名为ParticipationStatus的导航属性,您只需要这样做:

var usersWithStatus = await dbContext.Users
    .Where(u => u.JoinDate >= someDateTime)
    .Select(u => new CustomObject
    {
        Name = u.FullName,
        ParticipationStatus = u.ParticipationStatus.Label + " 这里添加一些字符串"
    })
    .ToListAsync();

如果您真的想要重复使用您现有的List<ParticipationStatus> lstStatuses = GetStatuses();(我认为这是一个不好的主意,因为据我们所知,没有保证lstStatuses实际上包含每个User引用的每个ParticipationStatus,而且您的代码似乎没有使用事务来确保隔离或一致的读取),但您可以在加载用户后在内存中进行Join操作:

List<ParticipationStatus> lstStatuses = GetStatuses();

List<User> users = await dbContext.Users
    .Where(u => u.JoinDate >= someDateTime)
    .ToListAsync();

List<CustomObject> usersWithStatus = users
    .Join(
        inner: lstStatuses,
        outerKeySelector: u => u.ParticipationStatusID,
        innerKeySelector: s => s.ParticipationStatusID,
        resultSelector: (u, s) => new CustomObject
        {
            Name = u.FullName,
            ParticipationStatus = s.Label + " 这里添加一些字符串"
        }
    )
    .ToList();
  • Linq的Join是一个INNER JOIN操作(而不是其他类型的连接,比如FULL OUTER JOIN)。请注意,与SQL的INNER JOIN一样,innerouter中的多行可能匹配,这可能是不希望的。

    • 如果任何User实体与lstStatuses中的项目不匹配,那么该User将被静默排除在结果之外 - 而我认为这是_异常_,如果这是我的程序,我希望它抛出异常而不是静默排除它。
  • 在内部,.Join将通过使用临时哈希表高效地将UserParticipationStatus映射到线性时间O(n[u] + n

    展开收缩
    ),而您当前的代码需要二次时间:O(n[u] * n
    展开收缩
    )

英文:

Assuming you have a ParticipationStatus navigation-property set-up, all you need is this:

var usersWithStatus = await dbContext.Users
    .Where( u =&gt; u.JoinDate &gt;= someDateTime )
    .Select( u =&gt; new CustomObject
    {
        Name = u.FullName,
        ParticipationStatus = u.ParticipationStatus.Label + &quot; Some string here&quot;
    } )
    .ToListAsync();

If you really want to re-use your existing List&lt;ParticipationStatus&gt; lstStatuses = GetStatuses(); (which I think is a bad idea: because as far as we can see, there is no guarantee that lstStatuses actually contains every ParticipationStatus referneced by every User, and your code dopesn't appear to be using a transaction to ensure isolated or consistent reads), but you can do the Join in-memory after loading users:

List&lt;ParticipationStatus&gt; lstStatuses = GetStatuses();

List&lt;User&gt; users = await dbContext.Users
    .Where( u =&gt; u.JoinDate &gt;= someDateTime )
    .ToListAsync();

List&lt;CustomObject&gt; usersWithStatus = users
    .Join(
        inner: lstStatuses,
        outerKeySelector: u =&gt; u.ParticipationStatusID,
        innerKeySelector: s =&gt; s.ParticipationStatusID,
        resultSelector: ( u, s ) =&gt; new CustomObject
        {
            Name = u.FullName,
            ParticipationStatus = s.Label + &quot; Some string here&quot;
        }
    )
    .ToList();
  • Linq's Join is an INNER JOIN operation (and not any other kind of join, like FULL OUTER JOIN). Note that, as with SQL's INNER JOIN, it is possible for multiple rows in inner and outer to match each-other which may be undesirable.

    • And if any User entities aren't matched to a lstStatuses item then that User will be silently excluded from the results - whereas I'd consider that exceptional and if this were my program I'd want it to throw an exception instead of silently excluding it.
  • Internally, the .Join will efficiently map User and ParticipationStatus in linear-time O(n[u] + n

    展开收缩
    ) by using a temporary hashtable, whereas your current code takes quadratic time: O(n[u] * n
    展开收缩
    )
    .

huangapple
  • 本文由 发表于 2023年6月21日 22:46:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76524567.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定