通过实体框架和Where子句通过Linq To实体进行左外连接

时间:2011-03-22 15:44:30

标签: entity-framework linq-to-entities left-join outer-join

在使用实体框架时,我已阅读了与在Linq to Entities(.NET 3.5)中实现等效的LEFT OUTER JOIN相关的所有帖子,但尚未找到解决以下问题的方法。

给出两个表,由下面的对象表示:

    public class Foo
    {
        public int FooId;  // primary key
        public string Name;
    }

    public class Bar
    {
        public int BarId;  // primary key
        public int FooId;  // foreign key
        public string Desc;
    }

我需要创建一个Linq to Entities语句,它是以下SQL语句的EQUIVALENT。请注意,WHERE语句包含两个OR'd条件,这两个条件跨越两个表,并使用DISTINCT限定符。

SELECT DISTINCT
    Foo.*
FROM
    Foo
    LEFT OUTER JOIN Bar ON Foo.FooId = Bar.FooId
WHERE
    (Foo.Name = 'fooname' OR Bar.Desc = 'bardesc')

我生成的Linq查询是通过实体框架实现Linq到实体,并且(希望)生成一个要在服务器上执行的SQL语句。 Linq to Entities不支持FirstOrDefault()扩展子句,因此LEFT OUTER JOIN的标准Linq语法将不起作用。

以下是我的解决方案,但我无法执行以下任一操作:

1)生成一个结果集,其中包含LEFT OUTER JOIN操作返回的一组Foo / Bar组合。

2)实现WHERE子句的等价物:WHERE (Foo.Name = 'fooname' OR Bar.Desc = 'bardesc')

    private class JoinSet
    {
        public Foo Foo;
        public IQueryable<Bar> Bars;
    };

    private class FooBar
    {
        public Foo Foo;
        public Bar Bar;
    };

    IEnumerable<Foo> OuterJoinTest()
    {
        IQueryable<Foo> fooBaseQuery = dbContext.FooSet;
        IQueryable<Bar> barBaseQuery = dbDontext.BarSet;

        IQueryable<JoinSet> joinQuery =
            from foo in fooBaseQuery
            select new JoinSet
                    {
                        Foo = foo,
                        Bars = barBaseQuery.Where(bar => bar.FooId == foo.FooId)
                    };

        // How do I generate a result set containing FooBar objects ?

        // How or where do I insert the equivalent of: ?
        //  WHERE (Foo.Name = 'fooname' OR Bar.Description = 'bardesc')

        IQueryable<Foo> resultQuery =
            from joinSet in joinQuery
            select joinSet.Foo;

        resultQuery = resultQuery.Distinct();

        return resultQuery.ToList();
    }

任何帮助,想法或建议都将不胜感激。

EulerOperator

1 个答案:

答案 0 :(得分:11)

.NET 3.5

private class FooBar
{
   public Foo Foo { get; set; }
   public Bar? Bar { get; set; }
}

var innerQuery = from foo in context.Foos
                 from bar in context.Bars
                 where foo.Name == 'fooname' || bar.Description == 'bardesc'
                 where foo.FooId == bar.FooId
                 select new FooBar { Foo = foo, Bar = bar };


var outerQuery = from foo in context.Foos
                 where foo.Name == 'fooname' 
                 where !context.Bars.Any(b => b.FooId == foo.FooId)
                 select new FooBar { Foo = foo, Bar = null };

var leftouterjoinQuery = innerQuery.Union(outerQuery).Distinct();

.NET 4.0

var query = (from foo in context.Foo
            join b in context.Bar
            on foo.FooId equals b.FooId into Bar
            from bar in Bar.DefaultIfEmpty()
            where foo.Name = 'fooname' || bar.Description = 'bardesc'
            select new { foo, bar }).Distinct();