【问题标题】:Returning a collection of objects where an objects property matches any property from another collection of objects using LINQ-to-Entities使用 LINQ-to-Entities 返回一个对象集合,其中对象属性与另一个对象集合中的任何属性匹配
【发布时间】:2012-07-31 21:32:24
【问题描述】:

我一直在搜索一整天都找不到解决这个问题的方法......

我有一个 EntityCollectionCommunication 对象,每个对象都有一个 Intention 对象的实例(一对一)。

我还有一个 User 对象,它有许多 UserLocation EntityObjects(一对多)实例

  • Intention 对象有一个属性 UID
  • UserLocation 对象具有属性 LID

  • 我想编写一个 LINQ 表达式,它返回所有Communication 对象,其中与Intention 对象关联的Intention 实例的Communication 对象等于ANY 的任何实例的任何LID 属性UserLocation User 对象的实例。

我试过了

return _context.Communications.Where
(u => u.Intention.UID.Equals
(user.UserLocations.Select
(p => p.LID)));

还有这个

return _context.Communications.Where
(u => user.UserLocations.Any
(x => x.LID.Equals
(u.Intention.UID)));

还有这个

var thislist = from Intentions in _context.Intentions
                           join UserLocations in user.UserLocations
                           on Intentions.UID equals UserLocations.LID
                           select Intentions.UID;
            return _context.Communications.Where(u => u.Intention.Equals(thislist.Any()));

还有这个

var lidlist = user.UserLocations.Select(x => x.LID);
return _context.Communications.Where(x=> lidlist.Contains(x.Intention.UID)).ToList();

(这让我在 Contains 语句中出现错误,提示“Delegate System.Func<Communication,int,bool> 不接受 1 个参数”,不知道如何解决)

除了所有这些变化之外,我还有:

  • 修改了我的方法以返回IQueryable<Communication>,并且还尝试了List<Communication>,同时将ToList() 附加到我的查询中。

没有任何作用。无论我尝试什么,我总是会遇到这个异常

NotSupportedException 未被用户代码处理

无法创建“PreparisCore.BusinessEntities.UserLocation”类型的常量值。此上下文仅支持原始类型(“例如 Int32、String 和 Guid”)。

我做错了什么??

【问题讨论】:

  • UID和LID有哪些类型?
  • 嗯,比第二种形式应该有效。为了清楚起见,我会使用 = 。我会尝试写一个测试用例来确认。
  • 哪个代表不接受 1 个参数?通常,异常会准确指定委托类型。你的方法返回什么类型?我认为最后一个代码应该可以工作。其他三个确实不行。
  • 我想我发现了第二种形式的问题...... BRB
  • @Slauma System.Func

标签: c# linq entity-framework linq-to-entities entitycollection


【解决方案1】:

鉴于此代码:

namespace CollectionsWithIntentions
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;

    internal class Program
    {
        #region Methods

        private static void Main(string[] args)
        {
            var communications = new[]
                {
                    new Communication { Intention = new Intention { UID = 1 } },
                    new Communication { Intention = new Intention { UID = 2 } },
                    new Communication { Intention = new Intention { UID = 3 } },
                    new Communication { Intention = new Intention { UID = 4 } },
                };
            var users = new[]
                {
                    new User { UserLocations = new List<UserLocation>(new[] { new UserLocation { LID = 2 },new UserLocation{LID=5}  }) },
                    new User { UserLocations = new List<UserLocation>(new[] { new UserLocation { LID = 3 } }) }
                };

            IEnumerable<Communication> res =
                communications.Where(w => users.Any(a => a.UserLocations.Any(b=>b.LID == w.Intention.UID)));
            foreach (Communication communication in res)
            {
                Trace.WriteLine(communication);
            }
        }

        #endregion
    }

    internal class Communication
    {
        #region Public Properties

        public Intention Intention { get; set; }

        #endregion

        #region Public Methods and Operators

        public override string ToString()
        {
            return string.Concat("Communication-> Intention:", this.Intention.UID);
        }

        #endregion
    }

    internal class Intention
    {
        #region Public Properties

        public int UID { get; set; }

        #endregion
    }

    internal class User
    {
        #region Public Properties

        public List<UserLocation> UserLocations { get; set; }

        #endregion
    }

    internal class UserLocation
    {
        #region Public Properties

        public int LID { get; set; }

        #endregion
    }
}

我得到这个结果:

Communication-> Intention:2
Communication-> Intention:3

我错过了什么吗?

【讨论】:

  • 一个更正,我只搜索一个用户,但您的代码看起来与我的第二个示例几乎完全相同。另一个需要注意的区别是,所有这些对象都是 EntityObjects(UserLocation, User, Communication, Intention) 或 EntityCollections(Userlocations)。 UserLocations 是两个实体“用户”和“位置”之间的“桥接”对象。
  • 我可以确认通过 EF 会导致遇到相同的错误...调查中
  • 答案在这个post。因此,在您的情况下,您必须首先将 Communications 和 UserLocations 转换为列表。比它有效: ctx.Communications.ToList().Where(w1 => user.Locations.ToList().Any(a1 => a1.LID == w1.Intentions.UID)) .ToList();
  • 你太棒了 :) 就是这样!我觉得 apply hand to forward 在这里是有序的。谢谢你的帮助!!
  • @MattFoxxDuncan 和 Darek:评论中的解决方案非常邪恶,因为它会先将整个 Communications 表加载到内存中在应用过滤器之前。该表中的 100 条记录可能不是问题,而是 100000 或 100 万条记录?
【解决方案2】:

根据您在其中一个 cmets 中链接的最后两个编译器错误...

...我会得出结论,Intention.UID可空 类型 int? 而不是您在 cmets 中所说的不可空 int。这确实不编译。尝试将上一个查询更改为:

var lidlist = user.UserLocations.Select(x => x.LID);
return _context.Communications
    .Where(x => x.Intention.UID.HasValue
             && lidlist.Contains(x.Intention.UID.Value))
    .ToList();

其他三个查询不起作用,因为user.UserLocations 是内存中非原始自定义类型的集合(对于要生成的 SQL 查询,它是一个“常量”值)并且 EF 不支持构建具有此类常量自定义类型的 SQL 查询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-01
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    相关资源
    最近更新 更多