2

我尝试通过 LINQ 查询数据库项目,但它不工作。唯一的例外是:

你调用的对象是空的。

堆栈跟踪与异常本身一样无用:

在 SQLite.TableQuery 1.CompileExpr(Expression expr, List1 queryArgs) 在 d:\XX\XX\XX\XX\XX\SQLite.cs:line 2383 at SQLite.TableQuery 1.CompileExpr(Expression expr, List1 queryArgs) 在 d:\XX\XX\XX\XX\XX\SQLite. cs: 1.CompileExpr(Expression expr, Listd:\XX\XX\XX\XX\XX\SQLite.cs 中 SQLite.TableQuery 1 queryArgs 的第 2388 行:d:\XX\XX\XX\XX\ 中 SQLite.TableQuery 1 queryArgs 的第 23081.CompileExpr(Expression expr, List行XX\SQLite.cs: d:\XX\XX\XX\XX\XX\SQLite.cs: SQLite.TableQuery 1.GetEnumerator() in d:\XX 1.CompileExpr(Expression expr, List\XX\XX\XX\XX\SQLite.cs:line 2308 at SQLite.TableQuery 1 queryArgs) 1.GenerateCommand(String selectionList) in d:\XX\XX\XX\XX\XX\SQLite.cs:line 2274 at SQLite.TableQueryXX\XX\XX\XX\SQLite.cs:System.Collections.Generic.List 1..ctor(IEnumerable1 集合的第 2521 行)
在 System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) 在 Kapital.DataModel.DataManagerOnetimeExpense.<>c__DisplayClass5.b__4() 在 d:\XX\XX\XX\XX\XX\DataModel\DataManagerOnetimeExpense.cs :
d:\XX\XX\XX\XX\XX\SQLite.cs 中 SQLite.SQLiteConnection.RunInTransaction(Action action) 的第 47 行:Kapital.DataModel.DataManagerOnetimeExpense.RetrieveItems 的第 906 行(Int32 月,Int32 年,Boolean isPaid ) 在 d:\XX\XX\XX\XX\XX\DataModel\DataManagerOnetimeExpense.cs:第 39 行 UnitTestKapital.Database.TestDataManagerOnetimeExpense.TestRetrieveItemsByMonthYearIsPaid() 在 d:\XX\XX\XX\XX\XX\UnitTestKapital\Database \TestDataManagerOnetimeExpense.cs:第 154 行

但是这里是 LINQ 查询:

public List<OnetimeExpense> RetrieveItems(int month, int year, bool isPaid)
{
    var onetimeExpenses = new List<OnetimeExpense>();

    connection.RunInTransaction(() =>
    {
        var items = from s in connection.Table<OnetimeExpense>()
                    let convertedDate = (DateTime)s.PaymentDate
                    where (convertedDate.Month == month)
                       && (convertedDate.Year == year)
                       && (s.IsPaid == isPaid)
                    select s;
        onetimeExpenses = items.ToList();
    });

    return onetimeExpenses;
}

它肯定与日期有关,因为以下方法有效(基本上是相同的方法,没有日期的东西):

public List<OnetimeExpense> RetrieveItems(bool isPaid)
{
    var onetimeExpenses = new List<OnetimeExpense>();

    connection.RunInTransaction(() =>
    {
        var items = from s in connection.Table<OnetimeExpense>()
                    where (s.IsPaid == isPaid)
                    select s;
        onetimeExpenses = items.ToList();
    });

    return onetimeExpenses;
}

有趣的部分来了:几个月前我在 WinRT 应用程序中遇到了同样的问题。我设法以与上图相同的方式解决了这个问题。

我正在使用SQLite 3.7.16.2。LINQ 提供程序是sqlite-net

还有什么?Visual Studio 2012、C#、.Net 4.5。它是一个 WPF 应用程序。

编辑: 这是我的数据对象,它是一个简单的 POCO。PaymentDate 使用 DateTime.Today 进行初始化,因此永远不会为空。

public class OnetimeExpense : NotifyPropertyChanged
{
    /**
     * int Id
     * string Name
     * DateTime PaymentDate
     * decimal Amount
     * Boolean IsPaid
     * */
    #region getters and setters

    private int id;
    [PrimaryKey, AutoIncrement]
    public int Id
    {
        get { return id; }
        set
        {
            this.id = value;
            this.OnPropertyChanged("Id");
        }
    }

    private DateTime paymentDate = DateTime.Today;
    public DateTime PaymentDate
    {
        get { return this.paymentDate; }
        set
        {
            paymentDate = value;
            this.OnPropertyChanged("PaymentDate");
        }
    }

    private bool isPaid;
    public bool IsPaid
    {
        get { return this.isPaid; }
        set
        {
            this.isPaid = value;
            this.OnPropertyChanged("IsPaid");
        }
    }

    #endregion

    #region Constructor

    public OnetimeExpense(string name, decimal amount, DateTime paymentDate, bool isPaid)
    {
        this.name = name;
        this.paymentDate = paymentDate;
        this.amount = amount;
        this.isPaid = isPaid;
    }

    public OnetimeExpense()
    {
    }

    #endregion
}


Edit2 Gert Arnold 建议使用这项工作。据我了解,它正在工作并且具有比我的查询更好的性能。不过,我想知道上面的查询有什么问题。

public List<OnetimeExpense> RetrieveItems(int month, int year, bool isPaid)
{
    var onetimeExpenses = new List<OnetimeExpense>();

    var lowerBound = new DateTime(year, month, 1);
    var upperBound = lowerBound.AddMonths(1);

    connection.RunInTransaction(() =>
    {
        var items = from s in connection.Table<OnetimeExpense>()
                    where s.PaymentDate >= lowerBound
                       && s.PaymentDate < upperBound
                       && s.IsPaid == isPaid
                    select s;
        onetimeExpenses = items.ToList();
    });

    return onetimeExpenses;
}
4

2 回答 2

2

不是直接的解决方案,但您可以通过不同的过滤来规避问题。假设您要过滤 2013 年 5 月的记录:

var lowerBound = new DateTime(2013,5,1);
var upperBound = new DateTime(2013,6,1);

var items = from s in connection.Table<OnetimeExpense>()
            where s.PaymentDate >= lowerBound
               && s.PaymentDate < upperBound
               && s.IsPaid == isPaid
            select s;

这不仅仅是回避问题。当有索引时,它也有可能使查询更有效PaymentDate。像这样的表达式convertedDate.Year被翻译成DATEPART(Year, [t0].[PaymentDate]). 这样的表达式不是sargable,即数据库引擎不能使用索引进行查找。

于 2013-05-18T23:48:42.230 回答
0
 if (LoggingFilter.StartDate.HasValue)
            {
                logs = auditlogs.Where(x => x.DateTime > auditLoggingFilter.StartDate).ToList();
            }
            if (LoggingFilter.EndDate.HasValue)
            {
                LoggingFilter.EndDate = LoggingFilter.EndDate.Value.AddTicks(DateTime.Now.TimeOfDay.Ticks);
                logs = auditlogs.Where(x => x.DateTime < LoggingFilter.EndDate).ToList();
            }

这对我有用。

于 2020-08-31T12:23:33.093 回答