2

LINQ 経由でデータベース アイテムのクエリを実行しようとしましたが、うまくいきません。例外は次のとおりです。

オブジェクト参照がオブジェクト インスタンスに設定されていません。

スタック トレースは、例外自体と同じくらい役に立ちません。

SQLite.TableQuery 1.CompileExpr(Expression expr, List1 queryArgs) で d:\XX\XX\XX\XX\XX\SQLite.cs:line 2383 で SQLite.TableQuery 1.CompileExpr(Expression expr, List1 queryArgs) で d:\XX\XX\XX\XX\XX\SQLite. cs:SQLite.TableQuery 1.CompileExpr(Expression expr, List1 queryArgs の 2388 行目 d:\XX\XX\XX\XX\XX\SQLite.cs:SQLite.TableQuery 1.CompileExpr(Expression expr, List1 queryArgs の 2308 行目 d:\XX\XX\XX\XX\ XX\SQLite.cs: 1.CompileExpr(Expression expr, Listd:\XX\XX\XX\XX\XX\SQLite.cs: 1.GenerateCommand(String selectionList) in d:\XX\XX\XX\XX\XX\SQLite.cs:line 2274 at SQLite.TableQueryd:\XX\ の SQLite.TableQuery 1.GetEnumerator() の2308 行の SQLite.TableQuery 1 queryArgs) の 2308 行XX\XX\XX\XX\SQLite.cs: System.Collections.Generic.List 1..ctor(IEnumerable1 コレクションの 2521 行目)
System.Linq.Enumerable.ToList[TSource](IEnumerable`1 ソース) で 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(Int32 month, Int32 year, Boolean isPaid の 906 行目) ) 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 で初期化されるため、null になることはありません。

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 に答える