2017-09-05 3 views
0

J'utilise SQLite dans mon application (via le package System.Data.SQLite). En ce moment, toutes les requêtes d'insertion, et d'autres opérations sont effectuées en envoyant des commandes à l'aide de chaînes, par exemple:Gestion de SQLite en C# - avancement des manipulations de chaîne de passe en tant que commandes

 SQLiteCommand command = new SQLiteCommand(comStr, db); 

où comStr - est une variable de chaîne contenant la commande.

Existe-t-il d'autres options que je peux utiliser à la place des chaînes? Ou les chaînes sont-elles les bonnes méthodes à utiliser lors du traitement des requêtes SQL à partir de .NET? Le problème est que l'utilisation des chaînes peut devenir plutôt salissante, par exemple j'ai quelques filtres que l'utilisateur peut définir. La commande en utilisant la manipulation des cordes - bien que les travaux - me sent très fragile:

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

Eh bien, au moins vous pouvez utiliser les paramètres pour commencer. – Fildor

+0

Et peut-être jeter un oeil à SqlCommandBuilder. – Fildor

+0

Je suppose qu'il veut utiliser LINQ. –

Répondre

0

Depuis que je ne l'ai pas obtenu une réponse satisfaisante, je vais poster ce que je fini par faire. Je pense que c'est probablement une manière décente, mais il pourrait y avoir d'autres meilleures façons d'atteindre ce que je cherchais (en utilisant la syntaxe de type LINQ sur ma base de données, au lieu d'utiliser des chaînes contenant des requêtes).

Aussi - Je ne suis pas sûr que ce soit plus rapide, puis simplement en utilisant des chaînes de requête. TL; DR: utilisez SQLite.CodeFirst + EntityFramework.

(D'un autre côté, il pourrait être possible d'utiliser LINQ to SQL au lieu de EntityFramework, mais je ne sais pas si c'est aussi une approche CodeFirst.) Je mettrai à jour une fois que j'ai essayé et testé.


chose d'abord, vous devez ajouter ces paquets:

  • Entity Framework
  • System.Data.SQLite (qui installera probablement aussi :)
  • System.Data.SQLite.Noyau
  • System.Data.SQLite.EF6
  • System.Data.SQLite.Linq

Et enfin, si vous commencez à partir du code (comme moi), vous aurez également besoin

  • SQLite.CodeFirst

la prochaine chose à faire est de mettre en place la chaîne de connexion dans app.config.

(Sur une note de côté - Il semble y avoir des tonnes de bogues avec les fournisseurs, ce que la désinstallation et la réinstallation des paquets ci-dessus semble corriger. - si vous tenez à ce que je l'ai écrit, c'est ceci:

<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> 

)

La chaîne de connexion doit spécifier un nom, et au moins un chemin où votre fichier DB doit être situé. Vous pouvez également utiliser des chemins relatifs que vous définissez ultérieurement dans le code (en utilisant le | DataDirectory | syntaxe):

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

L'étape suivante, si vous faites de code d'abord, est la création d'une nouvelle classe qui soit votre modèle, cela utilise essentiellement le paquet SQLite.CodeFirst:

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. 
} 

}

Vous pouvez en lire davantage here.

Et c'est fondamentalement cela avec les préparations.

(Sur une note de côté, si vous voulez changer le chemin relatif au fichier DB à partir du code derrière, vous devez écrire:

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

)

Maintenant, vous pouvez simplement utiliser il.La syntaxe de base est très simple, il suffit d'utiliser:

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

Alors Sélectionnez:

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

Si vous voulez Insérer:

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

Si vous voulez encore utiliser des requêtes de chaîne:

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

Certaines choses importantes à retenir:

  • Si vous changez quelque chose dans le DB, vous devez appeler Context.SaveChange() à la fin (vous n'avez pas besoin pour ce ExecuteSqlCommand)
  • La suppression peut se faire avec RemoveRange + SaveChange() ou en utilisant toujours une chaîne de requête.

Ainsi, l'exemple dans les changements de GetFilterString question à:

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 pour fournir une solution en réponse.

Ce tutoriel vous montre comment implémenter correctement SQLite et utiliser les extensions Linq pour interagir avec vos tables de base de données. J'ai copié les parties pertinentes ci-dessous. Une fois que votre connexion à la base de données est ouverte et que vous avez créé vos premières tables de données, vous pouvez alors interagir avec la table comme avec n'importe quel IEnumerable avec Linq. Il fournit également une option de passer en SQL comme une chaîne, mais comme cela n'est pas vérifié au moment de la compilation, vous courez le risque d'avoir des erreurs d'exécution.

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

Le constructeur de TodoItemDatabase est illustré ci-dessous:

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

Cette approche crée une seule connexion de base de données qui est maintenue ouverte pendant l'exécution de l'application, évitant ainsi les frais d'ouverture et de fermeture du fichier de base de données chaque fois qu'une opération de base de données est effectuée. Le reste de la classe TodoItemDatabase contient des requêtes SQLite qui s'exécutent sur plusieurs plates-formes. Exemple code de requête est présentée ci-dessous (plus de détails sur la syntaxe se trouvent dans l'utilisation de l'article SQLite.NET):

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

Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et fournir le lien pour référence. Les réponses à lien uniquement peuvent devenir invalides si la page liée change. - [De l'examen] (/ review/low-quality-posts/17239331) –

+0

J'ai copié certaines des informations de cette page de tutoriel, Comme il a la connexion à la base de données, les parties restantes devraient être triviales. – Joagwa

+0

Eh bien, c'est un package et une classe différente (ne pas avoir SQLiteAsyncConnection) mais je pense que je peux y repérer que vous utilisez simplement des expressions LINQ régulières sur l'objet DB. Je vais essayer pour voir si cela fonctionne. –