創作世界のいろいろ〜AdobeとかC#とか

絵を描く人がC#とか3Dとか動画編集とかやる為の備忘録

4【MySQL】MySQL DBをMAUIでバインディングして新規登録もする

前回の続きのはずだったけど色々中身が変わってます。手順としては同じ作業

matsrikagraphic.hatenablog.com

 

データベースに接続するServiceクラスを作成する

MVVMパターンのViewModelやModelと別に、Serviceクラスというcsにデータベースに直接接続する部分の実装をしていくのが良いみたいです。

 

public class DBService
	{
		//Balanceクラス
		public ObservableCollection<Balance> Balances { get; set; }
        //TODO Workerクラス、Companyクラス

        //DB接続-----------------------------------
        private readonly string connectionString = $"server=<~~~~server.mysql.database.azure.com>;database=<~~~~>;user=<~~~~>;password=<~~~~>;sslmode=Required;sslcert=DigiCertGlobalRootCA.crt.pem,Charset=utf8";
        public DBService(string connectionString)
        { connectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString; }
        //DB接続-----------------------------------


        //instance,connection,substitution
        public DBService()
        {
            Balances = new ObservableCollection<Balance>();
            //TODO Workers,Companies

            using var connection = new MySql.Data.MySqlClient.MySqlConnection(connectionString);

            try
            {
                connection.Open();

                //"SELECT * FROM Table名",↓の場合は"balance"がMySQLで作成したテーブル名
                using var command = new MySql.Data.MySqlClient.MySqlCommand("SELECT * FROM balance", connection);
                using var reader = command.ExecuteReader();//"Execute=実行する"

                while(reader.Read())
                {
                    //instanceしたBalancesへTableDataを格納する
                    Balances.Add(new Balance
                    {
                        idbalance   = reader.GetInt32(0),
                        paydate     = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1),
                        invoicedate = reader.IsDBNull(2) ? DateTime.MinValue : reader.GetDateTime(2),
                        price       = reader.GetInt32(3),
                        bname       = reader.GetString(4),
                        bcompany    = reader.IsDBNull(5) ? null : reader.GetString(5),
                        bmemo       = reader.IsDBNull(6) ? null : reader.GetString(6),
                        iscash      = reader.GetBoolean(7),

                    });
                }
                //Check substitution
                Debug.WriteLine($"現在のデータ数 ; {Balances.Count.ToString()}");
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }

        }

.上記のようにMySQLデータベースサーバーに接続してから、コード内の同一の変数があるカスタムクラス(Modelに記述するクラス)に格納していきます。

そして、ViewModelへ運んであげる感じ

 

//Acquire from DBService Balances
        var service = new DBService();
        balances.Value = service.Balances;

        //Detect when it has been updated and update ReactiveProperties
        service.Balances.CollectionChanged += (_, __) =>
        {
            balances.Value = service.Balances;
        };

        BalanceCollection.ItemsSource = balances.Value;

ReactiveProperties は、Inotyfyなんちゃらの機能を継承したまま、記述量を減らしてくれるパッケージです。

zenn.dev

 

cs側は以上のようなかたちで、xamlのCollectioinViewにBindingします。

 

<CollectionView x:Name="BalanceCollection" ItemsSource="{Binding balances.Value}" SelectionMode="Multiple">
                        <CollectionView.ItemTemplate>
                            <DataTemplate>
                            <VerticalStackLayout Grid.Row="0">
                                <Grid Grid.Column="0" RowDefinitions="24,24" ColumnDefinitions="20,130,100,90,200,*">
                                <Label Grid.Column="0" FontSize="12"  Grid.RowSpan="2" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" Text="{Binding idbalance}" x:Name="idclick"/>
                                <Label Grid.Column="1" Grid.RowSpan="2" FontSize="16" HorizontalTextAlignment="Start" Text="{Binding paydate, StringFormat='{0: yyyy / MM / dd}'}"/>
                                <Label Grid.Row="1" Grid.Column="4" FontSize="15" Text="{Binding invoicedate, StringFormat='{0:yyyy 年 M 月}'}"/>
                                <Label Grid.Column="3" Grid.RowSpan="2" Text="{Binding price, StringFormat='{0:¥ 0,0}'}" Margin="0,0,12,0" FontSize="18" HorizontalTextAlignment="End"/>
                                <Label Grid.Column="5" Grid.RowSpan="2" Text="{Binding bmemo, StringFormat='MEMO&#10;   {0}'}" HorizontalTextAlignment="Start" VerticalTextAlignment="Start" Padding="6,0" BackgroundColor="#F9F7F4" TextColor="#5F6479" FontSize="12"/>
                                <Label Grid.Column="4" Grid.Row="0" Text="{Binding bcompany}"/>
                                </Grid>
                                <Border StrokeThickness="1"/>
                            </VerticalStackLayout>
                            </DataTemplate>
                        </CollectionView.ItemTemplate>
                    </CollectionView>

