2014年11月12日水曜日

【解決】SQLEXPRESSインストールエラー e:\sql11_main_t.obj.x86release?

横道に逸れるよ。

SQLSERVER EXPRESSがクラッシュしたので再インストールをしているのだが
2日ほど、ハマっている。

インストールに失敗するのだ。というか、インストールはできるのだが、SQLEXPRESSのサービスが起動しないのだ。

インストールしたバージョンはSQL SERVER EXPRESS EDITION 2012。 Service Pack 1 でもどっちでもダメ。
インストールの後半 SqlEngineDBStartConfigAction_install_configrrc_Cpu32 で
「データベースエンジンの復旧ハンドルの待機に失敗しました。考えられる原因については、SQL Serverエラーログを参照してください。」


SQL Server (SQLEXPRESS)のサービスを起動しようとすると

「ローカルコンピューターでSQL Server (SQLEXPRESS)を開始できませんでした。詳細情報はシステムイベントログを参照してください。これがMicrosoft以外のサービスである場合は、サービスの製造元に問い合わせてください。その際、サービス固有のエラーコードが -2146885628 であることを伝えてください。」

まぁMicrosoft製品の日本語が不自由なのは置いといて、
とりあえずログを確認。

C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\Log\ERRORLOG

Error: 17190, Severity: 16, State: 1.
Initializing the FallBack certificate failed with error code: 1, state: 20, error number: 0.
Unable to initialize SSL encryption because a valid certificate could not be found, and it is not possible to create a self-signed certificate.

これはSQLEXPRESSのサービスのログオンをローカルシステムアカウントにすれば良いという情報あり。


Failed to verify Authenticode signature on DLL 'c:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\Binn\ftimport.dll'.

DLLの認証コードのベリファイに失敗と出てくるが、このDLLが存在しない。
failedとは言うが、他は進んでいるようなので、とりあえず気にしないことにする。
つぎのログ。

FCB::Open failed: Could not open file e:\sql11_main_t.obj.x86release\sql\mkmastr\databases\objfre\i386\MSDBData.mdf for file number 1. OS error: 3(指定されたパスが見つかりません。).

これが何とも不可解。
EドライブはDVDに割り当ててあったが、インストールはメディアではなくダウンロードしたインストーラで行ったもの。
なので e:\sql11_main_t.obj.x86release というパスは存在しないわけだが・・・
なぜここを参照にいくのか。
どう見てもインストーラのバグっぽい気がしますがどうですか?
ですが同じインストーラで以前はうまくインストールできていたので、何か環境に起因する問題なのだろう。。。。

MSDBData.mdfというファイル名からすると、システムデータベースなのだろう。他にもmodel.mdfの同様のエラーもある。

http://w3facility.info/question/sql-server-express-service-is-not-starting/
ここの助けを参考にしてみた。

NET START MSSQL$SQLEXPRESS /f /T3608


なんという魔法のコマンド!
これでSQLEXPRESSサービスが起動しました。

-T3608 Masterデータベースのみをリカバリします。

だそうだ。

続いて

SELECT name, physical_name, state_desc FROM sys.master_files ORDER BY database_id

結果
master c:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA\master.mdf
mastlog c:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA\mastlog.ldf
tempdev e:\sql11_main_t.obj.x86release\sql\mkmastr\databases\objfre\i386\tempdb.mdf
templog e:\sql11_main_t.obj.x86release\sql\mkmastr\databases\objfre\i386\templog.ldf
modeldev e:\sql11_main_t.obj.x86release\sql\mkmastr\databases\objfre\i386\model.mdf
modellog e:\sql11_main_t.obj.x86release\sql\mkmastr\databases\objfre\i386\modellog.ldf
MSDBData e:\sql11_main_t.obj.x86release\sql\mkmastr\databases\objfre\i386\MSDBData.mdf
MSDBLog e:\sql11_main_t.obj.x86release\sql\mkmastr\databases\objfre\i386\MSDBLog.ldf
と落ちてきた。

このtempdev, templog, modeldev, modelloog, MSDBData, MSDBLogを書き換えてやる!

C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA
には、temp以外の枠も出来ていたので

ALTER DATABASE tempdb MODIFY FILE ( NAME = tempdev, FILENAME = 'c:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA\tempdb.mdf');
ALTER DATABASE tempdb MODIFY FILE ( NAME = templog, FILENAME = 'c:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA\templog.ldf');

ALTER DATABASE model MODIFY FILE ( NAME = modeldev, FILENAME = 'c:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA\model.mdf');
ALTER DATABASE model MODIFY FILE ( NAME = modellog, FILENAME = 'c:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA\modellog.ldf');

