locked
model class vs main data class RRS feed

  • Question

  • I have a class that represents a product in the product master.  And then when the product is shown on the screen there is a product row model class that contains a subset of the properties of the product row class. And also the properties of the model call RaisePropertyChanged when changed.  Which is fine, but it seems like a duplication of code. And I have to write code that copies properties between the model and the data class.

    Is there a better way?  

    This becomes a bigger problem for me when there is little difference between the properties of the model and the data class.  But the data class contains methods that have nothing to do with the model. 

    Kind of confusing.

    Saturday, May 28, 2016 3:27 PM

Answers

  • You could use automapper to copy data across.

    It's not usually worth the effort. Similarly, it's not usually worth defining a class with a subset of properties. This introduces another failure point anyhow, where the two can get out of step.

    I'm a big fan of DRY ( don't repeat yourself ) and if I've got a class with my properties in it then I prefer to somehow use that rather than copy to some other one. *

    I'll assume here you're working on a small to mid sized system.

    Often you don't need to raise property changed on every single property in a class. In fact often you're either editing or viewing the data of a specific class so you don't need any inotifypropertychanged on model properties.

    What I (we) usually do is "wrap" the model class in a viewmodel. Making the model class a public property so you can bind to any properties from it you want.

    For those that need to raise property changed we have an extra property in the viewmodel. The getter returns the model property and the setter sets it, raises propertychanged.

    This might give you a flavour of wrapping. It's just a thrown together example so don't worry about the business logic.

    Imagine we're using entity framework or whatever and the model class is Order. We're working with a collection of orders. Total is Quantity + Price. So when the user changes either we need to recalculate the total price and notify change.

        public class MainWindowViewModel : ViewModelBase
        {
            public ObservableCollection<Order> Orders { get; set; }
            = new ObservableCollection<Order>
            {
                new Order { Price=21.33M, Qty=2 },
                new Order { Price=121.33M, Qty=5 },
                new Order { Price=87.49M, Qty=11 },
                new Order { Price=2.76M, Qty=3 }
            };
            private OrderVM wrappedOrder;
    
            public OrderVM WrappedOrder
            {
                get { return wrappedOrder; }
                set { wrappedOrder = value; }
            }
    
        }
        public class OrderVM : ViewModelBase
        {
            private Order theOrder;
    
            public Order TheOrder
            {
                get { return theOrder; }
                set { theOrder = value; RaisePropertyChanged(); }
            }
            public double Qty
            {
                get
                {
                    return TheOrder.Qty;
                }
                set
                {
                    TheOrder.Qty = value;
                    RaisePropertyChanged();
                    Calculate();
                }
            }
            public decimal Price
            {
                get
                {
                    return TheOrder.Price;
                }
                set
                {
                    TheOrder.Price = value;
                    RaisePropertyChanged();
                    Calculate();
                }
            }
            private void Calculate()
            {
                TheOrder.Total = (decimal) (TheOrder.Qty * (double)TheOrder.Price);
                RaisePropertyChanged("TheOrder.Total");
            }
        }

    .

    *

    There are exceptions.

    Some huge enterprise systems, you want to use DTO as you have some enterprise service bus or 3 business servers, 2 message queues and 5 workflows between your front and back end.

    I could advise on massive systems but it seems unlikely that you'd be asking this sort of question here if you're working on Amazon's logistic chain.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Marked as answer by Steve Richter Saturday, May 28, 2016 4:56 PM
    Saturday, May 28, 2016 4:04 PM

All replies

  • You could use automapper to copy data across.

    It's not usually worth the effort. Similarly, it's not usually worth defining a class with a subset of properties. This introduces another failure point anyhow, where the two can get out of step.

    I'm a big fan of DRY ( don't repeat yourself ) and if I've got a class with my properties in it then I prefer to somehow use that rather than copy to some other one. *

    I'll assume here you're working on a small to mid sized system.

    Often you don't need to raise property changed on every single property in a class. In fact often you're either editing or viewing the data of a specific class so you don't need any inotifypropertychanged on model properties.

    What I (we) usually do is "wrap" the model class in a viewmodel. Making the model class a public property so you can bind to any properties from it you want.

    For those that need to raise property changed we have an extra property in the viewmodel. The getter returns the model property and the setter sets it, raises propertychanged.

    This might give you a flavour of wrapping. It's just a thrown together example so don't worry about the business logic.

    Imagine we're using entity framework or whatever and the model class is Order. We're working with a collection of orders. Total is Quantity + Price. So when the user changes either we need to recalculate the total price and notify change.

        public class MainWindowViewModel : ViewModelBase
        {
            public ObservableCollection<Order> Orders { get; set; }
            = new ObservableCollection<Order>
            {
                new Order { Price=21.33M, Qty=2 },
                new Order { Price=121.33M, Qty=5 },
                new Order { Price=87.49M, Qty=11 },
                new Order { Price=2.76M, Qty=3 }
            };
            private OrderVM wrappedOrder;
    
            public OrderVM WrappedOrder
            {
                get { return wrappedOrder; }
                set { wrappedOrder = value; }
            }
    
        }
        public class OrderVM : ViewModelBase
        {
            private Order theOrder;
    
            public Order TheOrder
            {
                get { return theOrder; }
                set { theOrder = value; RaisePropertyChanged(); }
            }
            public double Qty
            {
                get
                {
                    return TheOrder.Qty;
                }
                set
                {
                    TheOrder.Qty = value;
                    RaisePropertyChanged();
                    Calculate();
                }
            }
            public decimal Price
            {
                get
                {
                    return TheOrder.Price;
                }
                set
                {
                    TheOrder.Price = value;
                    RaisePropertyChanged();
                    Calculate();
                }
            }
            private void Calculate()
            {
                TheOrder.Total = (decimal) (TheOrder.Qty * (double)TheOrder.Price);
                RaisePropertyChanged("TheOrder.Total");
            }
        }

    .

    *

    There are exceptions.

    Some huge enterprise systems, you want to use DTO as you have some enterprise service bus or 3 business servers, 2 message queues and 5 workflows between your front and back end.

    I could advise on massive systems but it seems unlikely that you'd be asking this sort of question here if you're working on Amazon's logistic chain.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Marked as answer by Steve Richter Saturday, May 28, 2016 4:56 PM
    Saturday, May 28, 2016 4:04 PM
  • this is great Andy.  Thank you.

    Saturday, May 28, 2016 4:56 PM