まだUIデザインを決めかねてるので直でこちゃこちゃつけてるので見にくいですが、ReactivePropertyでBindingするときは、{Binding プロパティ名.Value}というようにValueを後ろにつけます。 Collectionの場合は、各要素には不要。

 

こんな感じに無事表示されました。勘定科目名のラベルつけ忘れた

テスト用に、アプリ側コード内からデータベースに追加してみます。

    //DB Balance
    #region
    public ReactiveProperty<ObservableCollection<Balance>> balances { get; } = new();

    public void AddBalanceClicked(System.Object sender, System.EventArgs e)
    {
        //テスト用
        AddBalanceData(
            999,
            DateTime.ParseExact("20300505", "yyyyMMdd", null),
            DateTime.ParseExact("20281205", "yyyyMMdd", null),
            9999,
            "交際費",
            "りかりかストア",
            "接待費",
            true
            );
    }

    public void AddBalanceData
        (
        int id, DateTime payD, DateTime invD, int pr, string bna, string bco, string bme, bool cash
        )
    {
        var balance = new Balance
        {//TODO Entry Text to
            idbalance = id,
            paydate = payD,
            invoicedate = invD,
            price = pr,
            bname = bna,
            bcompany = bco,
            bmemo = bme,
            iscash = cash
        };

        var service = new DBService();
        service.AddBalanceData(balance);

    }
    #endregion

この辺とくに試行錯誤なので正しい手順かわからないです、、

ログを見てみると、1個きちんと追加されたみたいです。

Workbenchで見てみると、

追加されてます。

"交際費"だけは日本語が通ってて、他が通ってないです。

これは、BNameだけ明示的にUTF-8に文字コードを指定したからだと思います。

 

public void AddBalanceData(Balance balance)
        {
            using(var connection = new MySql.Data.MySqlClient.MySqlConnection(connectionString))
            {
                connection.Open();

                var command = new MySql.Data.MySqlClient.MySqlCommand("INSERT INTO balance(idBalance, PayDate, INvoiceDate,Price,BName,BCompany,BMemo,IsCash) VALUES (@idbalance,@paydate,@invoicedate,@price,@bname,@bcompany,@bmemo,@iscash)", connection);
                command.Parameters.AddWithValue("@idbalance", balance.idbalance);
                command.Parameters.AddWithValue("@paydate", balance.paydate);
                command.Parameters.AddWithValue("@invoicedate", balance.invoicedate);
                command.Parameters.AddWithValue("@price", balance.price);
                byte[] utf8Bytes = Encoding.UTF8.GetBytes(balance.bname);//←ここ
                string encodedBName = Encoding.UTF8.GetString(utf8Bytes);//←ここ
                command.Parameters.AddWithValue("@bname", utf8Bytes);
                command.Parameters.AddWithValue("@bcompany", balance.bcompany);
                command.Parameters.AddWithValue("@bmemo", balance.bmemo);
                command.Parameters.AddWithValue("@iscash", balance.iscash);

                command.ExecuteNonQuery();
            }
            return;
        }

上記だと、本当はencodedBNameをAddWithValueに入れるはずだったのですが、上手くいかずに、byte[]のまま入れたらどうだろうって試してみた結果、表示された

これで良いのか分からないですが

良いのかなぁ

アプリ上も更新されたので、ひとまずokとします!