ALTER DATABASE msdb MODIFY FILE ( NAME = MSDBData, FILENAME = 'c:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA\MSDBData.mdf');
ALTER DATABASE msdb MODIFY FILE ( NAME = MSDBLog, FILENAME = 'c:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA\MSDBLog.ldf');

を流してやった。

The file "tempdev" has been modified in the system catalog. The new path will be
 used the next time the database is started.

他もうまく行った。
再度SELECT叩いて、OKだ。
サービスを一旦落として、開始!!!!

めっちゃ時間かかったけど・・・開始になった~!!

いちおうログ確認すると、最初の2番目のFailedは相変わらず出ているけど、他のエラーはなかった。

めでたし、めでたし。

microsoftさんよ、2日返せ~

2014年8月21日木曜日

Hello World 完成版。

ViewModelを使った、私個人なりのベストなHello World。

動作は今まで通り



です。

MainWindow.xaml
<Window x:Class="HelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Label Content="名前を入れてね" />
        <TextBox Text="{Binding Name}" />
        <Button Content="Enter" Click="ButtonEnter_Click" />
        <TextBlock Text="{Binding Message}" />
    </StackPanel>
</Window>


MainWindow.xaml.cs
using System.Windows;

namespace HelloWorld
{
    /// 
    /// MainWindow
    /// 
    public partial class MainWindow : Window
    {
        /// 
        /// ViewModel
        /// 
        private MainViewModel _viewmodel;

        /// 
        /// Constructor
        /// 
        public MainWindow()
        {
            InitializeComponent();
            _viewmodel = new MainViewModel();
            this.DataContext = _viewmodel;
        }

        /// 
        /// ボタン押下時のイベント処理
        /// 
        /// 
        /// 
        private void ButtonEnter_Click(object sender, RoutedEventArgs e)
        {
            _viewmodel.SetMessage();
        }
    }
}


MainViewModel.cs
using System;
using System.Windows;
using System.Windows.Input;
namespace HelloWorld
{
    /// 
    /// MainWindowのViewModel
    /// 
    class MainViewModel : ViewModelBase
    {
        private string _Name;
        private string _Message;

        /// 
        /// Constructor
        /// 
        public MainViewModel()
        {
        }

        #region Property
        /// 
        /// Name Property
        /// 
        public string Name
        {
            get
            {
                return _Name;
            }
            set
            {
                if (_Name != value)
                {
                    _Name = value;
                    RaisePropertyChanged("Name");
                }
            }
        }

        /// 
        /// Message Property
        /// 
        public string Message
        {
            get
            {
                return _Message;
            }
            set
            {
                if (_Message != value)
                {
                    _Message = value;
                    RaisePropertyChanged("Message");
                }
            }
        }
        #endregion

        /// 
        /// メッセージをセットする処理
        /// 
        public void SetMessage()
        {
            Message = "こんにちは、" + Name + "さん!";
        }
    }
}


ViewModelBase.cs
using System.ComponentModel;

namespace HelloWorld
{
    /// 
    /// ViewModelの基底クラス
    /// 
    class ViewModelBase : INotifyPropertyChanged
    {
        /// 
        /// プロパティ変更のイベント
        /// 
        public event PropertyChangedEventHandler PropertyChanged;

        /// 
        /// プロパティ変更のイベントを発行する
        /// 
        /// 
        internal void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
            }
        }
    }
}


変わったところは、MainWindow.xaml.csのボタンのイベントハンドラの処理内容をViewModelに書いたことでしょうか。
イベントの受けはxaml.csでやっても、ビジネスロジックは、ViewModelに書きたい。というところがポイントです。
しっかし、ViewModelは長くなるなぁ。。。なんかいい方法ないかなぁ。

さぁて、次はどんなプログラムを作ろうかな。

Coffee Break : 私の結論(MVVMは果たして効率的なのか?)

しばらく悩んでおりました。
適当な理由をつけて、結果を出しました。

「MVVMにするのは、コードビハインドを排除していく一つの手段であるが

何が何でもコードビハインドを排除する必要はないんじゃないか。」

まぁ
XAMLとプログラムを別の人が作るってのは理想ではあるけれど

実際は
全部自分たちで作るのがSEなわけで

まぁ
BtoCみたいなサイトならまだしも

inBだったりBtoBのシステムに関してXAMLに凝るものなんて無いじゃん?

じゃぁコードビハインドに書いたっていいじゃんね?

コマンドまでRelayだなんだで面倒なことわざわざやる必要ない!
ClickだったらClickのイベントハンドラからViewModelにアクセスしにいけばいいじゃん。


