使用LINQ聚合的entity framework来连接字符串?

这对我来说很容易在TSQL中执行,但我只是坐在这里,试着让它在EF4中工作!

我有一个表,让我们称之为TestData。 它有字段,比如:DataTypeID,Name,DataValue。

DataTypeID, Name, DataValue 1,"Data 1","Value1" 1,"Data 1","Value2" 2,"Data 1","Value3" 3,"Data 1","Value4" 

我想对DataID / Name进行分组,并将DataValue连接成CSV字符串。 期望的结果应包含 –

 DataTypeID, Name, DataValues 1,"Data 1","Value1,Value2" 2,"Data 1","Value3" 3,"Data 1","Value4" 

现在,我正在努力做到这一点 –

 var query = (from t in context.TestData group h by new { DataTypeID = h.DataTypeID, Name = h.Name } into g select new { DataTypeID = g.Key.DataTypeID, Name = g.Key.Name, DataValues = (string)g.Aggregate("", (a, b) => (a != "" ? "," : "") + b.DataValue), }).ToList() 

问题是LINQ to Entities不知道如何将其转换为SQL。 这是3个LINQ查询联合的一部分,我真的希望它保持这种方式。 我想我可以检索数据,然后再执行聚合。 出于性能原因,这对我的应用程序无效。 我还考虑过使用SQL服务器function。 但这在EF4世界中似乎并不“正确”。

有人在乎这个问题吗?

如果ToList()是原始查询的一部分而不是仅为此示例添加,则使用结果列表上的LINQ to Objects进行聚合:

 var query = (from t in context.TestData group t by new { DataTypeID = t.DataTypeID, Name = t.Name } into g select new { DataTypeID = g.Key.DataTypeID, Name = g.Key.Name, Data = g.AsEnumerable()}) .ToList() .Select (q => new { DataTypeID = q.DataTypeID, Name = q.Name, DataValues = q.Data.Aggregate ("", (acc, t) => (acc == "" ? "" : acc + ",") + t.DataValue) }); 

在LINQPad中测试,它产生了这个结果:

替代文字

感谢moi_meme的答案。 LINQ to Entities我不希望这样做。 正如其他人所建议的那样,您必须使用LINQ to Objects来访问字符串操作方法。

有关详细信息,请参阅moi_meme发布的链接。

更新8/27/2018 – 更新链接(再次) – https://web.archive.org/web/20141106094131/http://www.mythos-rini.com/blog/archives/4510

而且,由于我从8年前开始接受仅限链接的答案,我将澄清以防万一存档副本有一天消失。 它的基本要点是您无法在EF查询中访问string.join。 您必须创建LINQ查询,然后调用ToList()以执行对db的查询。 然后你有内存中的数据(又名LINQ to Objects),所以你可以访问string.join。

上述参考链接的建议代码如下 –

 var result1 = (from a in users b in roles where (a.RoleCollection.Any(x => x.RoleId = b.RoleId)) select new { UserName = a.UserName, RoleNames = b.RoleName) }); var result2 = (from a in result1.ToList() group a by a.UserName into userGroup select new { UserName = userGroup.FirstOrDefault().UserName, RoleNames = String.Join(", ", (userGroup.Select(x => x.RoleNames)).ToArray()) }); 

作者进一步建议用聚合替换string.join以获得更好的性能,就像这样 –

 RoleNames = (userGroup.Select(x => x.RoleNames)).Aggregate((a,b) => (a + ", " + b)) 

一些答案建议调用ToList()然后执行计算为LINQ to OBJECT。 这对于少量数据来说很好,但如果我有太多数据我不想太早加载到内存中,那么,ToList()可能不是一个选项。

我有类似的要求。 我的问题是获取实体的子项列表,并使用该子项的第一个字符创建逗号分隔值字符串。

  1. 我在View Model中创建了一个属性,它将保存来自存储库的原始数据。

     public class MyViewModel { public string AnotherRegularProperty { get; set; } public IEnumerable RawChildItems { get; set; } public string FormattedData { get { if (this.RawChildItems == null) return string.Empty; string[] theItems = this.RawChildItems.ToArray(); return theItems.Length > 0 ? string.Format("{0} ( {1} )", this.AnotherRegularProperty, String.Join(", ", theItems.Select(z => z.Substring(0, 1)))) : string.Empty; } } } 

好的,就这样,我的ViewModel就绪了。 之后,我轻松地将LINQ to Entity中的数据加载到此View Model而不调用.ToList(),它将所有数据加载到内存中。 如果数据库有记录,我永远不会调用.ToList()。

例:

 IQueryable myEntities = _myRepository.GetData(); IQueryable viewModels = myEntities.Select(x => new MyViewModel() { AnotherRegularProperty = x.AProperty, RawChildItems = x.MyChildren }) 

现在,我可以随时调用MyViewModel的FormattedData属性,只有在调用属性时才会执行Getter。

也许最好在数据库上创建一个视图(为你连接字段),然后让EF使用这个视图而不是原始表?

我很确定它在LINQ语句或Mapping Details中是不可能的。

你已经非常接近了。 试试这个:

 var query = (from t in context.TestData group h by new { DataTypeID = h.DataTypeID, Name = h.Name } into g select new { DataTypeID = g.Key.DataTypeID, Name = g.Key.Name, DataValues = String.Join(",", g), }).ToList() 

或者,如果EF不允许String.Join (Linq-to-SQL这样做),你可以这样做:

 var qs = (from t in context.TestData group h by new { DataTypeID = h.DataTypeID, Name = h.Name } into g select new { DataTypeID = g.Key.DataTypeID, Name = g.Key.Name, DataValues = g }).ToArray(); var query = (from q in qs select new { q.DataTypeID, q.Name, DataValues = String.Join(",", q.DataValues), }).ToList();