• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Jak zrobić kopie property?

Object Storage Arubacloud
0 głosów
124 wizyt
pytanie zadane 11 czerwca 2017 w C# przez Marcino24 Nowicjusz (140 p.)

Witam, mam problem gdyż potrzebuje zrobić kopie property ze względu na to że operuje na obiektowej bazie danych i żeby zrobić update na danym rekordzie potrzebuje oryginalnych właściowości. Próbowałem zrobić coś takiego jak poniżej ale każda zmiana wartości w SelectedPerson1 zmienia również właściwości w SelectedPerson. 

 private Person _selectedPerson;
 
        public Person SelectedPerson
        {
            get { return _selectedPerson; }
            set
            {
                _selectedPerson = value;
                _selectedPerson1 = value;
                OnPropertyChanged(nameof(this.SelectedPerson));
            }
        }
 
        private Person_selectedPerson1;
 
        public Person SelectedPerson1
        {
            get { return _selectedPerson1; }
            set
            {
                _selectedPerson1 = value;
                OnPropertyChanged(nameof(this.SelectedPerson1));
            }
        }

 

2 odpowiedzi

0 głosów
odpowiedź 11 czerwca 2017 przez pulson666 Stary wyjadacz (12,560 p.)
może stworzyć nowy obiekt tej klasy i tam trzymać oryginalne wartości
0 głosów
odpowiedź 12 czerwca 2017 przez maciej.tokarz Nałogowiec (27,280 p.)

Może Ci się przyda, klasa robi kopię binarną obiektu i umożliwia również przywrócenie oryginału.

using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Windows;

namespace Tempus.Data
{
    /// <summary>
    ///     Klasa umożliwiająca przed rozpoczęciem edycji wykonanie binarnej kopii obiektu.
    ///     Ale co ważniejsze - udostępnia przywrócenie danych w przypadku anulowania operacji.
    /// </summary>
    public class EditableData<T> : IEditableObject, INotifyPropertyChanged where T : class
    {
        private byte[] _copy;
        private T _currentValue;
        private bool _hasConflict;
        private bool _isEdited;

        public void BeginEdit()
        {
            _isEdited = true;

            using (var ms = new MemoryStream())
            {
                new DataContractSerializer(typeof (T)).WriteObject(ms, this);
                _copy = ms.ToArray();
            }
        }

        public void EndEdit()
        {
            _isEdited = false;
        }

