多个类似的linq查询

3

我有一个 Course 模型,它有一些多对多的关系,比如 Age 或 Time。

我有以下查询:

string IDs = "1,2,3"
string[] IDList = IDs.Split(',');

return (from x in entities.Course
       where x.Ages.Where(val => IDList.Contains(val.ID.ToString())).Count() == IDList.Count()
       select x);

我需要为时间和其他一些属性设置相同的查询条件,例如:

string IDs = "1,2,3"
string[] IDList = IDs.Split(',');

return (from x in entities.Course
       where x.Times.Where(val => IDList.Contains(val.ID.ToString())).Count() == IDList.Count()
       select x);

如何使查询更具动态性,以便不必多次编写类似的查询?

谢谢。


1
这只是Linq,还是Linq to Entities?解决方案会有很大的差异。对于Linq,只需重构成一个方法即可。Linq to Entities的解决方案在http://www.albahari.com/nutshell/linqkit.aspx。 - Jeow Li Huan
2个回答

2
你可以创建一个方法,接受一个表达式(根据你的数据类型),然后以这种方式运行查询。你需要让AgesTime等实现特定的接口才能使它正常工作。
例如,假设你使用EF并且你的模型是使用DbSet的Code First,你可以创建以下内容:
public interface IObject
{
    int ID { get; set; }
}

public class Age : IObject
{
    public int ID { get; set; }

    // The rest of the data
}

public class Time : IObject
{
    public int ID { get; set; }

    // The rest of the data
}

public class Course
{
    public virtual ICollection<Age> Ages { get; set; }
    public virtual ICollection<Time> Times { get; set; }
}

public class CourseContext : DbContext
{
    public DbSet<Course> Course { get; set; }
}

public class Test
{
    public IQueryable<Course> GetCourses(Expression<Func<Course, ICollection<IObject>>> exp)
    {
        var entities = new CourseContext(); 
        string IDs = "1,2,3";
        string[] IDList = IDs.Split(',');

        var c = exp.Compile();

        return entities.Course.Where(x => c.Invoke(x).Count(val => IDList.Contains(val.ID.ToString())) == IDList.Count());
    }

    public void TestMethod()
    {
        var times = GetCourses(c => (ICollection<IObject>)c.Times);
        var ages = GetCourses(c => (ICollection<IObject>)c.Ages);
    }
}

没问题 :) 我喜欢表达式!它们是我最喜欢的 C# 特性之一。 - joe_coolish

1
我会创建返回不同查询结果的方法。
public IQuerable<Course> GetAllCourses() {
    return entities.Course;
}

public IQueryable<Course> ByAge(IQueryable<Course> source, IEnumerable<String> ages {
    return from x in source
           where x.Ages.Where(val => ages.Contains(val.ID.ToString())).Count() == IDList.Count()
           select x;
}

public IQuerable<Course> ByTimes(IQueryable<Course> source, IEnumerable<String> times) {
    return from x in source
           where x.Ages.Where(val => IDList.Contains(val.ID.ToString())).Count() == IDList.Count()
           select x;
}

原因是该方法封装了查询逻辑-只有where子句不同。然后,您可以传入任何源。您甚至可以将两个查询过滤器组合为链接的方法调用:
var ids = new [] { "1", "2", "3" };
var coursesByAgeAndTime = ByTime(ByAge(GetAllCourses(), ids), ids);

好的,是的,这就是我实现的相同功能 - 我想知道是否有一种方法可以将整个查询封装成1个。 - user441365
@user441365 这些方法封装了“where”逻辑。from x in sourceselect x 语句同样可以使用 source.Where(...) 来实现。 - Yuck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接