Xamarin.Mac'teki veritabanları
Bu makale, Xcode'un Arabirim Oluşturucusu'ndaki SQLite veritabanları ile kullanıcı arabirimi öğeleri arasında veri bağlamaya olanak sağlamak için anahtar-değer kodlama ve anahtar-değer gözlemleme özelliklerini kullanmayı kapsar. Ayrıca SQLite verilerine erişim sağlamak için SQLite.NET ORM'nin kullanılmasını da kapsar.
Genel bakış
Bir Xamarin.Mac uygulamasında C# ve .NET ile çalışırken, Xamarin.iOS veya Xamarin.Android uygulamasının erişebildiği SQLite veritabanlarına erişebilirsiniz.
Bu makalede SQLite verilerine erişmenin iki yolunu kapsayacağız:
- Doğrudan Erişim - SQLite Veritabanına doğrudan erişerek, anahtar-değer kodlaması ve Xcode'un Arabirim Oluşturucusu'nda oluşturulan kullanıcı arabirimi öğeleriyle veri bağlama için veritabanındaki verileri kullanabiliriz. Xamarin.Mac uygulamanızda anahtar-değer kodlama ve veri bağlama tekniklerini kullanarak, kullanıcı arabirimi öğelerini doldurmak ve bunlarla çalışmak için yazmanız ve korumanız gereken kod miktarını büyük ölçüde azaltabilirsiniz. Ayrıca, destek verilerinizi (Veri Modeli) ön uç Kullanıcı Arabiriminizden (Model-Görünüm-Denetleyici) daha fazla ayırmanın avantajına da sahip olursunuz ve bu sayede bakımı daha kolay ve daha esnek bir uygulama tasarımı elde edebilirsiniz.
- SQLite.NET ORM - açık kaynak SQLite.NET Nesne İlişki Yöneticisi'ni (ORM) kullanarak SQLite veritabanından veri okumak ve yazmak için gereken kod miktarını büyük ölçüde azaltabiliriz. Bu veriler daha sonra Tablo Görünümü gibi bir kullanıcı arabirimi öğesini doldurmak için kullanılabilir.
Bu makalede, Xamarin.Mac uygulamasında anahtar-değer kodlama ve SQLite Veritabanları ile veri bağlama ile çalışmanın temellerini ele alacağız. Bu makalede kullanacağımız temel kavramları ve teknikleri kapsarken öncelikle Hello, Mac makalesi, özellikle Xcode ve Interface Builder'a Giriş ve Çıkışlar ve Eylemler bölümleriyle çalışmanız önemle önerilir.
Anahtar-değer kodlaması ve veri bağlamayı kullanacağımızdan, bu belgelerde ve örnek uygulamasında kullanılacak temel teknikler ve kavramlar ele alınacağı için lütfen önce Veri bağlama ve anahtar-değer kodlaması ile çalışın.
Xamarin.Mac Internals belgesinin C# sınıflarını / yöntemlerini kullanıma alma Objective-C bölümüne de göz atmak isteyebilirsiniz. Bu belge, C# sınıflarınızı nesnelere ve ui öğelerine bağlamak için Objective-C kullanılan ve Export
özniteliklerini açıklar.Register
Doğrudan SQLite erişimi
Xcode'un Arabirim Oluşturucusu'ndaki kullanıcı arabirimi öğelerine bağlanacak SQLite verileri için, verilerin veritabanından yazılma ve okunma şekli üzerinde tam denetime sahip olduğunuzdan, SQLite veritabanına doğrudan erişmeniz önerilir (ORM gibi bir teknik kullanmak yerine).
Veri Bağlama ve Anahtar-Değer Kodlama belgelerinde gördüğümüz gibi, Xamarin.Mac uygulamanızda anahtar-değer kodlama ve veri bağlama tekniklerini kullanarak, kullanıcı arabirimi öğelerini doldurmak ve bunlarla çalışmak için yazmanız ve korumanız gereken kod miktarını büyük ölçüde azaltabilirsiniz. SQLite veritabanına doğrudan erişimle birlikte kullanıldığında, verileri okumak ve veritabanına yazmak için gereken kod miktarını da büyük ölçüde azaltabilir.
Bu makalede, veri bağlama ve anahtar-değer kodlama belgesindeki örnek uygulamayı bağlamanın arka kaynağı olarak bir SQLite Veritabanı kullanacak şekilde değiştireceğiz.
SQLite veritabanı desteği dahil
Devam etmeden önce, başvurularını birkaç öğesine ekleyerek uygulamamıza SQLite veritabanı desteği eklememiz gerekir. DLL dosyaları.
Aşağıdakileri yapın:
Çözüm Bölmesi'nde Başvurular klasörüne sağ tıklayın ve Başvuruları Düzenle'yi seçin.
Mono.Data.Sqlite ve System.Data derlemelerini seçin:
Değişikliklerinizi kaydetmek ve başvuruları eklemek için Tamam düğmesine tıklayın.
Veri modelini değiştirme
Artık uygulamamıza bir SQLite veritabanına doğrudan erişme desteği eklediğimize göre, Veri Modeli Nesnemizi veritabanındaki verileri okuyacak ve yazacak şekilde değiştirmemiz (anahtar-değer kodlaması ve veri bağlaması sağlamamız) gerekir. Örnek uygulamamız söz konusu olduğunda, PersonModel.cs sınıfını düzenleyeceğiz ve aşağıdaki gibi görünmesini sağlayacağız:
using System;
using System.Data;
using System.IO;
using Mono.Data.Sqlite;
using Foundation;
using AppKit;
namespace MacDatabase
{
[Register("PersonModel")]
public class PersonModel : NSObject
{
#region Private Variables
private string _ID = "";
private string _managerID = "";
private string _name = "";
private string _occupation = "";
private bool _isManager = false;
private NSMutableArray _people = new NSMutableArray();
private SqliteConnection _conn = null;
#endregion
#region Computed Properties
public SqliteConnection Conn {
get { return _conn; }
set { _conn = value; }
}
[Export("ID")]
public string ID {
get { return _ID; }
set {
WillChangeValue ("ID");
_ID = value;
DidChangeValue ("ID");
}
}
[Export("ManagerID")]
public string ManagerID {
get { return _managerID; }
set {
WillChangeValue ("ManagerID");
_managerID = value;
DidChangeValue ("ManagerID");
}
}
[Export("Name")]
public string Name {
get { return _name; }
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
// Save changes to database?
if (_conn != null) Update (_conn);
}
}
[Export("Occupation")]
public string Occupation {
get { return _occupation; }
set {
WillChangeValue ("Occupation");
_occupation = value;
DidChangeValue ("Occupation");
// Save changes to database?
if (_conn != null) Update (_conn);
}
}
[Export("isManager")]
public bool isManager {
get { return _isManager; }
set {
WillChangeValue ("isManager");
WillChangeValue ("Icon");
_isManager = value;
DidChangeValue ("isManager");
DidChangeValue ("Icon");
// Save changes to database?
if (_conn != null) Update (_conn);
}
}
[Export("isEmployee")]
public bool isEmployee {
get { return (NumberOfEmployees == 0); }
}
[Export("Icon")]
public NSImage Icon {
get {
if (isManager) {
return NSImage.ImageNamed ("group.png");
} else {
return NSImage.ImageNamed ("user.png");
}
}
}
[Export("personModelArray")]
public NSArray People {
get { return _people; }
}
[Export("NumberOfEmployees")]
public nint NumberOfEmployees {
get { return (nint)_people.Count; }
}
#endregion
#region Constructors
public PersonModel ()
{
}
public PersonModel (string name, string occupation)
{
// Initialize
this.Name = name;
this.Occupation = occupation;
}
public PersonModel (string name, string occupation, bool manager)
{
// Initialize
this.Name = name;
this.Occupation = occupation;
this.isManager = manager;
}
public PersonModel (string id, string name, string occupation)
{
// Initialize
this.ID = id;
this.Name = name;
this.Occupation = occupation;
}
public PersonModel (SqliteConnection conn, string id)
{
// Load from database
Load (conn, id);
}
#endregion
#region Array Controller Methods
[Export("addObject:")]
public void AddPerson(PersonModel person) {
WillChangeValue ("personModelArray");
isManager = true;
_people.Add (person);
DidChangeValue ("personModelArray");
}
[Export("insertObject:inPersonModelArrayAtIndex:")]
public void InsertPerson(PersonModel person, nint index) {
WillChangeValue ("personModelArray");
_people.Insert (person, index);
DidChangeValue ("personModelArray");
}
[Export("removeObjectFromPersonModelArrayAtIndex:")]
public void RemovePerson(nint index) {
WillChangeValue ("personModelArray");
_people.RemoveObject (index);
DidChangeValue ("personModelArray");
}
[Export("setPersonModelArray:")]
public void SetPeople(NSMutableArray array) {
WillChangeValue ("personModelArray");
_people = array;
DidChangeValue ("personModelArray");
}
#endregion
#region SQLite Routines
public void Create(SqliteConnection conn) {
// Clear last connection to prevent circular call to update
_conn = null;
// Create new record ID?
if (ID == "") {
ID = Guid.NewGuid ().ToString();
}
// Execute query
conn.Open ();
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "INSERT INTO [People] (ID, Name, Occupation, isManager, ManagerID) VALUES (@COL1, @COL2, @COL3, @COL4, @COL5)";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", ID);
command.Parameters.AddWithValue ("@COL2", Name);
command.Parameters.AddWithValue ("@COL3", Occupation);
command.Parameters.AddWithValue ("@COL4", isManager);
command.Parameters.AddWithValue ("@COL5", ManagerID);
// Write to database
command.ExecuteNonQuery ();
}
conn.Close ();
// Save children to database as well
for (nuint n = 0; n < People.Count; ++n) {
// Grab person
var Person = People.GetItem<PersonModel>(n);
// Save manager ID and create the sub record
Person.ManagerID = ID;
Person.Create (conn);
}
// Save last connection
_conn = conn;
}
public void Update(SqliteConnection conn) {
// Clear last connection to prevent circular call to update
_conn = null;
// Execute query
conn.Open ();
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "UPDATE [People] SET Name = @COL2, Occupation = @COL3, isManager = @COL4, ManagerID = @COL5 WHERE ID = @COL1";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", ID);
command.Parameters.AddWithValue ("@COL2", Name);
command.Parameters.AddWithValue ("@COL3", Occupation);
command.Parameters.AddWithValue ("@COL4", isManager);
command.Parameters.AddWithValue ("@COL5", ManagerID);
// Write to database
command.ExecuteNonQuery ();
}
conn.Close ();
// Save children to database as well
for (nuint n = 0; n < People.Count; ++n) {
// Grab person
var Person = People.GetItem<PersonModel>(n);
// Update sub record
Person.Update (conn);
}
// Save last connection
_conn = conn;
}
public void Load(SqliteConnection conn, string id) {
bool shouldClose = false;
// Clear last connection to prevent circular call to update
_conn = null;
// Is the database already open?
if (conn.State != ConnectionState.Open) {
shouldClose = true;
conn.Open ();
}
// Execute query
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "SELECT * FROM [People] WHERE ID = @COL1";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", id);
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Pull values back into class
ID = (string)reader [0];
Name = (string)reader [1];
Occupation = (string)reader [2];
isManager = (bool)reader [3];
ManagerID = (string)reader [4];
}
}
}
// Is this a manager?
if (isManager) {
// Yes, load children
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "SELECT ID FROM [People] WHERE ManagerID = @COL1";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", id);
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Load child and add to collection
var childID = (string)reader [0];
var person = new PersonModel (conn, childID);
_people.Add (person);
}
}
}
}
// Should we close the connection to the database
if (shouldClose) {
conn.Close ();
}
// Save last connection
_conn = conn;
}
public void Delete(SqliteConnection conn) {
// Clear last connection to prevent circular call to update
_conn = null;
// Execute query
conn.Open ();
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "DELETE FROM [People] WHERE (ID = @COL1 OR ManagerID = @COL1)";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", ID);
// Write to database
command.ExecuteNonQuery ();
}
conn.Close ();
// Empty class
ID = "";
ManagerID = "";
Name = "";
Occupation = "";
isManager = false;
_people = new NSMutableArray();
// Save last connection
_conn = conn;
}
#endregion
}
}
Şimdi aşağıdaki değişikliklere ayrıntılı olarak göz atalım.
İlk olarak, SQLite kullanmak için gereken birkaç using deyimi ekledik ve SQLite veritabanına son bağlantımızı kaydetmek için bir değişken ekledik:
using System.Data;
using System.IO;
using Mono.Data.Sqlite;
...
private SqliteConnection _conn = null;
Kullanıcı kullanıcı arabirimindeki içeriği veri bağlama aracılığıyla değiştirdiğinde kayıttaki değişiklikleri otomatik olarak kaydetmek için bu kayıtlı bağlantıyı kullanacağız:
[Export("Name")]
public string Name {
get { return _name; }
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
// Save changes to database?
if (_conn != null) Update (_conn);
}
}
[Export("Occupation")]
public string Occupation {
get { return _occupation; }
set {
WillChangeValue ("Occupation");
_occupation = value;
DidChangeValue ("Occupation");
// Save changes to database?
if (_conn != null) Update (_conn);
}
}
[Export("isManager")]
public bool isManager {
get { return _isManager; }
set {
WillChangeValue ("isManager");
WillChangeValue ("Icon");
_isManager = value;
DidChangeValue ("isManager");
DidChangeValue ("Icon");
// Save changes to database?
if (_conn != null) Update (_conn);
}
}
Ad, Meslek veya isManager özelliklerinde yapılan tüm değişiklikler, veriler daha önce kaydedilmişse (örn. _conn
değişken değilsenull
) veritabanına gönderilir. Şimdi veritabanından kişi oluşturma, güncelleştirme, yükleme ve silme işlemlerine eklediğimiz yöntemlere göz atalım.
Yeni kayıt oluşturma
SQLite veritabanında yeni bir kayıt oluşturmak için aşağıdaki kod eklendi:
public void Create(SqliteConnection conn) {
// Clear last connection to prevent circular call to update
_conn = null;
// Create new record ID?
if (ID == "") {
ID = Guid.NewGuid ().ToString();
}
// Execute query
conn.Open ();
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "INSERT INTO [People] (ID, Name, Occupation, isManager, ManagerID) VALUES (@COL1, @COL2, @COL3, @COL4, @COL5)";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", ID);
command.Parameters.AddWithValue ("@COL2", Name);
command.Parameters.AddWithValue ("@COL3", Occupation);
command.Parameters.AddWithValue ("@COL4", isManager);
command.Parameters.AddWithValue ("@COL5", ManagerID);
// Write to database
command.ExecuteNonQuery ();
}
conn.Close ();
// Save children to database as well
for (nuint n = 0; n < People.Count; ++n) {
// Grab person
var Person = People.GetItem<PersonModel>(n);
// Save manager ID and create the sub record
Person.ManagerID = ID;
Person.Create (conn);
}
// Save last connection
_conn = conn;
}
Veritabanında yeni kayıt oluşturmak için bir SQLiteCommand
kullanıyoruz. çağrısı CreateCommand
yaparak yöntemine SQLiteConnection
geçirdiğimiz (conn) komutundan yeni bir komut alırız. Ardından, SQL yönergesini yeni kaydı gerçekten yazacak şekilde ayarlayarak gerçek değerler için parametreler sağlarız:
command.CommandText = "INSERT INTO [People] (ID, Name, Occupation, isManager, ManagerID) VALUES (@COL1, @COL2, @COL3, @COL4, @COL5)";
Daha sonra üzerindeki yöntemini SQLiteCommand
kullanarak parametrelerin Parameters.AddWithValue
değerlerini ayarlayacağız. Parametreleri kullanarak, değerlerin (tek tırnak gibi) SQLite'e gönderilmeden önce düzgün bir şekilde kodlanmasını sağlarız. Örnek:
command.Parameters.AddWithValue ("@COL1", ID);
Son olarak, bir kişi yönetici olabileceğinden ve altında bir çalışan koleksiyonu olabileceğinden, bu kişilerin veritabanına kaydetme yöntemini yinelemeli olarak çağırıyoruz Create
:
// Save children to database as well
for (nuint n = 0; n < People.Count; ++n) {
// Grab person
var Person = People.GetItem<PersonModel>(n);
// Save manager ID and create the sub record
Person.ManagerID = ID;
Person.Create (conn);
}
Kaydı güncelleştirme
SQLite veritabanındaki mevcut bir kaydı güncelleştirmek için aşağıdaki kod eklendi:
public void Update(SqliteConnection conn) {
// Clear last connection to prevent circular call to update
_conn = null;
// Execute query
conn.Open ();
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "UPDATE [People] SET Name = @COL2, Occupation = @COL3, isManager = @COL4, ManagerID = @COL5 WHERE ID = @COL1";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", ID);
command.Parameters.AddWithValue ("@COL2", Name);
command.Parameters.AddWithValue ("@COL3", Occupation);
command.Parameters.AddWithValue ("@COL4", isManager);
command.Parameters.AddWithValue ("@COL5", ManagerID);
// Write to database
command.ExecuteNonQuery ();
}
conn.Close ();
// Save children to database as well
for (nuint n = 0; n < People.Count; ++n) {
// Grab person
var Person = People.GetItem<PersonModel>(n);
// Update sub record
Person.Update (conn);
}
// Save last connection
_conn = conn;
}
Yukarıdaki Oluştur gibi, geçirilen SQLiteConnection
dosyasından bir SQLiteCommand
alır ve SQL'imizi kaydımızı güncelleştirecek şekilde ayarlarız (parametreler sağlar):
command.CommandText = "UPDATE [People] SET Name = @COL2, Occupation = @COL3, isManager = @COL4, ManagerID = @COL5 WHERE ID = @COL1";
Parametre değerlerini (örnek: command.Parameters.AddWithValue ("@COL1", ID);
) dolduruyoruz ve herhangi bir alt kayıtta yinelemeli olarak güncelleştirmeyi çağırıyoruz:
// Save children to database as well
for (nuint n = 0; n < People.Count; ++n) {
// Grab person
var Person = People.GetItem<PersonModel>(n);
// Update sub record
Person.Update (conn);
}
Kayıt yükleme
SQLite veritabanından var olan bir kaydı yüklemek için aşağıdaki kod eklendi:
public void Load(SqliteConnection conn, string id) {
bool shouldClose = false;
// Clear last connection to prevent circular call to update
_conn = null;
// Is the database already open?
if (conn.State != ConnectionState.Open) {
shouldClose = true;
conn.Open ();
}
// Execute query
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "SELECT * FROM [People] WHERE ID = @COL1";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", id);
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Pull values back into class
ID = (string)reader [0];
Name = (string)reader [1];
Occupation = (string)reader [2];
isManager = (bool)reader [3];
ManagerID = (string)reader [4];
}
}
}
// Is this a manager?
if (isManager) {
// Yes, load children
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "SELECT ID FROM [People] WHERE ManagerID = @COL1";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", id);
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Load child and add to collection
var childID = (string)reader [0];
var person = new PersonModel (conn, childID);
_people.Add (person);
}
}
}
}
// Should we close the connection to the database
if (shouldClose) {
conn.Close ();
}
// Save last connection
_conn = conn;
}
Yordam bir üst nesneden (çalışan nesnesini yükleyen bir yönetici nesnesi gibi) özyinelemeli olarak çağrılabildiğinden, veritabanı bağlantısını açma ve kapatma işlemini işlemek için özel kod eklendi:
bool shouldClose = false;
...
// Is the database already open?
if (conn.State != ConnectionState.Open) {
shouldClose = true;
conn.Open ();
}
...
// Should we close the connection to the database
if (shouldClose) {
conn.Close ();
}
Her zaman olduğu gibi SQL'imizi kaydı alacak ve parametreleri kullanacak şekilde ayarlayacağız:
// Create new command
command.CommandText = "SELECT ID FROM [People] WHERE ManagerID = @COL1";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", id);
Son olarak, sorguyu yürütmek ve kayıt alanlarını (sınıfın PersonModel
örneğine kopyaladığımız) döndürmek için veri okuyucu kullanırız:
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Pull values back into class
ID = (string)reader [0];
Name = (string)reader [1];
Occupation = (string)reader [2];
isManager = (bool)reader [3];
ManagerID = (string)reader [4];
}
}
Bu kişi bir yöneticiyse, tüm çalışanlarını da yüklememiz gerekir (yine, özyinelemeli olarak yöntemini çağırarak Load
):
// Is this a manager?
if (isManager) {
// Yes, load children
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "SELECT ID FROM [People] WHERE ManagerID = @COL1";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", id);
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Load child and add to collection
var childID = (string)reader [0];
var person = new PersonModel (conn, childID);
_people.Add (person);
}
}
}
}
Kayıt silme
Mevcut bir kaydı SQLite veritabanından silmek için aşağıdaki kod eklendi:
public void Delete(SqliteConnection conn) {
// Clear last connection to prevent circular call to update
_conn = null;
// Execute query
conn.Open ();
using (var command = conn.CreateCommand ()) {
// Create new command
command.CommandText = "DELETE FROM [People] WHERE (ID = @COL1 OR ManagerID = @COL1)";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", ID);
// Write to database
command.ExecuteNonQuery ();
}
conn.Close ();
// Empty class
ID = "";
ManagerID = "";
Name = "";
Occupation = "";
isManager = false;
_people = new NSMutableArray();
// Save last connection
_conn = conn;
}
Burada SQL'e yönetici kaydını ve bu yöneticinin altındaki çalışanların kayıtlarını (parametreleri kullanarak) silmesini sağlıyoruz:
// Create new command
command.CommandText = "DELETE FROM [People] WHERE (ID = @COL1 OR ManagerID = @COL1)";
// Populate with data from the record
command.Parameters.AddWithValue ("@COL1", ID);
Kayıt kaldırıldıktan sonra sınıfın geçerli örneğini PersonModel
temizleriz:
// Empty class
ID = "";
ManagerID = "";
Name = "";
Occupation = "";
isManager = false;
_people = new NSMutableArray();
Veritabanını başlatma
Veri Modelimizin veritabanında okunmasını ve yazmasını desteklemek için yapılan değişikliklerle, veritabanına bir bağlantı açıp ilk çalıştırmada başlatmamız gerekir. Şimdi MainWindow.cs dosyamıza aşağıdaki kodu ekleyelim:
using System.Data;
using System.IO;
using Mono.Data.Sqlite;
...
private SqliteConnection DatabaseConnection = null;
...
private SqliteConnection GetDatabaseConnection() {
var documents = Environment.GetFolderPath (Environment.SpecialFolder.Desktop);
string db = Path.Combine (documents, "People.db3");
// Create the database if it doesn't already exist
bool exists = File.Exists (db);
if (!exists)
SqliteConnection.CreateFile (db);
// Create connection to the database
var conn = new SqliteConnection("Data Source=" + db);
// Set the structure of the database
if (!exists) {
var commands = new[] {
"CREATE TABLE People (ID TEXT, Name TEXT, Occupation TEXT, isManager BOOLEAN, ManagerID TEXT)"
};
conn.Open ();
foreach (var cmd in commands) {
using (var c = conn.CreateCommand()) {
c.CommandText = cmd;
c.CommandType = CommandType.Text;
c.ExecuteNonQuery ();
}
}
conn.Close ();
// Build list of employees
var Craig = new PersonModel ("0","Craig Dunn", "Documentation Manager");
Craig.AddPerson (new PersonModel ("Amy Burns", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Joel Martinez", "Web & Infrastructure"));
Craig.AddPerson (new PersonModel ("Kevin Mullins", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Mark McLemore", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Tom Opgenorth", "Technical Writer"));
Craig.Create (conn);
var Larry = new PersonModel ("1","Larry O'Brien", "API Documentation Manager");
Larry.AddPerson (new PersonModel ("Mike Norman", "API Documentor"));
Larry.Create (conn);
}
// Return new connection
return conn;
}
Yukarıdaki koda daha yakından bakalım. İlk olarak, yeni veritabanı için bir konum seçiyoruz (bu örnekte kullanıcının Masaüstü), veritabanının var olup olmadığını görmek için bakın ve yoksa oluşturun:
var documents = Environment.GetFolderPath (Environment.SpecialFolder.Desktop);
string db = Path.Combine (documents, "People.db3");
// Create the database if it doesn't already exist
bool exists = File.Exists (db);
if (!exists)
SqliteConnection.CreateFile (db);
Ardından, yukarıda oluşturduğumuz yolu kullanarak veritabanına bağlanmayı kuracağız:
var conn = new SqliteConnection("Data Source=" + db);
Ardından veritabanında ihtiyacımız olan tüm SQL tablolarını oluştururuz:
var commands = new[] {
"CREATE TABLE People (ID TEXT, Name TEXT, Occupation TEXT, isManager BOOLEAN, ManagerID TEXT)"
};
conn.Open ();
foreach (var cmd in commands) {
using (var c = conn.CreateCommand()) {
c.CommandText = cmd;
c.CommandType = CommandType.Text;
c.ExecuteNonQuery ();
}
}
conn.Close ();
Son olarak, uygulama ilk kez çalıştırıldığında veya veritabanı eksikse veritabanı için varsayılan bir kayıt kümesi oluşturmak üzere Veri Modelimizi (PersonModel
) kullanırız:
// Build list of employees
var Craig = new PersonModel ("0","Craig Dunn", "Documentation Manager");
Craig.AddPerson (new PersonModel ("Amy Burns", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Joel Martinez", "Web & Infrastructure"));
Craig.AddPerson (new PersonModel ("Kevin Mullins", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Mark McLemore", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Tom Opgenorth", "Technical Writer"));
Craig.Create (conn);
var Larry = new PersonModel ("1","Larry O'Brien", "API Documentation Manager");
Larry.AddPerson (new PersonModel ("Mike Norman", "API Documentor"));
Larry.Create (conn);
Uygulama başlatıldığında ve Ana Pencere'yi açtığında, yukarıda eklediğimiz kodu kullanarak veritabanına bir bağlantı kurarız:
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Get access to database
DatabaseConnection = GetDatabaseConnection ();
}
İlişkili verileri yükleme
SQLite veritabanından bağlı verilere doğrudan erişmeye yönelik tüm bileşenler mevcut olduğunda, verileri uygulamamızın sağladığı farklı görünümlere yükleyebiliriz ve kullanıcı arabirimimizde otomatik olarak görüntülenir.
Tek bir kaydı yükleme
Kimliğin bilindiği tek bir kaydı yüklemek için aşağıdaki kodu kullanabiliriz:
Person = new PersonModel (Conn, "0");
Tüm kayıtlar yükleniyor
Yönetici olup olmadığına bakılmaksızın tüm kişileri yüklemek için aşağıdaki kodu kullanın:
// Load all employees
_conn.Open ();
using (var command = _conn.CreateCommand ()) {
// Create new command
command.CommandText = "SELECT ID FROM [People]";
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Load child and add to collection
var childID = (string)reader [0];
var person = new PersonModel (_conn, childID);
AddPerson (person);
}
}
}
_conn.Close ();
Burada, kişiyi belleğe yüklemek için sınıfı için PersonModel
oluşturucunun aşırı yüklemesini kullanıyoruz:
var person = new PersonModel (_conn, childID);
Ayrıca, kişiyi kişi AddPerson (person)
koleksiyonumuza eklemek için Data Bound sınıfını çağırıyoruz. Bu, kullanıcı arabirimimizin değişikliği tanımasını ve görüntülemesini sağlar:
[Export("addObject:")]
public void AddPerson(PersonModel person) {
WillChangeValue ("personModelArray");
isManager = true;
_people.Add (person);
DidChangeValue ("personModelArray");
}
Yalnızca en üst düzey kayıtları yükleme
Yalnızca yöneticileri yüklemek için (örneğin, ana hat görünümünde verileri görüntülemek için) aşağıdaki kodu kullanırız:
// Load only managers employees
_conn.Open ();
using (var command = _conn.CreateCommand ()) {
// Create new command
command.CommandText = "SELECT ID FROM [People] WHERE isManager = 1";
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Load child and add to collection
var childID = (string)reader [0];
var person = new PersonModel (_conn, childID);
AddPerson (person);
}
}
}
_conn.Close ();
SQL deyimindeki tek gerçek fark (yalnızca yöneticileri command.CommandText = "SELECT ID FROM [People] WHERE isManager = 1"
yükler) ancak yukarıdaki bölümle aynı şekilde çalışır.
Veritabanları ve birleşik giriş kutuları
macOS için kullanılabilen Menü Denetimleri (Birleşik Giriş Kutusu gibi) bir iç listeden (Arabirim Oluşturucusu'nda önceden tanımlanabilir veya kod yoluyla doldurulabilir) ya da kendi özel, dış veri kaynağınızı sağlayarak açılan listeyi dolduracak şekilde ayarlanabilir. Diğer ayrıntılar için bkz . Menü Denetim Verilerini Sağlama.
Örnek olarak, Yukarıdaki Basit Bağlama örneğini Interface Builder'da düzenleyin, bir Birleşik Giriş Kutusu ekleyin ve adlı EmployeeSelector
bir çıkış kullanarak kullanıma açın:
Öznitelik Denetçisi'nde Otomatik Tamamlamalar ve Veri Kaynağı özelliklerini kullanır:
Değişikliklerinizi kaydedin ve eşitlemek için Mac için Visual Studio dönün.
Birleşik giriş kutusu verileri sağlama
Ardından, projeye adlı ComboBoxDataSource
yeni bir sınıf ekleyin ve aşağıdaki gibi görünmesini sağlayın:
using System;
using System.Data;
using System.IO;
using Mono.Data.Sqlite;
using Foundation;
using AppKit;
namespace MacDatabase
{
public class ComboBoxDataSource : NSComboBoxDataSource
{
#region Private Variables
private SqliteConnection _conn = null;
private string _tableName = "";
private string _IDField = "ID";
private string _displayField = "";
private nint _recordCount = 0;
#endregion
#region Computed Properties
public SqliteConnection Conn {
get { return _conn; }
set { _conn = value; }
}
public string TableName {
get { return _tableName; }
set {
_tableName = value;
_recordCount = GetRecordCount ();
}
}
public string IDField {
get { return _IDField; }
set {
_IDField = value;
_recordCount = GetRecordCount ();
}
}
public string DisplayField {
get { return _displayField; }
set {
_displayField = value;
_recordCount = GetRecordCount ();
}
}
public nint RecordCount {
get { return _recordCount; }
}
#endregion
#region Constructors
public ComboBoxDataSource (SqliteConnection conn, string tableName, string displayField)
{
// Initialize
this.Conn = conn;
this.TableName = tableName;
this.DisplayField = displayField;
}
public ComboBoxDataSource (SqliteConnection conn, string tableName, string idField, string displayField)
{
// Initialize
this.Conn = conn;
this.TableName = tableName;
this.IDField = idField;
this.DisplayField = displayField;
}
#endregion
#region Private Methods
private nint GetRecordCount ()
{
bool shouldClose = false;
nint count = 0;
// Has a Table, ID and display field been specified?
if (TableName !="" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT count({IDField}) FROM [{TableName}]";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read count from query
var result = (long)reader [0];
count = (nint)result;
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return the number of records
return count;
}
#endregion
#region Public Methods
public string IDForIndex (nint index)
{
NSString value = new NSString ("");
bool shouldClose = false;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {IDField} FROM [{TableName}] ORDER BY {DisplayField} ASC LIMIT 1 OFFSET {index}";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
value = new NSString ((string)reader [0]);
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return value;
}
public string ValueForIndex (nint index)
{
NSString value = new NSString ("");
bool shouldClose = false;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {DisplayField} FROM [{TableName}] ORDER BY {DisplayField} ASC LIMIT 1 OFFSET {index}";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
value = new NSString ((string)reader [0]);
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return value;
}
public string IDForValue (string value)
{
NSString result = new NSString ("");
bool shouldClose = false;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {IDField} FROM [{TableName}] WHERE {DisplayField} = @VAL";
// Populate parameters
command.Parameters.AddWithValue ("@VAL", value);
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
result = new NSString ((string)reader [0]);
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return result;
}
#endregion
#region Override Methods
public override nint ItemCount (NSComboBox comboBox)
{
return RecordCount;
}
public override NSObject ObjectValueForItem (NSComboBox comboBox, nint index)
{
NSString value = new NSString ("");
bool shouldClose = false;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {DisplayField} FROM [{TableName}] ORDER BY {DisplayField} ASC LIMIT 1 OFFSET {index}";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
value = new NSString((string)reader [0]);
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return value;
}
public override nint IndexOfItem (NSComboBox comboBox, string value)
{
bool shouldClose = false;
bool found = false;
string field = "";
nint index = NSRange.NotFound;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {DisplayField} FROM [{TableName}] ORDER BY {DisplayField} ASC";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read () && !found) {
// Read the display field from the query
field = (string)reader [0];
++index;
// Is this the value we are searching for?
if (value == field) {
// Yes, exit loop
found = true;
}
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return index;
}
public override string CompletedString (NSComboBox comboBox, string uncompletedString)
{
bool shouldClose = false;
bool found = false;
string field = "";
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Escape search string
uncompletedString = uncompletedString.Replace ("'", "");
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {DisplayField} FROM [{TableName}] WHERE {DisplayField} LIKE @VAL";
// Populate parameters
command.Parameters.AddWithValue ("@VAL", uncompletedString + "%");
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
field = (string)reader [0];
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return field;
}
#endregion
}
}
Bu örnekte, herhangi bir SQLite Veri Kaynağından Birleşik Giriş Kutusu Öğeleri sunabilen yeni NSComboBoxDataSource
bir oluşturacağız. İlk olarak aşağıdaki özellikleri tanımlayacağız:
Conn
- SQLite veritabanına bir bağlantı alır veya ayarlar.TableName
- Tablo adını alır veya ayarlar.IDField
- Verilen Tablo için benzersiz kimliği sağlayan alanı alır veya ayarlar. Varsayılan değer şudur:ID
.DisplayField
- Açılan listede görüntülenen alanı alır veya ayarlar.RecordCount
- Verilen Tablodaki kayıtların sayısını alır.
Nesnenin yeni bir örneğini oluştururken bağlantıyı, tablo adını, isteğe bağlı olarak Kimlik alanını ve görüntüleme alanını geçiririz:
public ComboBoxDataSource (SqliteConnection conn, string tableName, string displayField)
{
// Initialize
this.Conn = conn;
this.TableName = tableName;
this.DisplayField = displayField;
}
yöntemi, GetRecordCount
verilen Tablodaki kayıtların sayısını döndürür:
private nint GetRecordCount ()
{
bool shouldClose = false;
nint count = 0;
// Has a Table, ID and display field been specified?
if (TableName !="" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT count({IDField}) FROM [{TableName}]";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read count from query
var result = (long)reader [0];
count = (nint)result;
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return the number of records
return count;
}
, veya DisplayField
özellikleri değeri her TableName
IDField
değiştirildiğinde çağrılır.
yöntemi, IDForIndex
verilen açılan liste öğesi dizinindeki kaydın benzersiz kimliğini (IDField
) döndürür:
public string IDForIndex (nint index)
{
NSString value = new NSString ("");
bool shouldClose = false;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {IDField} FROM [{TableName}] ORDER BY {DisplayField} ASC LIMIT 1 OFFSET {index}";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
value = new NSString ((string)reader [0]);
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return value;
}
yöntemi, ValueForIndex
verilen açılan liste dizinindeki öğenin () değeriniDisplayField
döndürür:
public string ValueForIndex (nint index)
{
NSString value = new NSString ("");
bool shouldClose = false;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {DisplayField} FROM [{TableName}] ORDER BY {DisplayField} ASC LIMIT 1 OFFSET {index}";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
value = new NSString ((string)reader [0]);
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return value;
}
yöntemi, IDForValue
verilen değer (IDField
) için benzersiz kimliği (DisplayField
) döndürür:
public string IDForValue (string value)
{
NSString result = new NSString ("");
bool shouldClose = false;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {IDField} FROM [{TableName}] WHERE {DisplayField} = @VAL";
// Populate parameters
command.Parameters.AddWithValue ("@VAL", value);
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
result = new NSString ((string)reader [0]);
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return result;
}
, ItemCount
veya özellikleri değiştirildiğinde TableName
IDField
DisplayField
hesaplandığı gibi listedeki önceden derlenmiş öğe sayısını döndürür:
public override nint ItemCount (NSComboBox comboBox)
{
return RecordCount;
}
yöntemi, ObjectValueForItem
verilen açılan liste öğesi dizini için (DisplayField
) değerini sağlar:
public override NSObject ObjectValueForItem (NSComboBox comboBox, nint index)
{
NSString value = new NSString ("");
bool shouldClose = false;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {DisplayField} FROM [{TableName}] ORDER BY {DisplayField} ASC LIMIT 1 OFFSET {index}";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
value = new NSString((string)reader [0]);
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return value;
}
SQLite komutumuzdaki ve OFFSET
deyimlerini, ihtiyacımız olan tek kayıtla sınırlamak için kullandığımıza LIMIT
dikkat edin.
yöntemi verilen IndexOfItem
değerin (DisplayField
) açılan öğe dizinini döndürür:
public override nint IndexOfItem (NSComboBox comboBox, string value)
{
bool shouldClose = false;
bool found = false;
string field = "";
nint index = NSRange.NotFound;
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {DisplayField} FROM [{TableName}] ORDER BY {DisplayField} ASC";
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read () && !found) {
// Read the display field from the query
field = (string)reader [0];
++index;
// Is this the value we are searching for?
if (value == field) {
// Yes, exit loop
found = true;
}
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return index;
}
Değer bulunamazsa değer NSRange.NotFound
döndürülüp açılan listeden tüm öğelerin seçimi kaldırılır.
yöntemi, CompletedString
kısmen yazılan bir giriş için ilk eşleşen değeri (DisplayField
) döndürür:
public override string CompletedString (NSComboBox comboBox, string uncompletedString)
{
bool shouldClose = false;
bool found = false;
string field = "";
// Has a Table, ID and display field been specified?
if (TableName != "" && IDField != "" && DisplayField != "") {
// Is the database already open?
if (Conn.State != ConnectionState.Open) {
shouldClose = true;
Conn.Open ();
}
// Escape search string
uncompletedString = uncompletedString.Replace ("'", "");
// Execute query
using (var command = Conn.CreateCommand ()) {
// Create new command
command.CommandText = $"SELECT {DisplayField} FROM [{TableName}] WHERE {DisplayField} LIKE @VAL";
// Populate parameters
command.Parameters.AddWithValue ("@VAL", uncompletedString + "%");
// Get the results from the database
using (var reader = command.ExecuteReader ()) {
while (reader.Read ()) {
// Read the display field from the query
field = (string)reader [0];
}
}
}
// Should we close the connection to the database
if (shouldClose) {
Conn.Close ();
}
}
// Return results
return field;
}
Verileri görüntüleme ve olaylara yanıt verme
Tüm parçaları bir araya getirmek için öğesini düzenleyin SubviewSimpleBindingController
ve aşağıdaki gibi görünmesini sağlayın:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.IO;
using Mono.Data.Sqlite;
using Foundation;
using AppKit;
namespace MacDatabase
{
public partial class SubviewSimpleBindingController : AppKit.NSViewController
{
#region Private Variables
private PersonModel _person = new PersonModel();
private SqliteConnection Conn;
#endregion
#region Computed Properties
//strongly typed view accessor
public new SubviewSimpleBinding View {
get {
return (SubviewSimpleBinding)base.View;
}
}
[Export("Person")]
public PersonModel Person {
get {return _person; }
set {
WillChangeValue ("Person");
_person = value;
DidChangeValue ("Person");
}
}
public ComboBoxDataSource DataSource {
get { return EmployeeSelector.DataSource as ComboBoxDataSource; }
}
#endregion
#region Constructors
// Called when created from unmanaged code
public SubviewSimpleBindingController (IntPtr handle) : base (handle)
{
Initialize ();
}
// Called when created directly from a XIB file
[Export ("initWithCoder:")]
public SubviewSimpleBindingController (NSCoder coder) : base (coder)
{
Initialize ();
}
// Call to load from the XIB/NIB file
public SubviewSimpleBindingController (SqliteConnection conn) : base ("SubviewSimpleBinding", NSBundle.MainBundle)
{
// Initialize
this.Conn = conn;
Initialize ();
}
// Shared initialization code
void Initialize ()
{
}
#endregion
#region Private Methods
private void LoadSelectedPerson (string id)
{
// Found?
if (id != "") {
// Yes, load requested record
Person = new PersonModel (Conn, id);
}
}
#endregion
#region Override Methods
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Configure Employee selector dropdown
EmployeeSelector.DataSource = new ComboBoxDataSource (Conn, "People", "Name");
// Wireup events
EmployeeSelector.Changed += (sender, e) => {
// Get ID
var id = DataSource.IDForValue (EmployeeSelector.StringValue);
LoadSelectedPerson (id);
};
EmployeeSelector.SelectionChanged += (sender, e) => {
// Get ID
var id = DataSource.IDForIndex (EmployeeSelector.SelectedIndex);
LoadSelectedPerson (id);
};
// Auto select the first person
EmployeeSelector.StringValue = DataSource.ValueForIndex (0);
Person = new PersonModel (Conn, DataSource.IDForIndex(0));
}
#endregion
}
}
özelliği Birleşik DataSource
Giriş Kutusu'na ComboBoxDataSource
eklenmiş (yukarıda oluşturulmuş) öğesine bir kısayol sağlar.
yöntemi, LoadSelectedPerson
belirtilen Benzersiz Kimlik için veritabanından kişiyi yükler:
private void LoadSelectedPerson (string id)
{
// Found?
if (id != "") {
// Yes, load requested record
Person = new PersonModel (Conn, id);
}
}
Yöntemi geçersiz kılmada AwakeFromNib
, önce özel Combo Box Veri Kaynağımızın bir örneğini ekleyeceğiz:
EmployeeSelector.DataSource = new ComboBoxDataSource (Conn, "People", "Name");
Ardından, kullanıcının Birleşik Giriş Kutusu'nun metin değerini düzenlemesine yanıt olarak, veri sunan verilerin ilişkili benzersiz kimliğini (IDField
) bulan ve bulunan kişiyi yükleyerek yanıt veririz:
EmployeeSelector.Changed += (sender, e) => {
// Get ID
var id = DataSource.IDForValue (EmployeeSelector.StringValue);
LoadSelectedPerson (id);
};
Kullanıcı açılan listeden yeni bir öğe seçerse yeni bir kişi de yükleriz:
EmployeeSelector.SelectionChanged += (sender, e) => {
// Get ID
var id = DataSource.IDForIndex (EmployeeSelector.SelectedIndex);
LoadSelectedPerson (id);
};
Son olarak Birleşik Giriş Kutusu'nu otomatik olarak doldurup listedeki ilk öğeyle kişiyi görüntüledik:
// Auto select the first person
EmployeeSelector.StringValue = DataSource.ValueForIndex (0);
Person = new PersonModel (Conn, DataSource.IDForIndex(0));
SQLite.NET ORM
Yukarıda belirtildiği gibi, açık kaynak SQLite.NET Nesne İlişki Yöneticisi'ni (ORM) kullanarak SQLite veritabanından veri okumak ve yazmak için gereken kod miktarını büyük ölçüde azaltabiliriz. Anahtar-değer kodlama ve veri bağlamanın bir nesneye yerleştirdiği gereksinimlerin birkaçı nedeniyle bu, verileri bağlarken izlenecek en iyi yol olmayabilir.
SQLite.Net web sitesine göre, "SQLite, bağımsız, sunucusuz, sıfır yapılandırmalı, işlemsel SQL veritabanı altyapısını uygulayan bir yazılım kitaplığıdır. SQLite, dünyanın en yaygın olarak dağıtılan veritabanı altyapısıdır. SQLite kaynak kodu genel etki alanındadır."
Aşağıdaki bölümlerde, tablo görünümü için veri sağlamak üzere SQLite.Net nasıl kullanılacağını göstereceğiz.
SQLite.net NuGet'i dahil
SQLite.NET, uygulamanıza eklediğiniz bir NuGet Paketi olarak sunulur. SQLite.NET kullanarak veritabanı desteği ekleyebilmek için önce bu paketi dahil etmemiz gerekir.
Paketi eklemek için aşağıdakileri yapın:
Çözüm Bölmesi'nde Paketler klasörüne sağ tıklayın ve Paket Ekle... öğesini seçin.
Arama Kutusuna girin
SQLite.net
ve sqlite-net girişini seçin:Bitirmek için Paket Ekle düğmesine tıklayın.
Veri modelini oluşturma
Şimdi projeye yeni bir sınıf ekleyelim ve öğesini OccupationModel
çağıralım. Şimdi OccupationModel.cs dosyasını düzenleyelim ve aşağıdaki gibi görünmesini sağlayalım:
using System;
using SQLite;
namespace MacDatabase
{
public class OccupationModel
{
#region Computed Properties
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Name { get; set;}
public string Description { get; set;}
#endregion
#region Constructors
public OccupationModel ()
{
}
public OccupationModel (string name, string description)
{
// Initialize
this.Name = name;
this.Description = description;
}
#endregion
}
}
İlk olarak, SQLite.NET ()using Sqlite
ekleyeceğiz, ardından her biri bu kayıt kaydedildiğinde veritabanına yazılacak olan çeşitli Özellikleri kullanıma sunacağız. Birincil anahtar olarak yaptığımız ve otomatik olarak artıracak şekilde ayarladığımız ilk özellik aşağıdaki gibi:
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
Veritabanını başlatma
Veri Modelimizin veritabanında okunmasını ve yazmasını desteklemek için yapılan değişikliklerle, veritabanına bir bağlantı açıp ilk çalıştırmada başlatmamız gerekir. Şimdi aşağıdaki kodu ekleyelim:
using SQLite;
...
public SQLiteConnection Conn { get; set; }
...
private SQLiteConnection GetDatabaseConnection() {
var documents = Environment.GetFolderPath (Environment.SpecialFolder.Desktop);
string db = Path.Combine (documents, "Occupation.db3");
OccupationModel Occupation;
// Create the database if it doesn't already exist
bool exists = File.Exists (db);
// Create connection to database
var conn = new SQLiteConnection (db);
// Initially populate table?
if (!exists) {
// Yes, build table
conn.CreateTable<OccupationModel> ();
// Add occupations
Occupation = new OccupationModel ("Documentation Manager", "Manages the Documentation Group");
conn.Insert (Occupation);
Occupation = new OccupationModel ("Technical Writer", "Writes technical documentation and sample applications");
conn.Insert (Occupation);
Occupation = new OccupationModel ("Web & Infrastructure", "Creates and maintains the websites that drive documentation");
conn.Insert (Occupation);
Occupation = new OccupationModel ("API Documentation Manager", "Manages the API Documentation Group");
conn.Insert (Occupation);
Occupation = new OccupationModel ("API Documenter", "Creates and maintains API documentation");
conn.Insert (Occupation);
}
return conn;
}
İlk olarak, veritabanının bir yolunu (bu örnekte Kullanıcının Masaüstü) alacağız ve veritabanının zaten var olup olmadığını göreceğiz:
var documents = Environment.GetFolderPath (Environment.SpecialFolder.Desktop);
string db = Path.Combine (documents, "Occupation.db3");
OccupationModel Occupation;
// Create the database if it doesn't already exist
bool exists = File.Exists (db);
Ardından, yukarıda oluşturduğumuz yolda veritabanına bir bağlantı kuracağız:
var conn = new SQLiteConnection (db);
Son olarak, tabloyu oluşturur ve bazı varsayılan kayıtları ekleriz:
// Yes, build table
conn.CreateTable<OccupationModel> ();
// Add occupations
Occupation = new OccupationModel ("Documentation Manager", "Manages the Documentation Group");
conn.Insert (Occupation);
Occupation = new OccupationModel ("Technical Writer", "Writes technical documentation and sample applications");
conn.Insert (Occupation);
Occupation = new OccupationModel ("Web & Infrastructure", "Creates and maintains the websites that drive documentation");
conn.Insert (Occupation);
Occupation = new OccupationModel ("API Documentation Manager", "Manages the API Documentation Group");
conn.Insert (Occupation);
Occupation = new OccupationModel ("API Documenter", "Creates and maintains API documentation");
conn.Insert (Occupation);
Tablo görünümü ekleme
Örnek kullanım olarak, Xcode'un Arabirim oluşturucusunda kullanıcı arabirimimize bir Tablo Görünümü ekleyeceğiz. C# koduyla erişebilmek için bu Tablo Görünümü'nü bir çıkış (OccupationTable
) aracılığıyla kullanıma sunarız:
Ardından, bu tabloyu SQLite.NET veritabanındaki verilerle doldurmak için özel sınıflar ekleyeceğiz.
Tablo veri kaynağını oluşturma
Şimdi tablomuz için veri sağlamak üzere özel bir Veri Kaynağı oluşturalım. İlk olarak adlı TableORMDatasource
yeni bir sınıf ekleyin ve aşağıdaki gibi görünmesini sağlayın:
using System;
using AppKit;
using CoreGraphics;
using Foundation;
using System.Collections;
using System.Collections.Generic;
using SQLite;
namespace MacDatabase
{
public class TableORMDatasource : NSTableViewDataSource
{
#region Computed Properties
public List<OccupationModel> Occupations { get; set;} = new List<OccupationModel>();
public SQLiteConnection Conn { get; set; }
#endregion
#region Constructors
public TableORMDatasource (SQLiteConnection conn)
{
// Initialize
this.Conn = conn;
LoadOccupations ();
}
#endregion
#region Public Methods
public void LoadOccupations() {
// Get occupations from database
var query = Conn.Table<OccupationModel> ();
// Copy into table collection
Occupations.Clear ();
foreach (OccupationModel occupation in query) {
Occupations.Add (occupation);
}
}
#endregion
#region Override Methods
public override nint GetRowCount (NSTableView tableView)
{
return Occupations.Count;
}
#endregion
}
}
Bu sınıfın bir örneğini daha sonra oluşturduğumuzda, açık SQLite.NET veritabanı bağlantımızı geçireceğiz. LoadOccupations
yöntemi veritabanını sorgular ve bulunan kayıtları belleğe kopyalar (veri modelimizi OccupationModel
kullanarak).
Tablo temsilcisi oluşturma
İhtiyacımız olan son sınıf, SQLite.NET veritabanından yüklediğimiz bilgileri görüntülemek için özel bir Tablo Temsilcisidir. Şimdi projemize yeni bir ekleme TableORMDelegate
yapalım ve aşağıdaki gibi görünmesini sağlayalım:
using System;
using AppKit;
using CoreGraphics;
using Foundation;
using System.Collections;
using System.Collections.Generic;
using SQLite;
namespace MacDatabase
{
public class TableORMDelegate : NSTableViewDelegate
{
#region Constants
private const string CellIdentifier = "OccCell";
#endregion
#region Private Variables
private TableORMDatasource DataSource;
#endregion
#region Constructors
public TableORMDelegate (TableORMDatasource dataSource)
{
// Initialize
this.DataSource = dataSource;
}
#endregion
#region Override Methods
public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
{
// This pattern allows you reuse existing views when they are no-longer in use.
// If the returned view is null, you instance up a new view
// If a non-null view is returned, you modify it enough to reflect the new data
NSTextField view = (NSTextField)tableView.MakeView (CellIdentifier, this);
if (view == null) {
view = new NSTextField ();
view.Identifier = CellIdentifier;
view.BackgroundColor = NSColor.Clear;
view.Bordered = false;
view.Selectable = false;
view.Editable = false;
}
// Setup view based on the column selected
switch (tableColumn.Title) {
case "Occupation":
view.StringValue = DataSource.Occupations [(int)row].Name;
break;
case "Description":
view.StringValue = DataSource.Occupations [(int)row].Description;
break;
}
return view;
}
#endregion
}
}
Burada, yöntem geçersiz kılma yoluyla tablomuzun sütunlarını doldurmak için Veri Kaynağı'nın Occupations
koleksiyonunu (SQLite.NET veritabanından GetViewForItem
yüklediğimiz) kullanırız.
Tabloyu doldurma
Tüm parçalar hazır olduğunda, yöntemini geçersiz kılıp aşağıdaki gibi görünmesini sağlayarak tablomuzu .xib dosyasından AwakeFromNib
şişirildiğinde dolduralım:
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Get database connection
Conn = GetDatabaseConnection ();
// Create the Occupation Table Data Source and populate it
var DataSource = new TableORMDatasource (Conn);
// Populate the Product Table
OccupationTable.DataSource = DataSource;
OccupationTable.Delegate = new TableORMDelegate (DataSource);
}
İlk olarak, SQLite.NET veritabanımıza erişerek henüz yoksa oluşturup dolduruyoruz. Ardından, özel Tablo Veri Kaynağımızın yeni bir örneğini oluşturacak, veritabanı bağlantımızı geçirecek ve tabloya ekleyeceğiz. Son olarak, özel Tablo Temsilcimizin yeni bir örneğini oluşturur, Veri Kaynağımızı geçirir ve tabloya ekleriz.
Özet
Bu makalede, Xamarin.Mac uygulamasında SQLite veritabanlarıyla veri bağlama ve anahtar-değer kodlama ile çalışma konusuna ayrıntılı bir bakış sağlandı. İlk olarak, anahtar-değer kodlaması (KVC) ve anahtar-değer gözlemleme (KVO) kullanarak bir C# sınıfını Objective-C kullanıma sunar. Daha sonra, KVO uyumlu bir sınıfın nasıl kullanılacağını ve Xcode'un Arabirim Oluşturucusu'ndaki Ui öğelerine Veri Bağlama'nın nasıl kullanılacağını gösterdi. Makalede ayrıca SQLite.NET ORM aracılığıyla SQLite verileriyle çalışma ve bu verilerin Tablo Görünümü'nde görüntülenmesi ele alınmıştır.
İlişkili Bağlantılar
- Hello, Mac
- Veri bağlama ve anahtar-değer kodlama
- Standart denetimler
- Tablo görünümleri
- Anahat görünümleri
- Koleksiyon görünümleri
- Anahtar-Değer Kodlama Programlama Kılavuzu
- Kakao Bağlamalarına Giriş Programlama Konuları
- Kakao Bağlama başvurusuna giriş
- NSCollectionView
- macOS İnsan Arabirimi Yönergeleri