        public void CancelEdit()
        {
            _isEdited = false;

            // Jeśli w czasie edycji dane zostały zmienione przez innego użytkownika ustaw je jako aktualne.
            if (_hasConflict)
            {
                SetValues(_currentValue);
                _currentValue = null;
                _hasConflict = false;
                return;
            }

            // Jeżeli nie ma zmian zakończ.
            if (!HasChanges()) return;

            // Przywróć stan obiektu sprzed edycji.
            using (var ms = new MemoryStream(_copy))
            {
                var original = (T) new DataContractSerializer(typeof (T)).ReadObject(ms);
                SetValues(original);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public bool HasChanges()
        {
            using (var ms = new MemoryStream())
            {
                new DataContractSerializer(typeof (T)).WriteObject(ms, this);
                return !ms.ToArray().SequenceEqual(_copy);
            }
        }

        /// <summary>
        ///     Zaktualizuj obiekt nowymi wartościami.
        /// </summary>
        public void Update(T current)
        {
            // Jeśli dane są aktualnie edytowane poinformuj użytkownika o konflikcie i zapamiętaj nowy obiekt.
            if (_isEdited)
            {
                // Todo: zablokuj klawisz zamknij/zapisz.

                MessageBox.Show(
                    "Dane zostały zmienione przez innego użytkownika!\r\n" +
                    "Zapis zmian został zablokowany.");

                _currentValue = current;
                _hasConflict = true;

                return;
            }

            SetValues(current);
        }

        /// <summary>
        ///     Zastąp bieżące wartości właściwości nowymi.
        /// </summary>
        private void SetValues(T current)
        {
            var currentProperties = current.GetType().GetProperties();
            var properties = GetType().GetProperties();

            foreach (var property in properties)
            {
                var currentProperty = currentProperties.First(x => x.Name == property.Name);
                if (property.CanWrite) property.SetValue(this, currentProperty.GetValue(current, null));
                OnPropertyChanged(property.Name);
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

M.

komentarz 12 czerwca 2017 przez Marcino24 Nowicjusz (140 p.)
Jak tego użyć w WPFie?
komentarz 12 czerwca 2017 przez maciej.tokarz Nałogowiec (27,280 p.)

Wygląda to tak dla przykładu:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;

namespace Tempus.Data
{
    public sealed class Employee : EditableData<Employee>
    {
        public int Id { get; set; }

        [StringLength(50)]
        public string FirstName { get; set; }

        [StringLength(50)]
        public string LastName { get; set; }
    }
}

A zastosowanie...

Przed rozpoczęciem edycji jakiegoś pracownika robię jego kopię:

public void Load(Data.Employee employee, bool isNew)
        {
            employee.BeginEdit();

W przypadku aktualizowania (zapisu) sprawdzam czy są zmiany:

private async void Update()
        {
            if (!Employee.HasChanges()) return;

W przypadku anulowania edycji:

public void Cancel()
        {
            if (!_isNew) Employee.CancelEdit();

No i zamknięcie widoku jest równoznaczne z zakończeniem edycji:

public void Close()
        {
            if (!Validate()) return;
            Employee.EndEdit();
        }

Zwróć uwagę na .CancelEdit();, ta metoda przywraca z kopii wartości oryginalne obiektu:

// Przywróć stan obiektu sprzed edycji.
            using (var ms = new MemoryStream(_copy))
            {
                var original = (T) new DataContractSerializer(typeof (T)).ReadObject(ms);
                SetValues(original);
            }

M.

komentarz 13 czerwca 2017 przez Marcino24 Nowicjusz (140 p.)
Powiem ci tak spoko metodka, ale chyba nie oto mi chodzi bo ta metoda pozwala tylko nadpisać modyfikacje albo anulować a ja robię program do edycji bazy obiektowej i potrzebuje oryginalne wartości oraz zmodyfikowane i dlatego potrzebuje zrobić kopie property.
komentarz 13 czerwca 2017 przez maciej.tokarz Nałogowiec (27,280 p.)

Jeśli używasz EF to może w taki sposób - przykładowo:

private void AddChangesLog(DbContext dataContext)
        {
            var changedEntities =
                dataContext.ChangeTracker.Entries().
                    Where(p =>
                        p.State == EntityState.Added ||
                        p.State == EntityState.Modified).ToArray();

            var states = new Dictionary<EntityState, string>
            {
                {EntityState.Modified, "Zmodyfikowano"},
                {EntityState.Added, "Dodano"}
            };

            foreach (var entity in changedEntities)
            {
                Message.AppendLine();
                Message.AppendLine($"{states[entity.State]}");
                Message.AppendLine("--------------------------------------");

                if (entity.State != EntityState.Added)
                {
                    Message.AppendLine("Wartości oryginalne:");
                    foreach (var propertyName in entity.OriginalValues.PropertyNames)
                        Message.AppendLine($"{propertyName} = {entity.OriginalValues[propertyName]}");
                    Message.AppendLine();
                }

                Message.AppendLine("Wartości aktualne:");
                foreach (var propertyName in entity.CurrentValues.PropertyNames)
                    Message.AppendLine($"{propertyName} = {entity.CurrentValues[propertyName]}");
            }

            if (MainModule.Sources.First().Created != new DateTime(1, 1, 1))
            {
                //LogManager.GetLogger("Message").Info(Message.ToString());
                EmailMessage.AppendLine(Message.ToString());
            }

            Message.Clear();
        }

M.

Podobne pytania

0 głosów
0 odpowiedzi 126 wizyt
0 głosów
0 odpowiedzi 117 wizyt
0 głosów
1 odpowiedź 141 wizyt
pytanie zadane 8 stycznia 2017 w C# przez jankustosz1 Nałogowiec (35,880 p.)

92,579 zapytań

141,432 odpowiedzi

319,664 komentarzy

61,964 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...