Laden...

Wo erstelle ich bei MVVM die MySQL Verbindung?

Erstellt von xKushGene vor 6 Jahren Letzter Beitrag vor 6 Jahren 2.160 Views
X
xKushGene Themenstarter:in
91 Beiträge seit 2017
vor 6 Jahren
Wo erstelle ich bei MVVM die MySQL Verbindung?

Hallo,
ich bin gerade dabei, mir MVVM anzueignen und möchte mein bisheriges Code-Behind Projekt in MVVM "nachbauen". Nun habe ich also ein Datagrid und möchte in dieses Datagrid die Daten aus einer Datenbank packen.

Allerdings bin ich mir durch die ganzen Tutorials nun ein wenig unsicher, wie ich das ganze denn mache.
Ich frage mich:
Wo / Wie soll ich nun die Datenbank Verbindung aufbauen?
Ich vermute mal, dass das ganze im Model passieren soll. Denn wie ich das richtig verstanden habe, sind in ViewModel nur Eigenschaften und Commands und in Model dann eben die Methoden. Allerdings habe ich beim Tutorial, was ich verfolgt habe kaum bis gar nicht mit dem Model selber gearbeitet (das mvvm tutorial von codefreaks).

Und wo lege ich dann den Connection String fest, den ich dann überall aufrufen kann, sobald ich ihn eben brauche (also so ziemlich überall).

Auch weiß ich noch nicht, wie ich das Login System einbauen soll.

In meinem LoginViewModel habe ich bisher nur folgendes:


public class LoginViewModel : ViewModelBase, IDataErrorInfo
    {
        private Dictionary<string, string> Errors { get; } = new Dictionary<string, string>();
        private static List<PropertyInfo> _propertyInfo;
        public LoginViewModel()
        {
            LoginButton = new RelayCommand(() =>
            {
                Trace.TraceInformation("OK");
            },
            () => IsOk);
        }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Benutzername erforderlich")]
        [MaxLength(15, ErrorMessage = "Es dürfen maximal 15 Zeichen verwendet werden")]
        public string Username { get; set; }
        public string Password { get; set; }
        public bool StayLoggedIn { get; set; }

        public RelayCommand LoginButton { get; private set; }

        public string this[string propertyName]
        {
            get
            {
                CollectErrors();
                return Errors.ContainsKey(propertyName) ? Errors[propertyName] : string.Empty;
            }
        }

        protected List<PropertyInfo> PropertyInfos
        {
            get
            {
                if (_propertyInfo == null)
                {
                    // TODO filter for other attributes
                    _propertyInfo = GetType()
                        .GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
                        .Where(prop =>
                            prop.IsDefined(typeof(RequiredAttribute), true) || prop.IsDefined(typeof(MaxLengthAttribute), true) /*|| prop.IsDefined(typeof(MinLengthAttribute), true*/)
                        .ToList();
                }
                return _propertyInfo;
            }
        }

        private void CollectErrors()
        {
            Errors.Clear();
            PropertyInfos.ForEach(
                prop =>
                {
                    var currentValue = prop.GetValue(this);
                    var requiredAttr = prop.GetCustomAttribute<RequiredAttribute>();
                    var maxLenAttr = prop.GetCustomAttribute<MaxLengthAttribute>();
                    //var minLenAttr = prop.GetCustomAttribute<MinLengthAttribute>();
                    if (requiredAttr != null)
                    {
                        if (string.IsNullOrEmpty(currentValue?.ToString() ?? string.Empty))
                            Errors.Add(prop.Name, requiredAttr.ErrorMessage);
                    }
                    if (maxLenAttr != null)
                    {
                        if ((currentValue?.ToString() ?? string.Empty).Length > maxLenAttr.Length)
                            Errors.Add(prop.Name, maxLenAttr.ErrorMessage);
                    }
                    // further attributes
                    //if (minLenAttr != null)
                    //{
                    //    if ((currentValue?.ToString() ?? string.Empty).Length < minLenAttr.Length)
                    //        Errors.Add(prop.Name, minLenAttr.ErrorMessage);
                    //}

                });
            LoginButton.RaiseCanExecuteChanged();
        }

        public string Error => string.Empty;
        public bool HasErrors => Errors.Any();
        public bool IsOk => !HasErrors;

    }

Aber nun hakt es eben daran, dass ich nicht weiß wo/wie ich eine Verbindung zu Datenbank herstelle und wo ich den Code fürs Login hinpacken soll.

Edit:
Ich habe das PropertyChanged.Fody NuGet package installiert sowie MvvmLight

4.939 Beiträge seit 2008
vor 6 Jahren

Hallo,

die Datenbankzugriffe solltest du nicht direkt im Model (Logikschicht) durchführen, sondern dafür eigene Klassen anlegen, welche dann nur vom Model aus aufgerufen werden (Stichwort: Repository, s. z.B. Datenzugriff aus MVVM mit Repository und UnitOfWork?), s. [Artikel] Drei-Schichten-Architektur.

Und die ViewModels sollten nur gerade so viel Code beinhalten, daß sie von der View aus per DataBinding benutzt werden können, alles andere (insbes. Wiederverwertbares) sollte in der Logikschicht untergebracht sein.

X
xKushGene Themenstarter:in
91 Beiträge seit 2017
vor 6 Jahren

Heißt im Endeffekt, dass der Code also in das ViewModel kommt?
Dass habe ich nun getan. Allerdings fange ich langsam an, MVVM zu hassen, da man weder PasswordBox binden kann, noch eine MessageBox anzeigen kann. Alles muss unbedingt um 10 Stufen schwieriger gemacht werden damit ich am ende dann.. ja gut was habe ich eigentlich davon außer 10h an einer MessageBox / binden des Inhalts der PasswordBox zu sitzen?

709 Beiträge seit 2008
vor 6 Jahren

Wenn du es richtig machst, ist es hinterher egal, ob dein ViewModel in einer Desktopanwendung sitzt und dort eine MessageBox aufpoppt, oder es z.B. in einer Xamarin.Forms-App sitzt und die Meldung z.B. als UIActionSheet oder UIAlertView unter iOS darstellt, da das ViewModel einen entsprechenden Service nutzt, der dann die Darstellung auf dem entsprechenden System übernimmt.

Zusätzlich weißt du, dass es genau eine Klasse gibt, die du anfassen musst, wenn du etwas an der Darstellung ändern willst, da sich nur eine Klasse darum kümmert.

Außerdem hast du dann das alles noch testbar, da du den Service dann entsprechend mocken kannst und das Test-Framework nicht auf einen User wartet, der dann mal eben die MessageBox passend für den Testfall klicken muss.

3.003 Beiträge seit 2006
vor 6 Jahren

Ja nun. Was hat man davon, organisiert vorzugehen? MVVM ist kein Selbstzweck. Es soll helfen, Code so zu strukturieren, dass man ihn auch noch managen kann, wenn er schon zehn Jahre alt und etliche tausend Zeilen lang ist.

PasswordBox lässt sich nicht binden? Du meinst, MVVM hindert dich aktiv daran, die Security-Todsünde zu begehen und ein Passwort ewig unverschlüsselt im Speicher zu halten? Ja, ei der Daus aber auch.
Und, aeh, eine (wenn auch nicht DIE) Messagebox anzuzeigen, ist selten mehr als eine Zeile XAML.

Sagen wir es so: MVVM behindert dich dabei, Dinge falsch zu machen. Wenn du dich gerade sehr behindert fühlst, ist das ein Zeichen dafür, dass du dringend umlernen musst.

Die Frage, ob der Code ins VM gehölrt, hat Th69 schon beantwortet, wenn du dir die Zeit nehmen würdest, seinen Beitrag mal zu lesen.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

5.658 Beiträge seit 2006
vor 6 Jahren

Hi xKushGene;

ja gut was habe ich eigentlich davon

Abgesehen von dem, was pinki und LaTino bereits geschrieben haben, findest du die Antworten auf deine Frage auch in dem bereits verlinkten Artikel [Artikel] MVVM und DataBinding

Weeks of programming can save you hours of planning