简体   繁体   English

实体框架,LINQ 查询

[英]Entity Framework, LINQ Query

How to loop through the Items below and update the Field which have empty values with the value (!) Error:如何遍历下面的项目并使用值 (!) 错误更新具有空值的字段:

Cannot implicitly convert type System.threading.task to System.Collections.Generic.IEnumerable<Respositories.AssignmentMasterData>无法将 System.threading.task 类型隐式转换为 System.Collections.Generic.IEnumerable<Respositories.AssignmentMasterData>

using (SUPEntities db = new SUPEntities())
{
    IEnumerable<AssignementMasterData> masterDatas = null;

    masterDatas = db.AssignementMasterDatas
                    .Where(m => DbFunctions.TruncateTime(m.CreatedDateTime) >= DbFunctions.TruncateTime(criteria.FilterStartDate)
                        && DbFunctions.TruncateTime(m.CreatedDateTime) <= DbFunctions.TruncateTime(criteria.FilterEndDate)
                        && (m.AssignmentNoteNumber == criteria.AssigmentNumber || criteria.AssignmentNumber == null)
                        && (m.BaseCourseId == criteria.courseId || criteria.CourseId == 0)
                        && (m.AccountNumber == criteria.AccountNumber || criteria.AccountNumber == null)
                        && (m.ReferenceNumber == criteria.ReferenceNumber || criteria.ReferenceNumber == null)
                        && (m.FacultyCode == criteria.FAcultyCode || criteria.FacultyCode == null)
                        && (m.Processed == criteria.Processed)
                        && (m.ClassNumber == criteria.ClassNumber || criteria.ClassNumber == null))
                    .ForEachAsync(t => t.AssignmentNoteIdentifiedClasses.Select(e => String.IsNullOrEmpty(e.Category)? "(!)": e.Category));
                
}

Firstly, about the error message:首先,关于错误信息:

You are trying to assign the wrong type to your masterDatas variable.您正在尝试为masterDatas变量分配错误的类型。 You declare it as a IEnumerable<Respositories.AssignmentMasterData> , but the ForEachAsync at the last line will return a Task , hence the error message.您将其声明为IEnumerable<Respositories.AssignmentMasterData> ,但最后一行的ForEachAsync将返回Task ,因此会返回错误消息。

See the ForEachAsync signature:请参阅ForEachAsync签名:

public static System.Threading.Tasks.Task ForEachAsync (this System.Linq.IQueryable source, Action action);公共静态 System.Threading.Tasks.Task ForEachAsync(这个 System.Linq.IQueryable 源,Action 动作);

Secondly.其次。 You want to return an IEnumerable<Respositories.AssignmentMasterData>你想返回一个IEnumerable<Respositories.AssignmentMasterData>

For that you don't need the call to ForEachAsync.为此,您不需要调用 ForEachAsync。

You will need to some point transform your IQueryable into an IEnumerable .您需要将IQueryable转换为IEnumerable A call to AsEnumerable() does that.AsEnumerable()调用就是这样做的。 Then you need to replace some values.然后你需要替换一些值。 So you need to project your collection using a Select .因此,您需要使用Select来投影您的收藏。

