c# - SQLite:从列表中的对象中检索子元素

标签 c# sqlite xamarin sqlite-net sqlite-net-extensions

有一个Basket , 它存储一个 List<Fruit> .每个Fruit有一个Pip .如果我存储此关系并稍后检索它,ForeignKey PipId有一个值,但是对象 Pipnull ,尽管我使用 CascadeRead .

如果我尝试使用 CascadeOperation.AllFruitList我得到 Constraint

  at SQLite.PreparedSqlLiteInsertCommand.ExecuteNonQuery (System.Object[] source) [0x00116] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:2507 
  at SQLite.SQLiteConnection.Insert (System.Object obj, System.String extra, System.Type objType) [0x0014b] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:1386 
  at SQLite.SQLiteConnection.Insert (System.Object obj) [0x00008] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:1224 
  at SQLiteNetExtensions.Extensions.WriteOperations.InsertElement (SQLite.SQLiteConnection conn, System.Object element, System.Boolean replace, System.Reflection.PropertyInfo primaryKeyProperty, System.Boolean isAutoIncrementPrimaryKey, System.Collections.Generic.ISet`1[T] objectCache) [0x0005a] in C:\home\mk\work\frameworks\sqlite-net-extensions\SQLiteNetExtensions\Extensions\WriteOperations.cs:270 
  at SQLiteNetExtensions.Extensions.WriteOperations.InsertElements (SQLite.SQLiteConnection conn, System.Collections.IEnumerable elements, System.Boolean replace, System.Collections.Generic.ISet`1[T] objectCache) [0x00069] in C:\home\mk\work\frameworks\sqlite-net-extensions\SQLiteNetExtensions\Extensions\WriteOperations.cs:238 
  at SQLiteNetExtensions.Extensions.WriteOperations.InsertValue (SQLite.SQLiteConnection conn, System.Object value, System.Boolean replace, System.Boolean recursive, System.Collections.Generic.ISet`1[T] objectCache) [0x0002c] in C:\home\mk\work\frameworks\sqlite-net-extensions\SQLiteNetExtensions\Extensions\WriteOperations.cs:219 
  at SQLiteNetExtensions.Extensions.WriteOperations.InsertChildrenRecursive (SQLite.SQLiteConnection conn, System.Object element, System.Boolean replace, System.Boolean recursive, System.Collections.Generic.ISet`1[T] objectCache) [0x0004c] in C:\home\mk\work\frameworks\sqlite-net-extensions\SQLiteNetExtensions\Extensions\WriteOperations.cs:200 
  at SQLiteNetExtensions.Extensions.WriteOperations.InsertWithChildrenRecursive (SQLite.SQLiteConnection conn, System.Object element, System.Boolean replace, System.Boolean recursive, System.Collections.Generic.ISet`1[T] objectCache) [0x0002b] in C:\home\mk\work\frameworks\sqlite-net-extensions\SQLiteNetExtensions\Extensions\WriteOperations.cs:181 
  at SQLiteNetExtensions.Extensions.WriteOperations.InsertWithChildren (SQLite.SQLiteConnection conn, System.Object element, System.Boolean recursive) [0x00000] in C:\home\mk\work\frameworks\sqlite-net-extensions\SQLiteNetExtensions\Extensions\WriteOperations.cs:59 
  at SQLiteNetExtensionsAsync.Extensions.WriteOperations+<>c__DisplayClass1_0.<InsertWithChildrenAsync>b__0 () [0x00013] in C:\home\mk\work\frameworks\sqlite-net-extensions\SQLiteNetExtensionsAsync-PCL\Extensions\WriteOperations.cs:55 
  at System.Threading.Tasks.Task.InnerInvoke () [0x0000f] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.Threading.Tasks.Task.Execute () [0x00010] in <d18287e1d683419a8ec3216fd78947b9>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0 
  at TestSQLite.Database+<StoreBasketAsync>d__5.MoveNext () [0x0021b] in C:\Users\some-user\Documents\Visual Studio 2015\Projects\TestSQLite\TestSQLite\TestSQLite\Database.cs:189 

此外,我尝试使用 recursive: trueInsertWithChildrenAsync() ,但是 Pip也是null .这是示例:

数据模型

public class Basket
{
    private string number;
    private List<Fruit> fruitList;

    [PrimaryKey]
    public string Number
    {
        get { return this.number; }
        set { this.number = value; }
    }

    public string Name { get; set; }

    [OneToMany(CascadeOperations = CascadeOperation.CascadeRead)]
    public List<Fruit> FruitList
    {
        get { return this.fruitList; }
        set { this.fruitList = value; }
    }

    public Basket()
    {

    }
}

public class Fruit
{
    private string number;
    private Pip pip;

    [PrimaryKey]
    public string Number
    {
        get { return this.number; }
        set { this.number = value; }
    }

    public string Type { get; set;}

    [ForeignKey(typeof(Pip))]
    public string PipId { get; set; }

    [OneToOne]
    public Pip Pip
    {
        get { return this.pip; }
        set { this.pip = value; }
    }

    [ForeignKey(typeof(Basket))]
    public string BasketId { get; set; }

    public Fruit()
    {  
    }

}

public class Pip
{

    private string number;
    private string title;

    [PrimaryKey]
    public string Number
    {
        get { return this.number; }
        set { this.number = value; }
    }

    public string Title
    {
        get { return this.title; }
        set { this.title = value; }
    }

    public Pip()
    {

    }
}

数据库操作

public class Database
{
    private readonly SQLiteAsyncConnection database;

    public Database(string databasePath)
    {
        this.database = new SQLiteAsyncConnection(databasePath);
        this.database.CreateTableAsync<Basket>().Wait();
        this.database.CreateTableAsync<Fruit>().Wait();
        this.database.CreateTableAsync<Pip>().Wait();
    }

    public async Task<Basket> GetBasketAsync(string basketId)
    {
        try
        {
            var queryResult = await this.database.Table<Basket>().Where(b => b.Number == basketId).CountAsync();
            if (queryResult > 0)
            {
                return await this.database.GetWithChildrenAsync<Basket>(basketId, true);
            }
            else
            {
                return null;
            }
        }
        catch(Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
            return null;
        }
    }

    public async Task<Fruit> GetFruitAsync(string number)
    {
        try
        {
            var queryResult = await this.database.Table<Fruit>().Where(f => f.Number == number).CountAsync();
            if (queryResult > 0)
            {
                return await this.database.GetWithChildrenAsync<Fruit>(number, true);
            }
            else
            {
                return null;
            }
        }
        catch(Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
            return null;
        }
    }

    public async Task<Pip> GetPipAsync(string number)
    {
        try
        {
            var queryResult = await this.database.Table<Pip>().Where(p => p.Number == number).CountAsync();
            if (queryResult > 0)
            {
                return await this.database.GetAsync<Pip>(number);
            }
            else
            {
                return null;
            }
        }
        catch(Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
            return null;
        }
    }

    public async Task StoreBasketAsync(Basket basket)
    {
        if (basket == null)
            return;

        try
        {
            await this.StoreFruitListAsync(basket.FruitList);

            var foundItem = await this.GetBasketAsync(basket.Number);
            if (foundItem != null)
            {
                await this.database.UpdateWithChildrenAsync(basket);
            }
            else
            {
                await this.database.InsertWithChildrenAsync(basket);
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }
    }

    public async Task StoreFruitListAsync(List<Fruit> fruitList)
    {
        if (fruitList == null || fruitList.Count == 0)
            return;

        try
        {
            foreach (Fruit fruit in fruitList)
            {
                await this.StorePipAsync(fruit.Pip);

                var foundItem = await this.GetFruitAsync(fruit.Number);
                if (foundItem != null)
                {
                    await this.database.UpdateWithChildrenAsync(fruit);
                }
                else
                {
                    await this.database.InsertWithChildrenAsync(fruit);
                }
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }
    }

    public async Task<int> StorePipAsync(Pip pip)
    {
        if (pip == null)
            return 0;

        try
        {
            var foundItem = await this.GetPipAsync(pip.Number);
            if (foundItem != null)
            {
                return await this.database.UpdateAsync(pip);
            }
            else
            {
                return await this.database.InsertAsync(pip);
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
            return 0;
        }
    }
}

测试用例

public MainPage()
{
    InitializeComponent();

    Pip pip = new Pip();
    pip.Number = "4";
    pip.Title = "pip from apple";

    Fruit apple = new Fruit();
    apple.Number = "1";
    apple.Pip = pip;

    Basket basket = new Basket();
    basket.Number = "10";
    basket.Name = "grandma";
    basket.FruitList = new List<Fruit>() { apple };

    this.basket = basket;
}

protected override async void OnAppearing()
{
    base.OnAppearing();

    await App.Database.StoreBasketAsync(this.basket);
    Basket existingBasket = await App.Database.GetBasketAsync(this.basket.Number);
}

我正在使用最新的 SQLiteNetExtensions.Async v2.0.0-alpha2 NuGet 包。如何检索子元素 Pip正确吗?

最佳答案

现在我阅读了 documentation它指出

Cascade read operations allow you to fetch a complete relationship tree from the database starting at the object that you are fetching and continuing with all the relationships with CascadeOperations set to CascadeRead

我的 Fruit 类现在看起来像这样

public class Fruit
{
    [OneToOne(CascadeOperations = CascadeOperation.CascadeRead)]
    public Pip Pip
    {
        get { return this.pip; }
        set { this.pip = value; }
    }    
}

它按预期工作。我想,只有当我有一个 object 时才需要 CascadeRead,它有一些进一步的关系,但事实并非如此。您需要对所有对象使用 CascadeRead,无论对象是如何构建的,都应该递归获取这些对象。

关于c# - SQLite:从列表中的对象中检索子元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44820237/

相关文章:

c# - 遍历字符串?

c# - 如何使公共(public)方法仅在类本身和拥有 C# 中的对象的类中可见?

python - 如何使用Django存储历史数据

c# - Xamarin.Forms 填充 ListView

c# - 网格行高自动属性的奇怪行为

c# - 转换字典以供 javascript 使用

c# - LINQ 中的股票数据结转到第二天

java - 查询不返回任何数据 SQLite

Java-使用 SQLite 从列中选择某些行

xaml - 按钮内的 Xamarin.Forms TextBlock。自定义文本换行