web-dev-qa-db-ja.com

ViewModelでModelオブジェクトを公開する最良の方法は何ですか?

WPF MVVMアプリケーションで、Modelクラス(依存関係の原因)のインスタンスをViewModelに作成することによって、モデルオブジェクトをviewModelに公開しました。個別のVMプロパティを作成する代わりに、ModelプロパティをViewModelプロパティ内にラップします。

私のモデルは、エンティティフレームワークによって生成されたプロキシクラスです。

public partial class TblProduct
{
    public TblProduct()
    {
        this.TblPurchaseDetails = new HashSet<TblPurchaseDetail>();
        this.TblPurchaseOrderDetails = new HashSet<TblPurchaseOrderDetail>();
        this.TblSalesInvoiceDetails = new HashSet<TblSalesInvoiceDetail>();
        this.TblSalesOrderDetails = new HashSet<TblSalesOrderDetail>();
    }

    public int ProductId { get; set; }
    public string ProductCode { get; set; }
    public string ProductName { get; set; }
    public int CategoryId { get; set; }
    public string Color { get; set; }
    public Nullable<decimal> PurchaseRate { get; set; }
    public Nullable<decimal> SalesRate { get; set; }
    public string ImagePath { get; set; }
    public bool IsActive { get; set; }

    public virtual TblCompany TblCompany { get; set; }
    public virtual TblProductCategory TblProductCategory { get; set; }
    public virtual TblUser TblUser { get; set; }
    public virtual ICollection<TblPurchaseDetail> TblPurchaseDetails { get; set; }
    public virtual ICollection<TblPurchaseOrderDetail> TblPurchaseOrderDetails { get; set; }
    public virtual ICollection<TblSalesInvoiceDetail> TblSalesInvoiceDetails { get; set; }
    public virtual ICollection<TblSalesOrderDetail> TblSalesOrderDetails { get; set; }
}

これが私のViewModelです:

public class ProductViewModel : WorkspaceViewModel
{
    #region Constructor
    public ProductViewModel()
    {
        StartApp();
    }

    #endregion //Constructor

    #region Properties

    private IProductDataService _dataService;
    public IProductDataService DataService
    {
        get
        {
            if (_dataService == null)
            {
                if (IsInDesignMode)
                {
                    _dataService = new ProductDataServiceMock();
                }
                else
                {
                    _dataService = new ProductDataService();
                }
            }
            return _dataService;
        }

    }

    //Get and set Model object
    private TblProduct _product;
    public TblProduct Product
    {
        get
        {
            return _product ?? (_product = new TblProduct());
        }
        set
        {
            _product = value;
        }
    }

    #region Public Properties

    public int ProductId
    {
        get
        {
            return Product.ProductId;
        }
        set
        {
            if (Product.ProductId == value)
            {
                return;
            }

            Product.ProductId = value;
            RaisePropertyChanged("ProductId");
        }
    }

    public string ProductName
    {
        get
        {
            return Product.ProductName;
        }
        set
        {
            if (Product.ProductName == value)
            {
                return;
            }

            Product.ProductName = value;
            RaisePropertyChanged(() => ProductName);
        }
    }

    private ObservableCollection<TblProduct> _productRecords;
    public ObservableCollection<TblProduct> ProductRecords
    {
        get { return _productRecords; }
        set
        {
            _productRecords = value;
            RaisePropertyChanged("ProductRecords");
        }
    }

    //Selected Product
    private TblProduct _selectedProduct;
    public TblProduct SelectedProduct
    {
        get
        {
            return _selectedProduct;
        }
        set
        {
            _selectedProduct = value;
            if (_selectedProduct != null)
            {
                this.ProductId = _selectedProduct.ProductId;
                this.ProductCode = _selectedProduct.ProductCode;
            }
            RaisePropertyChanged("SelectedProduct");
        }
    }

    #endregion  //Public Properties

    #endregion  // Properties

    #region Commands

    private ICommand _newCommand;
    public ICommand NewCommand
    {
        get
        {
            if (_newCommand == null)
            {
                _newCommand = new RelayCommand(() => ResetAll());
            }
            return _newCommand;
        }
    }

