2017-09-05 4 views
0

Ich verwende SQLite in meiner App (über das System.Data.SQLite-Paket). Gerade jetzt alle Insertion, Abfragen und andere Operationen werden durch Senden von Befehlen erfolgt Strings, zum Beispiel:Umgang mit SQLite in C# - Weiterleiten von Pass-String-Manipulationen als Befehle

 SQLiteCommand command = new SQLiteCommand(comStr, db); 

wo comStr - ist ein String-Variable hält den Befehl.

Gibt es andere Optionen, die ich anstelle von Strings verwenden kann? Oder sind Strings die richtige Art, die man verwenden sollte, wenn man SQL-Anfragen von .NET bearbeitet?

Das Problem ist, dass die Verwendung von Strings kann ziemlich chaotisch werden, zum Beispiel habe ich einige Filter, die der Benutzer einstellen kann. Manipulieren des Befehls mit den Zeichenfolgen - obwohl funktioniert - fühlt sich sehr spröde an:

public string GetFilterString() 
    { 
     string fil1 = ""; 
     string fil2 = ""; 
     string fil3 = ""; 
     string fil4 = ""; 

     // filter by time 
     switch (WithinTimeBtnStatus) 
     { 
      case WithinTime.All: 
       break; 
      case WithinTime.Hour: 
       string minusHour = (DateTime.Now - new TimeSpan(0, 1, 0, 0)).ToString("yyyy-MM-dd HH:mm:ss.fff"); 
       fil1 = $" timestamp >= datetime('{minusHour}')"; 
       break; 
      case WithinTime.Day: 
       string minusDay = (DateTime.Now - new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd HH:mm:ss.fff"); 
       fil1 = $" timestamp >= datetime('{minusDay}')"; 
       break; 
      case WithinTime.Week: 
       string minusWeek = (DateTime.Now - new TimeSpan(7, 0, 0, 0)).ToString("yyyy-MM-dd HH:mm:ss.fff"); 
       fil1 = $" timestamp >= datetime('{minusWeek}')"; 
       break; 
     } 

     // filter by extension 
     for (int i = 0; i < FilteredExt.Count; i++) 
     { 
      fil2 += " ext != '" + FilteredExt[i] + "'"; 
      if (i < FilteredExt.Count - 1) 
       fil2 += " and"; 
     } 

     // filter by process 
     if (_processFilterSelected.ToLower() != "all" && _processFilterSelected != "") 
     { 
      fil3 = $" proc == '{_processFilterSelected}'"; 
     } 

     // filter by File Operation 
     if (_FileOperationFilterSelected.ToLower() != "all" && _FileOperationFilterSelected != "") 
     { 
      FileOperation fo = Converters.StringToFileOperation(_FileOperationFilterSelected); 
      switch (fo) 
      { 
       case FileOperation.Deleted: 
        fil4 = " oper == 'DELETED'"; 
        break; 
       case FileOperation.Renamed: 
        fil4 = " oper == 'RENAMED'"; 
        break; 
       case FileOperation.Modified: 
        fil4 = " oper == 'MODIFIED'"; 
        break; 
      } 
     } 


     string fil = ""; 
     var tmp = new[] { fil1, fil2, fil3, fil4 }; 
     foreach (var t in tmp) 
     { 
      if (t != "") 
      { 
       fil += " and" + t; 
      } 
     } 

     return fil; 
    } 
+0

Nun, zumindest könnte man Parameter für den Anfang verwenden. – Fildor

+0

Und vielleicht sehen Sie sich SqlCommandBuilder an. – Fildor

+0

Ich denke, er möchte LINQ verwenden. –

Antwort

0

Da ich keine befriedigende Antwort erhalten habe, werde ich schreiben, was ich tun endete. Ich denke, das ist wahrscheinlich ein vernünftiger Weg, aber es könnte andere bessere Wege geben, um das zu erreichen, wonach ich gesucht habe (indem ich die LINQ-Syntax in meiner Datenbank verwende, anstatt Strings zu verwenden, die Abfragen enthalten).

Auch - ich bin nicht sicher, dass das schneller ist als einfach Abfragezeichenfolgen verwenden.

TL; DR: Verwenden Sie SQLite.CodeFirst + EntityFramework.

(Nebenbei bemerkt, es könnte möglich sein, LINQ to SQL anstelle von EntityFramework zu verwenden, aber nicht sicher, ob auch in einem CodeFirst-Ansatz. Wird aktualisiert, sobald ich dies getestet und getestet habe).


Das erste, was müssen Sie diese Pakete hinzuzufügen:

  • Entity Framework
  • System.Data.SQLite (die auch wahrscheinlich installieren :)
  • System.Data.SQLite.Kern
  • System.Data.SQLite.EF6
  • System.Data.SQLite.Linq

Und schließlich, wenn Sie aus dem Code beginnen (wie ich), müssen Sie auch

  • SQLite.CodeFirst

Das nächste, was die Verbindung zu tun Zeichenfolge in app.config eingerichtet ist.

(Eine Randnotiz - Es scheint Tonnen von Fehlern mit der Angabe der Anbieter zu geben, die die oben genannten Pakete zu deinstallieren und neu zu installieren scheint. Ich bin nicht so sicher über die Logik hinter Entfernen und Hinzufügen und invariante Namen - wenn Sie kümmern, was ich geschrieben habe, dann ist es das:

<system.data> 
    <DbProviderFactories> 
     <remove invariant="System.Data.SQLite.EF6" /> 
     <add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" /> 
     <remove invariant="System.Data.SQLite" /> 
     <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /> 
    </DbProviderFactories> 
</system.data> 

<entityFramework> 
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" /> 
    <providers> 
     <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> 
     <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" /> 
     <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6"/> 
    </providers> 
    </entityFramework> 

)

Die Verbindungszeichenfolge sollte einen Namen, und zumindest ein Weg, wo sollten Sie Ihre DB-Datei befinden. Sie können auch relative Pfade verwenden, die Sie später im Code definieren (durch die Verwendung | Datadirectory | Syntax):

<connectionStrings> 
    <add name="YourModel" connectionString="Data Source=|DataDirectory|\NameOfYourDBFile.sqlite" providerName="System.Data.SQLite" /> 
</connectionStrings> 

Der nächste Schritt, wenn Sie Code-First tun, wird eine neue Klasse zu schaffen, das wird sein Modell, das ist im Grunde mit dem SQLite.CodeFirst Paket:

class YourModel : DbContext 
{ 
    // Your context has been configured to use a 'YourModel' connection string from your application's 
    // configuration file (App.config or Web.config). By default, this connection string targets the 
    // 'YourProject.YourModel' database on your LocalDb instance. 
    // 
    // If you wish to target a different database and/or database provider, modify the 'YourModel' 
    // connection string in the application configuration file. 
    public YourModel() 
     : base("name=YourModel") 
    { 
    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     var sqliteConnectionInitializer = new SqliteCreateDatabaseIfNotExists<YourModel>(modelBuilder); 
     Database.SetInitializer(sqliteConnectionInitializer); 
     Database.SetInitializer(new SqliteDropCreateDatabaseWhenModelChanges<YourModel>(modelBuilder)); 
    } 

    // Add a DbSet for each entity type that you want to include in your model. For more information 
    // on configuring and using a Code First model, see http://go.microsoft.com/fwlink/?LinkId=390109. 

    public virtual DbSet<YourTableClass> YourTable { get; set; } 
} 

[Table("YourTable")] 
public class YourTableClass 
{ 
    [Key] 
    public string Id { get; set; } 
    [Required] 
    public FileOperation Oper { get; set; } 
    [Required, Index] 
    public OperationState State { get; set; } 
    [Index] 
    public string Proc { get; set; } 
    [Required] 
    public string Src { get; set; } 
    public DateTime Timestamp { get; set; } 
    // etc. 
} 

}

