动态设置要在LINQ查询中加入的实体

时间:2014-04-19 07:16:19

标签: c# linq entity-framework

我有一个类似的查询:

from joinedEntity in joinedEntities
join relatedEntity in dbContext.X on ....

现在,我想以" X"的方式编写上述查询。可以动态传递,这样我就不需要为每个不同的" X"编写单独的linq查询。有帮助吗?我应该使用表达树和反射吗?如果有,怎么样?谢谢。

我猜想它应该是这样的:

var parameter =  Expression.Parameter(typeof (CompanyContext), "dbContext");
var member = Expression.MakeMemberAccess(parameter, typeof(CompanyContext).GetMember("X")[0]);
.....

以下是我的加入示例:

       from joinedEntity in joinedEntities
       join relatedEntity in dbContext.Channels on joinedEntity.Id equals relatedEntity.CId
        select new JoinedEntities(joinedEntity)
        {
        Channel  = relatedEntity.Name
        };

这是它的方法语法:

joinedEntities.Join(dbContext.Channels, m => m.Id, k => k.CId, (m, k) => new JoinedEntities(m)    { Channel = k.Name });

这也是另一个:

from joinedEntity in joinedEntities
join relatedEntity in dbContext.ActivityOutput on joinedEntity.Id equals relatedEntity.CId
        select new JoinedEntities(joinedEntity)
         {
              ActivityOutput = relatedEntity.Name
           };

1 个答案:

答案 0 :(得分:1)

最简单的方法是创建一个表示存在CId字段的界面。

// Don't know if you need this one or if you want to have the class of joinedEntities always being the same
public interface IJoinedEntities
{
    int Id { get; set; }
}

public interface IRelatedEntity
{
    int CId { get; set; }
}

所有相关实体都需要实施IRelatedEntity。实体框架的所有类都是部分的,因此您只需要创建另一个部分类来添加此接口。

由于您希望投影只是创建一个扩展方法,我们将链接到标准连接。

public static class CustomIQueryableExtensions
{
    public static IQueryable<TResult> CommonJoinQueryable<TOuter, TInner, TResult>(this IQueryable<TOuter> outer,
                                                                          IQueryable<TInner> inner,
                                                                          Expression<Func<TOuter, TInner, TResult>>
                                                                              resultSelector)
        where TOuter : IJoinedEntities
        where TInner : IRelatedEntity
    {
        // have to use expression trees to build the join otherwise cast to interface is in expression tree
        var outerParam = Expression.Parameter(typeof (TOuter), "outer");
        var outerBody = Expression.Lambda<Func<TOuter, int>>(Expression.Property(outerParam, "CId"), outerParam);

        var innerParam = Expression.Parameter(typeof (TInner), "inner");
        var innerBody = Expression.Lambda<Func<TInner, int>>(Expression.Property(innerParam, "Id"), innerParam);

        return outer.Join(inner, outerBody, innerBody, resultSelector);
    }


    public static IEnumerable<TResult> CommonJoinEnumerable<TOuter, TInner, TResult>(this IEnumerable<TOuter> outer,
                                                                           IEnumerable<TInner> inner,
                                                                           Func<TOuter, TInner, TResult>
                                                                               resultSelector)
        where TOuter : IJoinedEntities
        where TInner : IRelatedEntity
    {
        // have to use expression trees to build the join otherwise cast to interface is in expression tree
        Func<TOuter, int> outerJoin = outerParam => outerParam.Id;
        Func<TInner, int> relatedJoin = innerParam => innerParam.CId;

        return outer.Join(inner, outerJoin, relatedJoin, resultSelector);
    }
}

现在你可以使用它并仍然处理投影。

joinedEntities.CommonJoinQueryable(dbContext.Channels, (m, k) => new JoinedEntities()    { Channel = k.Name, tracking = m }); 

joinedEntities.CommonJoinEnumerable(dbContext.Channels, (m, k) => new JoinedEntities(m)    { Channel = k.Name }); 

您仍然应该使用SQL事件探查器来查看使用Enumerable时生成的内容,因为它会将结果拉下来然后将它们连接到内存中,而不是从SQL中连接。我知道这就是你的要求,但这并不常见。您不应该将参数传递给构造函数,而应该考虑创建一个可以使用投影设置的属性,然后使用IQueryable。

我相信这是lnanikian试图得到的。