2017-06-29 96 views
2

有一個Basket,它存儲List<Fruit>。每個Fruit有一個Pip。如果我保存這個關係,以後檢索時,ForeignKeyPipId具有價值,但對象Pipnull,儘管我用CascadeReadSQLite:從列表中的對象中檢索子元素

如果我嘗試使用上FruitListCascadeOperation.All我得到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 

此外,我試圖在InsertWithChildrenAsync()使用recursive: true,但Pipnull。這裏是例子:

數據模型

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

回答

1

現在我讀的documentation,並且聲明

級聯讀操作允許您從數據庫中獲取了完整的關係樹開始在您獲取的對象,並使用持續的所有關係與CascadeOperations集到CascadeRead

Fruit類現在看起來是這樣的

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

它按預期工作。我想,如果我有一個object,其中有一些進一步的關係CascadeRead只需要的,但事實並非如此。您需要所有對象上的CascadeRead,這些對象應該遞歸獲取,而不管對象是如何構建的。