Sie können mehr darüber lesen here.

Und das ist es im Grunde genommen mit den Vorbereitungen.

(Auf einer Seite beachten, wenn Sie den relativen Pfad zu der DB-Datei von Code hinter ändern möchten, müssen Sie schreiben:

AppDomain.CurrentDomain.SetData("DataDirectory", @"the\path\you\desire"); 

)

Jetzt können Sie nur verwenden, es.Die grundlegende Syntax sehr einfach ist, verwenden Sie einfach:

using (var context = new YourModel()) 
{ 
    // some query 
} 

So Select:

using (var context = new YourModel()) 
{ 
    var t = context.YourTable 
     .Where(e => e.State == OperationState.BackedUp) 
     .Select(e => e.Proc) 
     .Distinct() 
} 

Wenn Sie wollen Insert:

using (var context = new YourModel()) 
{ 
    var e = context.YourTable.Create(); 
    e.Id = guid; 
    // ...etc 
    e.Timestamp = timestamp; 
    context.YourTable.Add(e); 
    context.SaveChanges(); 
} 

Wenn Sie wollen immer noch Verwenden Sie String-Abfragen:

using (var context = new YourModel()) 
{ 
    context.Database.ExecuteSqlCommand(comString); 
} 

einige wichtige Dinge erinnern:

  • Wenn Sie etwas in der DB zu ändern, müssen Sie Context.SaveChange() am Ende nennen (Sie dies für ExecuteSqlCommand nicht brauchen)
  • Löschen mit getan werden kann, RemoveRange + SaveChange() oder indem weiterhin eine Abfragezeichenfolge verwendet wird.

