c# - 如何使用 Linq 或 Lambda 连接一对多表并将扁平化结果投影为匿名类型

标签 c# entity-framework linq lambda

我有 3 个通过外键链接的表:ChangeSet、ObjectChanges、PropertyChanges。这些表彼此之间具有一对多关系。我需要加入并投影并将结果扁平化为匿名类型。

我们在数据层使用 Entity Framework ,我本质上需要使用 linq 进行以下查询。

select c.Id as ChangeSetId,
c.Timestamp,
c.Author_Id,
u.Name as [User],
o.id as ObjectChangeId,
o.TypeName,
o.ObjectReference as EntityId,
o.DisplayName,
p.Id as PropertyChangeId,
p.PropertyName, 
p.ChangeType,
p.OriginalValue, 
p.Value  
from ChangeSets c
inner join ObjectChanges o
    on c.Id = o.ChangeSetId
left join PropertyChanges p
    on p.ObjectChangeId = o.Id
inner join Users u
    on u.Id = c.Author_Id
order by c.id desc

所讨论的方法看起来像这样:

GetAllWhereExpression(Expression<Func<ChangeSet, bool>> expression)

本例中的表达式可能是Where o.EntityId = [Some Value] and c.TimeStamp > X and < Y。

我在 linq 中感觉非常接近以下内容,但无法弄清楚如何注入(inject)表达式:(.GetRepository().Entities 基本上是 DbSet)

var foo = from c in _uow.GetRepository<ChangeSet>().Entities
        join o in _uow.GetRepository<ObjectChange>().Entities on c.Id equals o.ChangeSetId
        join p in _uow.GetRepository<PropertyChange>().Entities on o.Id equals p.ObjectChangeId
        where expression // This Line Not Valid
        select new
        {
            ChangeSetId = c.Id,
            Timestamp = c.Timestamp,
            User = c.User.DisplayName,  
            EntityType = o.TypeName,
            EntityValue = o.DisplayName,
            Property = p.PropertyName,
            OldValue = p.OriginalValue,
            NewValue = p.Value
        };

我更喜欢使用 Lambda 语法,但我不知道如何构建它。我知道我需要 SelectMany 来投影和展平结果,但我不知道如何在子集合的匿名类型中使用它们:

var queryable = _uow.GetRepository<ChangeSet>().Entities // This is basically the DbSet<ChangeSet>()
            .Where(expression)
            .SelectMany(c => new
            {
                ChangeSetId = c.Id,
                Timestamp = c.Timestamp,
                User = c.User.DisplayName,  
                EntityType = c.ObjectChanges.SelectMany(o => o.TypeName), //Doesn't work, turns string into char array
                //PropertyName = c. this would be a 1 to many on the entity
            }
                )

如何制作 linq 以产生与 sql 查询基本相同的结果?

最佳答案

方法语法如下。

_uow.GetRepository<ChangeSet>().Entities
    .Where(expression)
.Join(_uow.GetRepository<ObjectChanges>().Entities, cs => cs.Id, oc => oc.ChangeSetId, 
    (cs, oc) => new { cs, oc })
.Join(_uow.GetRepository<PropertyChanges>().Entities, outer => outer.oc.Id, pc => pc.ObjectChangeId, 
    (outer, pc) => new { cs = outer.cs, oc = outer.cs, pc })
.Join(_uow.GetRepository<User>().Entities, outer => outer.cs.Author_Id, u => u.Id, 
    (outer, u) => new { 
        ChangeSetId = outer.cs.Id,
        Timestamp = outer.cs.Timestamp,
        User = u.DisplayName,  
        EntityType = outer.oc.TypeName,
        EntityValue = outer.oc.DisplayName,
        Property = outer.pc.PropertyName,
        OldValue = outer.pc.OriginalValue,
        NewValue = outer.pc.Value
    })

关于c# - 如何使用 Linq 或 Lambda 连接一对多表并将扁平化结果投影为匿名类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42430915/

相关文章:

c# - 我怎样才能模拟这个静态方法

c# - 如何将 Predicate<T> 转换为 Expression<Predicate<T>> 以与 Moq 一起使用?

c# - 在 .net 中的嵌套循环内执行异步方法时出现问题

c# - 无法将表达式类型 'lambda expression' 转换为返回类型 'System.Linq.Expressions.Expression<System.Func<IProduct,string,bool>>'

entity-framework - 如何在 DB first 方法中为实体设置创建日期和修改日期

c# - 带有列名称的 EF7 支架现有数据库 = 表名称

entity-framework - Entity Framework 代码优先不要创建表

c# - Select() 内部的 bool 值

linq - 使用 LINQ 进行任意排序

c# - JSON.NET - 识别嵌套数组