将查找展平为单个linq表达式的循环

ekk*_*kis 2 .net c# linq entity-framework

LINQ到实体的类型成员支持中?我试图声明在LINQ中查询的类属性遇到了一些问题.在这里,我将在实现中布置代码,希望能够将其转换为查询.

我有一个Quiz包含Questions 集合的类,每个类都根据a进行分类QuestionLevel......我需要确定一个测验是"开放"还是"关闭",这是通过问题级别的外部联接来完成的.与最大值表相比较的每个级别的问题计数.这是代码,逐字:

public partial class Quiz
{
    public bool IsClosed
    {
        get
        {
            // if quiz has no questions, it's open
            if (this.Questions.Count() == 0) return false;

            // get a new handle to the EF container to do a query for max values
            using (EFContainer db = new EFContainer())
            {
                // we get a dictionary of LevelName/number
                Dictionary<string, int> max = db.Registry
                    .Where(x => x.Domain == "Quiz")
                    .ToDictionary(x => x.Key, x => Convert.ToInt32(x.Value));
                // count the number of questions in each level, comparing to the maxima
                // if any of them are less, the quiz is "open"
                foreach (QuestionLevel ql in db.QuestionLevels)
                {
                    if (this.Questions.Where(x => x.Level == ql).Count() < max["Q:Max:" + ql.Name])
                        return false;
                }
            }
            // the quiz is closed
            return true;
        }
    }
 }
Run Code Online (Sandbox Code Playgroud)

所以这是我尚未尝试的尝试:

    public static IQueryable<Quiz> WhereIsOpen(this IQueryable<Quiz> query)
    {
        EFContainer db = new EFContainer();
        return from ql in db.QuestionLevels
               join q in query on ql equals q.Questions.Select(x => x.Level)
               into qs
               from q in qs.DefaultIfEmpty()
               where q.Questions.Count() < db.Registry
                    .Where(x => x.Domain == "Quiz")
                    .Where(x => x.Key == "Q:Max" + ql.Name)
                    .Select(x => Convert.ToInt32(x.Value))
               select q;
    }
Run Code Online (Sandbox Code Playgroud)

它在联接帐户上失败,抱怨:

join子句中某个表达式的类型不正确.调用'GroupJoin'时类型推断失败

我还在努力解决这个问题.

*更新我*

啊.傻我.

   join q in query on ql equals q.Questions.Select(x => x.Level).Single()
Run Code Online (Sandbox Code Playgroud)

还有一个障碍:

指定的LINQ表达式包含对与不同上下文关联的查询的引用.

这是因为我为最大查找创建的新容器; 所以我想重新考虑这样的因素:

    public static IQueryable<Quiz> WhereIsOpen(this IQueryable<Quiz> query)
    {
        EFContainer db = new EFContainer();
        IEnumerable<QuestionLevel> QuestionLevels = db.QuestionLevels.ToList();
        Dictionary<string, int> max = db.Registry
                .Where(x => x.Domain == "Quiz")
                .ToDictionary(x => x.Key, x => Convert.ToInt32(x.Value));
        return from ql in QuestionLevels
               join q in query on ql equals q.Questions.Select(x => x.Level).Single()
               into qs
               from q in qs.DefaultIfEmpty()
               where q.Questions.Count() < max["Q:Max:" + ql.Name]
               select q;
    }
Run Code Online (Sandbox Code Playgroud)

但我无法获得编译的表达式...它需要我将QuestionLevels转换为IQueryable(但是转换不起作用,产生运行时异常).

*更新II*

我找到了铸造问题的解决方案,但现在我回到了"不同的上下文"异常.GRR ...

return from ql in QuestionLevels.AsQueryable()
Run Code Online (Sandbox Code Playgroud)

*更新(柯克的建议)*

所以我现在有了这个,它编译但生成一个运行时异常:

public static IQueryable<Quiz> WhereIsOpen(this IQueryable<Quiz> query)
{
    EFContainer db = new EFContainer();
    IEnumerable<string> QuestionLevels = db.QuestionLevels.Select(x => x.Name).ToList();
    Dictionary<string, int> max = db.Registry
            .Where(x => x.Domain == "Quiz")
            .ToDictionary(x => x.Key, x => Convert.ToInt32(x.Value));
    return from ql in QuestionLevels.AsQueryable()
           join q in query on ql equals q.Questions.Select(x => x.Level.Name).Single()
           into qs
           from q in qs.DefaultIfEmpty()
           where q.Questions.Count() < max["Q:Max:" + ql]
           select q;
}
Run Code Online (Sandbox Code Playgroud)

然后我这样称呼:

List<Product> p = db.Quizes.WhereIsOpen().Select(x => x.Component.Product).ToList();
Run Code Online (Sandbox Code Playgroud)

由此产生的异常:

此方法支持LINQ to Entities基础结构,不应在代码中直接使用.

Oma*_*mar 5

将数据库对象与域对象耦合时,遇到的问题很常见.出于这个原因,最好有一组代表你的域的单独的类和一组代表你的数据库并用于数据库CRUD的类.可以预期属性重叠,但这种方法可以更好地控制应用程序,并使数据库与业务逻辑分离.

测验关​​闭的想法属于您的域(业务逻辑).您的DAL(数据访问层)应负责加入所有必要的表,以便在您返回测验时,确定是否已关闭所需的所有信息.然后,您的域/服务/业务层应创建域对象,并IsClosed正确填充属性,以便在UI层(MVC)中轻松访问它.

我看到你直接访问了数据库上下文,我对此提出警告并鼓励你研究使用DI/IoC框架(Ninject很棒),但是,我还要直接访问数据库上下文

在您的视图/控制器中使用此类:

public class QuizDomainObject 
{
    public int Id {get; set;}
    public bool IsClosed {get; set;}
    // all other properties
}
Run Code Online (Sandbox Code Playgroud)

控制器:

public class QuizController : Controller 
{
    public ActionResult View(int id)
    {
        // using a DI/IoC container is the 
        // preferred method instead of 
        // manually creating a service
        var quizService = new QuizService(); 
        QuizDomainObject quiz = quizService.GetQuiz(id);

        return View(quiz);
    }
}
Run Code Online (Sandbox Code Playgroud)

服务/业务层:

public class QuizService
{
    public QuizDomainObject GetQuiz(int id)
    {
        // using a DI/IoC container is the 
        // preferred method instead of 
        // access the datacontext directly
        using (EFContainer db = new EFContainer())
        {
            Dictionary<string, int> max = db.Registry
                .Where(x => x.Domain == "Quiz")
                .ToDictionary(x => x.Key, x => Convert.ToInt32(x.Value));

            var quiz = from q in db.Quizes
                       where q.Id equals id
                       select new QuizDomainObject()
                       {
                            Id = q.Id,
                            // all other propeties,

                            // I'm still unclear about the structure of your  
                            // database and how it interlates, you'll need 
                            // to figure out the query correctly here
                            IsClosed =  from q in ....
                       };


            return quiz;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 有一件事我不明白:EF应该是我的建模空间,如何映射到后端数据库取决于映射机制......那么为什么我要拥有第二个(DAL)层?我的DAL不是EF型号吗? (2认同)