使用 C# LINQ 和 MongoDB 子查询或加入 embedded/nested 文档
Sub-Query or Join with embedded/nested document using C# LINQ with MongoDB
我正在尝试做类似以下示例的操作,但出现异常 -
System.ArgumentException:方法的'System.Collections.Generic.IEnumerable1 ' cannot be used for parameter of type 'System.Linq.IQueryable
1'类型的表达式。
这是我的代码和相关的 类 。我该如何解决这个问题,有什么办法可以解决吗?
var channels = _channelService.Collection;
var tracks = _trackService.Collection;
var query = from b in tracks.AsQueryable()
select b;
var data = (from q in channels.AsQueryable()
from p in q.Episodes
//from x in trackcoll.AsQueryable()
select new
{
p,
Tracks = query.Where(w => p.Tracks.Contains(w.Id))
}).ToList();
// Related classes
public class ContentBase : IAuditable
{
public string Id { get; set ; }
public string CreatedBy { get ; set ; }
public string CreatedOn { get ; set ; }
public string UpdatedBy { get ; set ; }
public string UpdatedOn { get; set; }
}
public class Channel: ContentBase
{
public List<Episode> Episodes { get; set; }
}
public class Episode: ContentBase
{
// List of track Id
public List<string> Tracks { get; set; }
}
public class Track: ContentBase
{
public string TrackUrl { get; set; }
public string Duration { get; set; }
public string Size { get; set; }
public string ContentType { get; set;
}
MongoDB 对联接的 LINQ 支持仅限于 here. Your expression cannot be translated into Aggregation Framework's $lookup 所述的相等联接,因为 .Contains()
.
没有等效语法
因此,您必须 运行 一个更接近聚合框架语法的操作。一个示例是流畅的聚合接口,它允许您 运行 扩展方法与聚合框架的运算符同名。尝试:
var q = _channels.Aggregate()
.Unwind(x => x.Episodes)
.Lookup(
foreignCollectionName:"tracks",
localField:"Episodes.Tracks",
foreignField:"_id",
@as:"Tracks");
var result = q.ToList();
以上代码将return一个List<BsonDocument>
mickl 的回答会让你得到官方驱动程序,但如果你不喜欢处理 bsondocuments 并且想要某种程度的类型安全,你可以简单地使用 执行以下操作mongodb.entities 图书馆(我是其作者):
public class EpisodeWithTracks
{
public Track[] Tracks { get; set; }
}
var pipeline = new Template<Channel, EpisodeWithTracks>(@"
[
{
$unwind: '$<Episodes>'
},
{
$lookup: {
from: '<track_collection>',
localField: '<Episodes.Tracks>',
foreignField: '_id',
as: '<Tracks>'
}
}
]")
.Path(c => c.Episodes)
.Tag("track_collection", collectionName)
.Path(c => c.Episodes[0].Tracks)
.PathOfResult(ewt => ewt.Tracks);
var result = DB.Aggregate(pipeline)
.ToList();
这里是 wiki page 解释它是如何工作的。
我正在尝试做类似以下示例的操作,但出现异常 -
System.ArgumentException:方法的'System.Collections.Generic.IEnumerable1 ' cannot be used for parameter of type 'System.Linq.IQueryable
1'类型的表达式。
这是我的代码和相关的 类 。我该如何解决这个问题,有什么办法可以解决吗?
var channels = _channelService.Collection;
var tracks = _trackService.Collection;
var query = from b in tracks.AsQueryable()
select b;
var data = (from q in channels.AsQueryable()
from p in q.Episodes
//from x in trackcoll.AsQueryable()
select new
{
p,
Tracks = query.Where(w => p.Tracks.Contains(w.Id))
}).ToList();
// Related classes
public class ContentBase : IAuditable
{
public string Id { get; set ; }
public string CreatedBy { get ; set ; }
public string CreatedOn { get ; set ; }
public string UpdatedBy { get ; set ; }
public string UpdatedOn { get; set; }
}
public class Channel: ContentBase
{
public List<Episode> Episodes { get; set; }
}
public class Episode: ContentBase
{
// List of track Id
public List<string> Tracks { get; set; }
}
public class Track: ContentBase
{
public string TrackUrl { get; set; }
public string Duration { get; set; }
public string Size { get; set; }
public string ContentType { get; set;
}
MongoDB 对联接的 LINQ 支持仅限于 here. Your expression cannot be translated into Aggregation Framework's $lookup 所述的相等联接,因为 .Contains()
.
因此,您必须 运行 一个更接近聚合框架语法的操作。一个示例是流畅的聚合接口,它允许您 运行 扩展方法与聚合框架的运算符同名。尝试:
var q = _channels.Aggregate()
.Unwind(x => x.Episodes)
.Lookup(
foreignCollectionName:"tracks",
localField:"Episodes.Tracks",
foreignField:"_id",
@as:"Tracks");
var result = q.ToList();
以上代码将return一个List<BsonDocument>
mickl 的回答会让你得到官方驱动程序,但如果你不喜欢处理 bsondocuments 并且想要某种程度的类型安全,你可以简单地使用 执行以下操作mongodb.entities 图书馆(我是其作者):
public class EpisodeWithTracks
{
public Track[] Tracks { get; set; }
}
var pipeline = new Template<Channel, EpisodeWithTracks>(@"
[
{
$unwind: '$<Episodes>'
},
{
$lookup: {
from: '<track_collection>',
localField: '<Episodes.Tracks>',
foreignField: '_id',
as: '<Tracks>'
}
}
]")
.Path(c => c.Episodes)
.Tag("track_collection", collectionName)
.Path(c => c.Episodes[0].Tracks)
.PathOfResult(ewt => ewt.Tracks);
var result = DB.Aggregate(pipeline)
.ToList();
这里是 wiki page 解释它是如何工作的。