【问题标题】:complicated mvc linq generated sql script复杂的 mvc linq 生成的 sql 脚本
【发布时间】:2016-08-19 18:11:13
【问题描述】:

我对 MVC 世界还很陌生,但我已经从事 asp.net 多年了。我用 mvc 开始这个项目,所以我可以习惯它。我一直在努力解决一些过于复杂的 sql 语句 linq 一直在生成我认为我做错了什么。如果不从头开始编写 sql 语句,我可能无法判断它是否正确。

好的,我的目标是获得这个身份数据库,我已经添加了一些字段并链接到其他一些表格,如地址和电话号码等。

我正在处理供应商搜索屏幕并想使用 linq 来获取数据。一些信息位于下面示例中 table1 的下拉列表中,并且有一个文本搜索选项,允许在主 aspnetusers 和其他一些表上的多个字段上进行“或”搜索。

我希望有人帮助我在 linq 上获得此简化版本。或者我应该开始编写我的 sql 并以某种方式在这里使用它(不知道如何在 mvc 中做到这一点,但应该非常相似

 var VendorRole = await db.Roles.FirstAsync(r => r.Name == "vendor");

        var results = db.Users.Include(u => u.table1).
            Include(u => u.table2).Include(u => u.table3).
            Include(u => u.table4).Include(u => u.table5).
            Where(u => u.Roles.Any(s => s.RoleId == VendorRole.Id));

        if (id1.HasValue)
        {
            results.Where(m => m.table1.First(a => a.id1 == id1) != null);
        }

        if (id2.HasValue)
        {
            results.Where(m => m.table1.First(a => a.id2 == id2) != null);
        }

        if (id3.HasValue)
        {
            results.Where(m => m.table1.First(a => a.id3 == id3) != null);
        }

        IEnumerable<string> searchTerms = SearchString.Split(' ')
                                              .Select(x => x.Trim());
        foreach (string term in searchTerms)
        {
            if (!string.IsNullOrWhiteSpace(term))
            {
                string captured = term.ToUpper();
                results = results.Where(t => (t.field1.ToUpper().Contains(captured) ||
                                            t.field2.ToUpper().Contains(captured) ||
                                            t.field3.ToUpper().Contains(captured) ||
                                            (t.field2 + " " + t.field3).ToUpper().Contains(captured) ||
                                            t.field4.ToUpper().Contains(captured) ||
                                            t.field5.ToUpper().Contains(captured) ||
                                            t.table2.Any(m => (m.field6 + " " + m.field7).ToUpper().Contains(captured)) != null));
            }
        }


        ViewBag.count = results.Count();
        if ((page -1) * 10 > ViewBag.count)
        {
            page = (int)Math.Floor((double)ViewBag.count / 10);
        }
        ViewBag.page = page;
        return PartialView(await results.OrderBy(m => m.field1 + " " + m.field2 + " " + m.field3).Skip((page - 1) * 10).Take(10).ToListAsync());

感谢您花时间提供帮助。

【问题讨论】:

  • 拥有多个Where 子句相当于AND 操作而不是OR。你真的想在所有条件下使用OR吗?

标签: c# linq asp.net-mvc-5 asp.net-identity .net-4.5


【解决方案1】:

您的查询现在的样子,每个Where 子句都使用集合上的AND 匹配,而不是OR

如果您真的想将OR 用于所有 条件,以下内容应该很有用。

正如我在another answer 中提到的,使用Linq 构建复杂查询谓词的正确方法是使用PredicateBuilder。有了这个,您可以将代码重构为两部分:

  1. Where 子句构建谓词和
  2. 查询数据

代码如下所示:

private Expression<Func<User, bool>> BuildIdQuery(
    Expression<Func<User, bool>> predicate,
    int? id,
    Func<User, int> propertySelector)
{
    if(id.HasValue)
    {
        // First(...) with throw an exception if there are no items
        // matching the predicate; Any() is the proper way to do it.
        return predicate.Or(m => m.Any(a => propertySelector(a) == id);
    }
    return predicate;
}

Expression<Func<User, bool>> BuildSearchTermQuery(
    Expression<Func<User, bool>> predicate, string searchTerm)
{
    if(String.IsNullOrWhiteSpace(searchTerm)
        return predicate;
    // You don't need to use ToUpper() unless you 
    // know that your database performs case-sensitive comparison
    return predicate.Or(m => m.field1.Contains(searchTerm))
        .Or(m => m.field2.Contains(searchTerm)); // etc.
}

所有的查询看起来像这样:

var predicate = PredicateBuilder.True<User>()
predicate = BuildIdQuery(predicate, id1, a => a.id1);
predicate = BuildIdQuery(predicate, id2, a => a.id2);
foreach(var term in searchTerms)
{
    predicate = BuildSearchTermQuery(predicate, term);
}

var results = db.Users
    .Where(predicate)
    .Skip(...)
    .Take(...);    

【讨论】:

  • 切换到使用谓词生成器,谢谢。
【解决方案2】:

使用什么 Linq 或存储过程取决于您。 对于数据库中的文本搜索,您可以查看 Lucene port

我建议您使用 N 层将复杂的业务逻辑与表示分离。您以后可以轻松更改/优化它。

/// <summary>
/// Assume you have special class to store users
/// </summary>
public class UserBdo
{
    public int id1 { get; set; }
    public int id2 { get; set; }
    ......
}

public class PagingParams
{
    public int CurrentPage { get; set; }
    public int PerPage { get; set; } = 10;
    /// <summary>
    /// How many without paging
    /// </summary>
    public int TotalResults { get; set; }
}

public class UsersBll
{
    public IEnumerable<UserBdo> Search(int? id1, int? id2, int? id3, IEnumerable<string> searchTerms, PagingParams pp)
    {
        var results = db.Users.Include(u => u.table1).
            Include(u => u.table2).Include(u => u.table3).
            Include(u => u.table4).Include(u => u.table5).
            Where(u => u.Roles.Any(s => s.RoleId == VendorRole.Id));

        if (id1.HasValue)
        {
            results.Where(m => m.table1.First(a => a.id1 == id1) != null);
        }

        if (id2.HasValue)
        {
            results.Where(m => m.table1.First(a => a.id2 == id2) != null);
        }

        //results = ...

        pp.TotalResults = 100;

        return results.Skip((pp.CurrentPage  - 1) * pp.PerPage).Take(pp.PerPage).ToListAsync();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 2017-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多