• 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
131 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 136 wizyt
0 głosów
0 odpowiedzi 127 wizyt
0 głosów
1 odpowiedź 153 wizyt
pytanie zadane 8 stycznia 2017 w C# przez jankustosz1 Nałogowiec (35,940 p.)

92,760 zapytań

141,684 odpowiedzi

320,470 komentarzy

62,104 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

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!

...