    private ICommand _saveCommand;
    public ICommand SaveCommand
    {
        get
        {
            if (_saveCommand == null)
            {
                _saveCommand = new RelayCommand(() => Save());
            }
            return _saveCommand;
        }
    }

    private ICommand _deleteCommand;
    public ICommand DeleteCommand
    {
        get
        {
            if (_deleteCommand == null)
            {
                _deleteCommand = new RelayCommand(() => Delete());
            }
            return _deleteCommand;
        }
    }

    #endregion //Commands

    #region Methods

    private void StartApp()
    {
        LoadProductCollection();
    }

    private void LoadProductCollection()
    {
        var q = DataService.GetAllProducts();
        this.ProductRecords = new ObservableCollection<TblProduct>(q);
    }


    private void Save()
    {
        if (SelectedOperateMode == OperateModeEnum.OperateMode.New)
        {
              //Pass the Model object into Dataservice for save
              DataService.SaveProduct(this.Product);
        }
        else if (SelectedOperateMode == OperateModeEnum.OperateMode.Edit)
        {
             //Pass the Model object into Dataservice for Update
              DataService.UpdateProduct(this.Product);
        }
        ResetAll();
        LoadProductCollection();
    }


    #endregion  //Methods
}

これが私のServiceクラスです:

class ProductDataService:IProductDataService
{
    /// <summary>
    /// Context object of Entity Framework model
    /// </summary>
    private MaizeEntities Context { get; set; }

    public ProductDataService()
    {
        Context = new MaizeEntities();
    }

    public IEnumerable<TblProduct> GetAllProducts()
    {
        using(var context=new R_MaizeEntities())
        {
           var q = from p in context.TblProducts
                   where p.IsDel == false
                   select p;

            return new ObservableCollection<TblProduct>(q);
        }
    }

    public void SaveProduct(TblProduct _product)
    {
        using(var context=new R_MaizeEntities())
        {
            _product.LastModUserId = GlobalObjects.LoggedUserID;
            _product.LastModDttm = DateTime.Now;
            _product.CompanyId = GlobalObjects.CompanyID;
            context.TblProducts.Add(_product);

            context.SaveChanges();
        }
    }

    public void UpdateProduct(TblProduct _product)
    {
        using (var context = new R_MaizeEntities())
        {
            context.TblProducts.Attach(_product);

            context.Entry(_product).State = EntityState.Modified;
            _product.LastModUserId = GlobalObjects.LoggedUserID;
            _product.LastModDttm = DateTime.Now;
            _product.CompanyId = GlobalObjects.CompanyID;
            context.SaveChanges();
        }
    }

    public void DeleteProduct(int _productId)
    {
        using (var context = new R_MaizeEntities())
        {
            var product = (from c in context.TblProducts
                    where c.ProductId == _productId
                    select c).First();

            product.LastModUserId = GlobalObjects.LoggedUserID;
            product.LastModDttm = DateTime.Now;
            product.IsDel = true;
            context.SaveChanges();
        }
    }


}

新しいキーワードを使用してそのインスタンスを作成することで、viewModelでモデルオブジェクトを公開しました。また、VMでDataServiceクラスをインスタンス化しました。これは強い依存関係を引き起こすことを知っています。

そう:

  1. ViewModelでModelオブジェクトを公開する最良の方法は何ですか?
  2. VMでDataServiceを使用する最良の方法は何ですか?
6
Angel

原則として、ViewModelオブジェクトでModelオブジェクトを公開することはお勧めできません。 ViewModelクラスの形式は、それを使用するビューのニーズによって決定される必要があります。 Modelクラスの形式は、データモデルの考慮事項によって決定される必要があります。

Entity FrameworkとMVVMパターンでの私の経験では、ViewModelオブジェクトにデータを入力するときにEFデータを変換するのが最善であると思いました。 ViewModelオブジェクトには、データモデルのデータが含まれますが、形式は異なります。ユーザーがデータを変更できるようにする必要がある場合、データストアに永続化できるように、変更されたViewModelデータをモデルデータに変換し直すメソッドが必要になることがよくあります。

4
gpersell