using (SUPEntities db = new SUPEntities())
{
    var masterDatas = db.AssignementMasterDatas
        .Where(m => DbFunctions.TruncateTime(m.CreatedDateTime) >= DbFunctions.TruncateTime(criteria.FilterStartDate)
            && DbFunctions.TruncateTime(m.CreatedDateTime) <= DbFunctions.TruncateTime(criteria.FilterEndDate)
            && (m.AssignmentNoteNumber == criteria.AssigmentNumber || criteria.AssignmentNumber == null)
            && (m.BaseCourseId == criteria.courseId || criteria.CourseId == 0)
            && (m.AccountNumber == criteria.AccountNumber || criteria.AccountNumber == null)
            && (m.ReferenceNumber == criteria.ReferenceNumber || criteria.ReferenceNumber == null)
            && (m.FacultyCode == criteria.FAcultyCode || criteria.FacultyCode == null)
            && (m.Processed == criteria.Processed)
            && (m.ClassNumber == criteria.ClassNumber || criteria.ClassNumber == null))
        .AsEnumerable()
        .Select(a =>
        {
            a.AssignmentNoteIdentifiedClasses = a.AssignmentNoteIdentifiedClasses
                .Select(e =>
                {
                    e.Category = string.IsNullOrWhiteSpace(e.Category) ? "(!)" : e.Category;
                    return e;
                })
                .ToList(); // Depending on the type of AssignmentNoteIdentifiedClasses, ToList() might be replaced.
            return a;
        });
    return masterDatas
}
  • Use .Include( m => m.AssignmentNoteIdentifiedClasses ) to bring-in related data in a single query, this is much faster than loading each set of related AssignmentNoteIdentifiedClasses in your for-each-row loop.使用.Include( m => m.AssignmentNoteIdentifiedClasses )在单个查询中引入相关数据,这比在 for-each-row 循环中加载每组相关的AssignmentNoteIdentifiedClasses快得多
  • You don't need to use TruncateTime .您不需要使用TruncateTime
    • In fact, you shouldn't because that will mean your query isn't SARGable.事实上,您不应该这样做,因为这意味着您的查询不是 SARGable。
    • Avoid functions in SQL predicates.避免在 SQL 谓词中使用函数。
    • Instead, just round criteria.FilterStartDate down to the start-of-day in application code and compare it normally with m => m.CreatedDateTime >= filterStart .相反,只需将criteria.FilterStartDate向下舍入到应用程序代码中的开始日期,然后将其与m => m.CreatedDateTime >= filterStart进行正常比较。
    • Similarly, FilterEndDate should be rounded-up and then compared like so: m => m.CreatedDateTime < filterEnd同样, FilterEndDate应该四舍五入,然后像这样比较: m => m.CreatedDateTime < filterEnd
      • Always use exclusive upper-bounds.始终使用独占上限。 It makes everything , especially date-range predicates, much easier to deal with.它使一切,尤其是日期范围谓词,更容易处理。
  • You don't need inline && in your Where .您不需要内联&&在您的Where Use additional separate .Where() clauses instead.改用其他单独的.Where()子句。 They'll be evaluated with AND他们将用AND进行评估
  • I assume EF Core isn't sophisted enough to recognize the NULL -means-ignore anti-pattern for optional search predicates, in which case **DON'T USE NULL -means-ignore IN AN PREDICATE!"我认为 EF Core 不够复杂,无法识别可选搜索谓词的NULL -means-ignore 反模式,在这种情况下,**不要在 PREDICATE 中使用NULL -means-ignore!”
    • This is bad for so many reasons: namely because query execution-plans are based on the structure ("shape") of the SQL query and not on parameter values, so the same cached execution-plan for non- NULL parameters will be used when some, or even all parameters are NULL - which is a problem.这很糟糕,原因有很多:即因为查询执行计划基于 SQL 查询的结构(“形状”)而不是参数值,因此在执行非NULL参数时将使用相同的缓存执行计划一些,甚至所有参数都是NULL - 这是一个问题。
    • Instead build your query by using IQueryable<T> 's Linq extensions and reassigning to itself.而是通过使用IQueryable<T>的 Linq 扩展并重新分配给自身来构建您的查询
      • eg IQueryable<T> query = db.Etc; query = query.Where( e => etc );例如IQueryable<T> query = db.Etc; query = query.Where( e => etc ); IQueryable<T> query = db.Etc; query = query.Where( e => etc );
      • Each .Where() is added as an AND condition.每个.Where()都作为AND条件添加。 If you want to build-up an OR condition then use PredicateBuilder .如果要建立OR条件,请使用PredicateBuilder

DateTime filterStart   = criteria.FilterStartDate.Date;
DateTime filterEndExcl = criteria.FilterEndDate  .Date.AddDays(1);