ただ、データバインディングという便利な機能は活用していくとして、画面とデータのやり取りをするような場合にはViewModelは必要なんだろうね。

という結論です。
それが生産性・可視性・保守性が一番バランス良さそう。

ではHello Worldの締めに入るか。

2014年8月14日木曜日

Coffee Break : MVVMは果たして効率的なのか?

ラストエントリの最後にも書きましたが、MVVMのViewModelにおけるコーディングが肥大化してしまうことが問題点に思えてきてなりません。

さらに、ViewModelに記述した名称と、xamlに書いた名称が合わなくても、xamlはサラッとエラーも出さずに澄ました顔してます。

もし何十と入力項目のあるような画面で、一部うまく表示されない、という場合にコードのどこに原因があるのか、開発者以外の人間が見て、すぐにわかるでしょうか?

MVVMフレームワークとして、「書き方は、こう!」という定型化されたものがあれば良いのですが、他人の書いたコードを見ていて、人によって書き方にバラツキが出てきているのが実情のようです。

google先生に聞いても、いろんな書き方がばらついているような気がします。



モノによっては、コードビハインドに処理をガリガリ書いたほうが視認性が高かったり、デバッグしやすかったり、MVVMを使うより楽なものも多そうです。

MVVMとして得た知識は経験として置いておき、もうちょっと違う目線でブログにしていこうかな、と思っています。


なのでブログタイトルは多分変わりますw

それではまた。

データバインディングを使ったHello World

今度は前回(Lesson 1 : クラシックなHello World)と同じ動作をする画面で、オブジェクトのプロパティを使用しない方法を試してみたいと思います。



まずは、この画面に使用される、「名前」と「メッセージ」をもつクラスを作成します。

MainViewModel.cs
namespace HelloWorld
{
    class MainViewModel
    {
        private string _Name;
        private string _Message;

        public MainViewModel()
        {
        }

        public string Name
        {
            get
            {
                return _Name;
            }
            set
            {
                _Name = value;
            }
        }

        public string Message
        {
            get
            {
                return _Message;
            }
            set
            {
                _Message = value;
            }
        }
    }
}

ローカル変数 _Name と _Message を定義して、そのgetter, setterをpublicにしています。

これを「ViewModel」として、xamlの中に取り入れていきます。

MainWindow.xaml.cs
<Window x:Class="HelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Label Content="名前を入れてね" />
        <TextBox Text="{Binding Name}" />
        <Button Name="btnEnter" Content="Enter" Click="btnEnter_Click" />
        <TextBlock Text="{Binding Message}" />
    </StackPanel>
</Window>

前回から大きく変わったのが、次の2点。
・TextBox, TextBlockから、Nameプロパティが消えた。
・TextBox, TextBlockの値プロパティTextの値が「{Binding 。。。}」となった。

この「{Binding 。。。}」がMVVMのキモっぽいです。どうやら。

次に、先ほどのMainViewModelと、このxamlをどう接続させるか。
それがコードビハインドに入りました。

MainWindow.xaml.cs
using System.Windows;

namespace HelloWorld
{
    public partial class MainWindow : Window
    {
        private MainViewModel _viewmodel;

        public MainWindow()
        {
            InitializeComponent();
            _viewmodel = new MainViewModel();
            DataContext = _viewmodel;
        }

        private void btnEnter_Click(object sender, RoutedEventArgs e)
        {
            _viewmodel.Message = "こんにちは、" + _viewmodel.Name + "さん!";
        }
    }
}

ローカル変数としてMainViewModelを定義し、コンストラクタでnewしています。
そして、DataContextに割り当てています。

これで接続は完了なのです。ふむふむ。

また、ボタンイベントの処理は、Nameプロパティで探して.Textプロパティで値を・・・という処理から、直接stringの編集にもっていけるのがコーディングが楽になるポイントでしょうか。

さて、これを実行・・・!としても、実は動きません。

ここがMVVMのややこしいところ。

どうして動かないのかというと、xamlのほうがViewModelの変数が変わったことに気づいていないからなのです(xamlの気持ちになったことがなく、よく分からないので、たぶん、気づいていないのです)。

では気づいてもらうために・・・RaisePropertyChangedというメッセージを送ってあげます。

さて、どうするか。
面倒なので、答えのコードをここに載せます。

ViewModelBase.cs
using System.ComponentModel;

namespace HelloWorld
{
    /// 
    /// ViewModelの基底クラス
    /// 
    class ViewModelBase : INotifyPropertyChanged
    {
        /// 
        /// プロパティ変更のイベント
        /// 
        public event PropertyChangedEventHandler PropertyChanged;