So das Beispiel in der Frage GetFilterString Änderungen:

public static IQueryable<YourTable> GetFilteredQueryable(IQueryable<YourTable> yourTable) 
    { 
     // filter by time 
     switch (RestoreLogic.WithinTimeBtnStatus) 
     { 
      case WithinTime.All: 
       break; 
      case WithinTime.Hour: 
       DateTime offsetHour = DateTime.Now.Add(new TimeSpan(-1, 0, 0)); 
       yourTable = yourTable.Where(e => e.Timestamp >= offsetHour); 
       break; 
      // etc. 
     } 

     // filter by extension 
     foreach (var i in FilteredExt) 
     { 
      yourTable = yourTable.Where(e => e.Ext != i); 
     } 

     // etc. 

     return yourTable; 
    } 
-2

EDIT, um eine Lösung in Antwort zu bieten.

Dieses Tutorial zeigt Ihnen, wie Sie SQLite richtig implementieren und Linq-Erweiterungen verwenden, um mit Ihren Datenbanktabellen zu interagieren. Ich habe die relevanten Teile unten kopiert. Sobald Sie Ihre Datenbankverbindung geöffnet haben und Ihre ersten Datenbanktabellen erstellt haben, können Sie mit der Tabelle wie mit jedem IEnumerable mit Linq interagieren. Es bietet auch die Möglichkeit, SQL als Zeichenfolge zu übergeben. Da dies jedoch zur Kompilierungszeit nicht überprüft wird, besteht das Risiko von Laufzeitfehlern.

https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/databases/

Der TodoItemDatabase Konstruktor wird unten dargestellt:

public TodoItemDatabase(string dbPath) 
{ 
    database = new SQLiteAsyncConnection(dbPath); 
    database.CreateTableAsync<TodoItem>().Wait(); 
} 

Dieser Ansatz schafft eine einzelne Datenbankverbindung, die offen gehalten wird, während die Anwendung ausgeführt wird, damit die Kosten der Öffnung zu vermeiden und die Datenbankdatei zu schließen jedes Mal, wenn eine Datenbankoperation ausgeführt wird. Der Rest der TodoItemDatabase-Klasse enthält SQLite-Abfragen, die plattformübergreifend ausgeführt werden. Beispiel Abfrage-Code ist unten dargestellt (weitere Informationen zur Syntax finden Sie in der Verwendung SQLite.NET Artikels zu finden):

public Task<List<TodoItem>> GetItemsAsync() 
{ 
    return database.Table<TodoItem>().ToListAsync(); 
} 

public Task<List<TodoItem>> GetItemsNotDoneAsync() 
{ 
    return database.QueryAsync<TodoItem>("SELECT * FROM [TodoItem] WHERE [Done] = 0"); 
} 

public Task<TodoItem> GetItemAsync(int id) 
{ 
    return database.Table<TodoItem>().Where(i => i.ID == id).FirstOrDefaultAsync(); 
} 

public Task<int> SaveItemAsync(TodoItem item) 
{ 
    if (item.ID != 0) 
    { 
    return database.UpdateAsync(item); 
    } 
    else { 
    return database.InsertAsync(item); 
    } 
} 

public Task<int> DeleteItemAsync(TodoItem item) 
{ 
    return database.DeleteAsync(item); 
} 
+0

Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz zur Verfügung zu stellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - [Aus Bewertung] (/ review/low-quality-posts/17239331) –

+0

Ich habe einige Informationen von dieser Tutorial-Seite kopiert, da er die Datenbankverbindung hat, sollten die restlichen Teile trivial sein. – Joagwa

+0

Nun, es ist ein anderes Paket und eine andere Klasse (habe keine SQLiteAsyncConnection), aber ich denke, ich kann dort erkennen, dass Sie einfach reguläre LINQ-Ausdrücke für das DB-Objekt verwenden. Ich werde es versuchen, um zu sehen, ob das funktioniert. –