using (SUPEntities db = new SUPEntities())
{
    IQueryable<AssignementMasterData> query = db.AssignementMasterDatas
        .Include( m => m.AssignmentNoteIdentifiedClasses )
        .Where( m => m.CreatedDateTime >= filterStart   )
        .Where( m => m.CreatedDateTime <  filterEndExcl ) // Exclusive upper-bound.
        .Where( m => m.Processed       == criteria.Processed )
        .Where( m => m.ClassNumber     == criteria.ClassNumber )
    ;

    if( criteria.AssigmentNumber != null )
    {
        query = query.Where( m => m.AssignmentNoteNumber == criteria.AssigmentNumber );
    }

    if( criteria.AccountNumber != null )
    {
        query = query.Where( m => m.AccountNumber == criteria.AccountNumber );
    }

    if( criteria.CourseId != null && criteria.CourseId.Value > 0 )
    {
        query = query.Where( m => m.BaseCourseId == criteria.CourseId );
    }

    if( criteria.ReferenceNumber != null )
    {
        query = query.Where( m => m.ReferenceNumber == criteria.ReferenceNumber );
    }

    if( criteria.FacultyCode != null )
    {
        query = query.Where( m => m.FacultyCode == criteria.FacultyCode );
    }

    if( criteria.ClassNumber != null )
    {
        query = query.Where( m => m.ClassNumber == criteria.ClassNumber );
    }

    List<AssignementMasterData> rows = await query.ToListAsync().ConfigureAwait(false);
    
    List<String> categories = rows
        .SelectMany( r => r.AssignmentNoteIdentifiedClasses )
        .Select( String.IsNullOrEmpty(e.Category)? "(!)": e.Category) )
        .ToList();

    return categories;
}

The above can be simplified by adding a new extension-method (make sure you use Expression<Func<...>> and not just Func<> so that EF can still interpret the query:上面可以通过添加一个新的扩展方法来简化(确保你使用Expression<Func<...>>而不仅仅是Func<>以便 EF 仍然可以解释查询:

public static class MyQueryableExtensions
{
    public static IQueryable<T> WhereIfNotNull<T,TValue>( this IQueryable<T> query, TValue? value, Expression<Func<T,Boolean>> predicate )
        where TValue : struct
    {
        if( value.HasValue && value.Value != default(TValue) )
        {
            return query.Where( predicate );
        }
        else
        {
            return query;
        }
    }
}

Used like so:像这样使用:

// `criteria` is now named `c` for brevity.

DateTime filterStart   = c.FilterStartDate.Date;
DateTime filterEndExcl = c.FilterEndDate  .Date.AddDays(1);

using (SUPEntities db = new SUPEntities())
{
    IQueryable<AssignementMasterData> query = db.AssignementMasterDatas
        .Include( m => m.AssignmentNoteIdentifiedClasses )
        .Where( m => m.CreatedDateTime >= filterStart    )
        .Where( m => m.CreatedDateTime <  filterEndExcl  ) // Exclusive upper-bound.
        .Where( m => m.Processed       == c.Processed    )
        .Where( m => m.ClassNumber     == c.ClassNumber  )
        .WhereIfNotNull( c.AssigmentNumber, m => m.AssignmentNoteNumber == c.AssigmentNumber )
        .WhereIfNotNull( c.AccountNumber  , m => m.AccountNumber        == c.AccountNumber   )
        .WhereIfNotNull( c.CourseId       , m => m.BaseCourseId       ​  == c.CourseId        )
        ​.WhereIfNotNull( c.ReferenceNumber, m => m.ReferenceNumberr     == c.ReferenceNumber )
        ​.WhereIfNotNull( c.FacultyCode    , m => m.FacultyCoder         == c.FacultyCode     )
        ​.WhereIfNotNull( c.ClassNumber    , m => m.ClassNumber          == c.ClassNumber     )
   ;

    List<AssignementMasterData> rows = await query.ToListAsync().ConfigureAwait(false);
    
    List<String> categories = rows
        .SelectMany( r => r.AssignmentNoteIdentifiedClasses )
        .Select( String.IsNullOrEmpty(e.Category)? "(!)": e.Category) )
        .ToList();

    return categories;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM