myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Code-Reviews » Logik zum anlegen/bearbeiten von Datensätzen in DB-Anwendung
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Logik zum anlegen/bearbeiten von Datensätzen in DB-Anwendung

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
sugar76 sugar76 ist männlich
myCSharp.de-Mitglied

Dabei seit: 19.10.2017
Beiträge: 66
Entwicklungsumgebung: Visual Studio, IntelliJ IDEA
Herkunft: Berlin


sugar76 ist offline

Logik zum anlegen/bearbeiten von Datensätzen in DB-Anwendung

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

ich möchte gerne mal zur Diskussion stellen, wie die Logik zum Anlegen/Bearbeiten von Datensätzen in einer klassischen Datenbank-Anwendung idealerweise implementiert wird.

Technologien: WPF und Entity Framework.

Hierzu ein Mini-Beispiel, um Email-Adressen in der DB anzulegen/bearbeiten. Jede E-Mail-Adresse besitzt zwei Felder:
- Die eigentliche Adresse
- Einen optionalen Typ, z.B. Privat, Arbeit, ...

Ich habe es so umgesetzt, dass mit Detached-Objekten arbeite, die
- an ein ViewModel zur Bearbeitung übergeben werden
- vom Benutzer editiert werden
- dann zum Speichern an einen Service.

Wie würdet Ihr das machen?

Gruß

View:

XML-Code:
<UserControl x:Class="MyApp.View.EmailEditView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             Height="Auto" Width="400" x:Name="View"
>
    <DockPanel>
        <Grid DockPanel.Dock="Top">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <!-- Email-Adresse -->
            <Label Grid.Row="0" Grid.Column="0" Content="Email-Adresse"/>
            <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Adresse, UpdateSourceTrigger=LostFocus, ValidatesOnNotifyDataErrors=True}" />

            <!-- Email-Typ -->
            <Label Grid.Row="1" Grid.Column="0" Content="Typ"/>
            <ComboBox
                Grid.Row="1" Grid.Column="1"
                ItemsSource="{Binding EmailTypList}"
                SelectedItem="{Binding EmailTyp, Mode=TwoWay}"
                DisplayMemberPath="Name"
/>
        </Grid>

        <!-- Speichern/Abbrechen -->
        <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right">
            <Button Content="Speichern" Command="{Binding Save}" CommandParameter="{Binding ElementName=View}" />
            <Button x:Name="BtnCancel" Content="Abbrechen" Click="BtnCancel_Click" />
        </StackPanel>
    </DockPanel>
</UserControl>

ViewModel:

C#-Code:
namespace MyApp.ViewModel
{
    public class EmailEditViewModel : ValidatingViewModelBase
    {
        private MyApp.Entities.Email email;

        private string adresse;
        public string Adresse
        {
            get { return adresse; }
            set { adresse = value; OnPropertyChanged(); }
        }

        private MyApp.Entities.EmailTyp emailTyp;
        public MyApp.Entities.EmailTyp EmailTyp
        {
            get { return emailTyp; }
            set { emailTyp = value; OnPropertyChanged(); }
        }

        private List<MyApp.Entities.EmailTyp> emailTypList;
        public List<MyApp.Entities.EmailTyp> EmailTypList
        {
            get { return emailTypList; }
            set { emailTypList = value; OnPropertyChanged(); }
        }

        public ICommand Save { get; set; }

        public EmailEditViewModel(MyApp.Entities.Email email)
        {
            this.email = email;

            Adresse = email.Adresse;
            EmailTyp = email.EmailTyp;

            // Liste der Typen, z.B. Arbeit, Privat, Sonstige, ...
            EmailTypList = EmailTypService.GetAll();

            Save = new RelayCommand(SaveExecute, IsValid);

            RegisterValidator(() => Adresse, ValidateAdresse);
            ValidateAll();
        }

        protected async Task<string> ValidateAdresse()
        {
            return await EmailValidationRule.ValidateEmail(adresse);
        }

        protected override void UpdateDataModel()
        {
            email.EmailTyp = emailTyp;
            email.Adresse = adresse;
        }

        protected override void SaveExecute(object obj)
        {
            UpdateDataModel();
            EmailService.Save(email);
            Window.GetWindow(obj as DependencyObject).Close();
        }
    }
}

Service + Entitäten:

C#-Code:
namespace MyApp.Service
{
    public class EmailService
    {
        public static void Save(MyApp.Entities.Email email)
        {
            using (var context = new MyAppEntities())
            {
                if (email.EmailTyp != null)
                {
                    if (email.EmailTyp.Id > 0)
                    {
                        // Nur den FK ohne referenziertes Objekt verwenden, um keine Duplikate beim Speichern zu erzeugen
                        email.EmailTypId = email.EmailTyp.Id;
                        email.EmailTyp = null;
                    }
                    else
                    {
                        context.Entry(email.EmailTyp).State = EntityState.Added;
                    }
                }

                context.Entry(email).State = email.Id == 0 ? EntityState.Added : EntityState.Modified;
                context.SaveChanges();
            }
        }
    }
}

namespace MyApp.Entities
{
    public partial class Email
    {
        public int Id { get; set; }
        public Nullable<int> EmailTypId { get; set; }

        public virtual EmailTyp EmailTyp { get; set; }
    }

    public partial class EmailTyp
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von sugar76 am 22.06.2018 13:11.

22.06.2018 13:09 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 14.280
Herkunft: Stuttgart/Stockholm


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Statische Methoden sind weder modular noch testbar.
 [Artikel] Unit-Tests: Einführung in das Unit-Testing mit VisualStudio

Ansonsten gilt auch hier
 [Artikel] Drei-Schichten-Architektur

Die Entität sollte auch EMailAddress heissen; denn es ist eine E-Mail Adresse und keine E-Mail.
Auch der Name des EMailService macht wenig sinn, wenn es offensichtlich eher ein Repository ist; daher wäre wohl EMailAddressMssqlRepository mit einem IEMailAddressRepository Interface eher passend.

Warum ist der Typ bei Dir eine extra Klasse und nicht einfach ein ENum, wenn es eh nur zwei Typen gibt und offensichtlich keine Erweiterbarkeit notwendig ist?
Asynchrone Methoden sollten auch einen Async-Suffix haben.

Da es eine Review Frage ist, auch dahin verschoben.
22.06.2018 14:58 Beiträge des Benutzers | zu Buddylist hinzufügen
sugar76 sugar76 ist männlich
myCSharp.de-Mitglied

Dabei seit: 19.10.2017
Beiträge: 66
Entwicklungsumgebung: Visual Studio, IntelliJ IDEA
Herkunft: Berlin

Themenstarter Thema begonnen von sugar76

sugar76 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von Abt:
Statische Methoden sind weder modular noch testbar.

Ja, das steht noch auf meiner Liste ...

Zitat von Abt:
Ansonsten gilt auch hier
 [Artikel] Drei-Schichten-Architektur

Die drei Schichten sind in dem Beispiel korrekt abgebildet, meine ich, oder? Bei MVVM übernimmt das ViewModel ja Aufgaben des Controllers (sprich: die Verbindung zwischen View und Datenmodell).

Ansonsten danke für die Hinweise zum Naming. Werde das berücksichtigen.
22.06.2018 17:50 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
sugar76 sugar76 ist männlich
myCSharp.de-Mitglied

Dabei seit: 19.10.2017
Beiträge: 66
Entwicklungsumgebung: Visual Studio, IntelliJ IDEA
Herkunft: Berlin

Themenstarter Thema begonnen von sugar76

sugar76 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Nachtrag: mich würde noch interessieren, wie die Daten aus dem ViewModel am besten an die Datenzugriffsschicht übergeben werden ...

Die ganzen Tutorials zum Thema MVVM/EF sind meist extrem einfach gehalten, kennt da jemand vielleicht ein Real-World-Beispiel?

EDIT: nachdem ich das geschrieben habe, hab ich noch mal gesucht und tatsächlich ein gutes Tutorial gefunden:  https://blog.magnusmontin.net/2013/05/30...tity-framework/

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von sugar76 am 22.06.2018 18:11.

22.06.2018 17:58 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 2 Jahre.
Der letzte Beitrag ist älter als 2 Jahre.
Antwort erstellen


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 24.10.2020 21:44