        /// 
        /// プロパティ変更のイベントを発行する
        /// 
        /// 
        internal void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
            }
        }
    }
}
このクラスを作成して、ViewModelのほうはこのクラスを継承させます。
もうこれは完全にテンプレート、呪文だと思って黙って入れる、でいいんですね。

MainViewModel.cs 改訂版
namespace HelloWorld
{
    class MainViewModel : ViewModelBase
    {
        private string _Name;
        private string _Message;

        public MainViewModel()
        {
        }

        public string Name
        {
            get
            {
                return _Name;
            }
            set
            {
                if (_Name != value)
                {
                    _Name = value;
                    RaisePropertyChanged("Name");
                }
            }
        }

        public string Message
        {
            get
            {
                return _Message;
            }
            set
            {
                if (_Message!= value)
                {
                    _Message = value;
                    RaisePropertyChanged("Message");
                }
            }
        }
    }
}
変わったのは、ViewModelBaseを継承したことと、setterでRaisePropertyChangedを書いたことです。

こう変更したことでどう動くのか?
・NameまたはMessageが変更になったとき、RaisePropertyChangedが動く。
・ViewModelBaseにより、INotifyPropertyChangedにより、プロパティの変更がxamlに通知される。
・xamlが気づいて、表示を変える。
んだと思う。。。

少しだけコードがスッキリしたような、余計にファイルが増えてややこしくなったような。

続いて、コマンドバインディングを使ってコードビハインドを完全にフリーにしてやります。
と思っていたのですが、やはりファイルが余計に増えてしまい、ViewModelも冗長なコーディングの塊になってしまうことから、MVVMって実際どうなの?っていう気持ちが強くなってきました。

ちょっと、考えてみます。


クラシックなHello World

まずはMVVMとか難しいこと考えずに、昔ながらの方法で、HelloWorldしてみたいと思います。

画面にはラベルとテキストボックス、ボタンを配置しました。
ボタンを押すと、テキストボックスの内容を読んで、メッセージを表示します。




メッセージを入れると・・・




くっそ、おっさん呼ばわりですww

コードはこちら。

MainWindow.xaml
<Window x:Class="HelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Label Content="名前を入れてね" />
        <TextBox Name="txtName" Text="" />
        <Button Name="btnEnter" Content="Enter" Click="btnEnter_Click" />
        <TextBlock Name="txtMessage" Text="" />
    </StackPanel>
</Window>


TextBox、TextBlock、それぞれのオブジェクトにName属性を指定して、Clickイベントを指定します。

MainWindow.xaml.cs
using System.Windows;

namespace HelloWorld
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void btnEnter_Click(object sender, RoutedEventArgs e)
        {
            txtMessage.Text = "こんにちは、" + txtName.Text + "さん!";
        }
    }
}


Clickイベントにて、xamlのTextBlockの入力値を取得して、TextBoxの入力値にセットする・・・

というクラシックなHello Worldができました。


さて、MVVMでは、「データバインド」という方法でコードビハインドを無くしてくことができるようですので、次はこの「 .Text 」を無くしていってみようと思います。

2014年7月29日火曜日

とりあえず、プロジェクトを作る

とりあえず、Visual Studioで新しいソリューションを作成してみよう。
わたしはVisual Studio Express 2013 for Windows Desktopを使っています。

ソリューション名は、とりあえずHelloWorld。



WPFアプリとして作ってみよう。



サクッとプロジェクトが出来上がる。

ここで出来たファイルは
App.config
App.xaml
App.xaml.cs
MainWindow.xaml
MainWindow.xaml.cs
の5つ(.csは、xamlを展開すると出てくる)。

App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>

プロジェクトの環境が書いてあるようだ。



App.xaml
<Application x:Class="HelloWorld.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

XAMLのベース。



App.xaml.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace HelloWorld
{
    /// 
    /// App.xaml の相互作用ロジック
    /// 
    public partial class App : Application
    {
    }
}

相互作用ロジックとは耳慣れない言葉だが、アプリケーションクラスであるようだ。



MainWindow.xaml
<Window x:Class="HelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        
    </Grid>
</Window>

メインウィンドウのXAML。



MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace HelloWorld
{
    /// 
    /// MainWindow.xaml の相互作用ロジック
    /// 
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

またもや相互作用ロジックだが
MainWindow.xamlのコードビハインドと言われる、c#を書くソース。

まずはここに、TextBlockで "Hello World" とでも表示させてみよう。
(次へ続く)