using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Tango.CodeGeneration { /// /// Represents the Tango DAO Java code file. /// /// public class TangoDAOJavaFile : CodeFile { /// /// Gets or sets the class name. /// public String Name { get; set; } /// /// Gets or sets the entities. /// public List Entities { get; set; } /// /// Initializes a new instance of the class. /// public TangoDAOJavaFile() { Entities = new List(); } /// /// Represents a Tango DAO Java entity. /// public class TangoDAOEntity { /// /// Gets or sets the entity name. /// public String Name { get; set; } /// /// Gets or sets the name of the table. public String TableName { get; set; } } } }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Core.Commands;
using Tango.BL.Entities;
using Tango.MachineStudio.Common.Notifications;
using Tango.MachineStudio.DB.Managers;
using Tango.SharedUI;
using System.Data.Entity.Infrastructure;
using Tango.MachineStudio.DB.Messages;
using System.Collections.ObjectModel;
using System.Reflection;
using Tango.MachineStudio.Common.StudioApplication;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using Tango.BL;
using Tango.Core.DI;
using Tango.Core.ExtensionMethods;

namespace Tango.MachineStudio.DB.ViewModels
{
    public abstract class DbTableViewModel<T> : ViewModel where T : class, IObservableEntity
    {
        protected INotificationProvider _notification;

        /// <summary>
        /// Initializes a new instance of the <see cref="DbTableViewModel"/> class.
        /// </summary>
        public DbTableViewModel(INotificationProvider notification) : base()
        {
            _notification = notification;
            Adapter = ObservablesEntitiesAdapter.Instance;
            ValidationErrors = new ObservableCollection<string>();

            AddCommand = new RelayCommand(OnAdd);
            EditCommand = new RelayCommand(OnEdit, (x) => SelectedEntity != null);
            DeleteCommand = new RelayCommand(OnDelete, (x) => SelectedEntity != null);
            DialogOKCommand = new RelayCommand(() => OnDialogOKPressed(DialogOpenMode, EditEntity));
            DialogCancelCommand = new RelayCommand(() => OnDialogCancelPressed(DialogOpenMode, EditEntity));

            IsDialogOpen = false;
        }

        private T _editEntity;
        /// <summary>
        /// Gets or sets the edit entity.
        /// </summary>
        public T EditEntity
        {
            get { return _editEntity; }
            set { _editEntity = value; RaisePropertyChangedAuto(); }
        }

        private DialogOpenMode _dialogOpenMode;
        /// <summary>
        /// Gets or sets the dialog open mode.
        /// </summary>
        public DialogOpenMode DialogOpenMode
        {
            get { return _dialogOpenMode; }
            set { _dialogOpenMode = value; RaisePropertyChangedAuto(); }
        }

        private bool _isDialogOpen;
        /// <summary>
        /// Gets or sets a value indicating whether this instance is dialog open.
        /// </summary>
        public bool IsDialogOpen
        {
            get { return _isDialogOpen; }
            set { _isDialogOpen = value; RaisePropertyChangedAuto(); }
        }

        private ObservablesEntitiesAdapter _adapter;
        /// <summary>
        /// Gets or sets the DB adapter.
        /// </summary>
        public ObservablesEntitiesAdapter Adapter
        {
            get { return _adapter; }
            set { _adapter = value; RaisePropertyChangedAuto(); }
        }

        private T _selectedEntity;
        /// <summary>
        /// Gets or sets the selected entity.
        /// </summary>
        public T SelectedEntity
        {
            get { return _selectedEntity; }
            set { _selectedEntity = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
        }

        private String _filter;
        /// <summary>
        /// Gets or sets the search filter.
        /// </summary>
        public String Filter
        {
            get { return _filter; }
            set { _filter = value; RaisePropertyChangedAuto(); OnFilterChanged(value); }
        }

        /// <summary>
        /// Gets or sets the dialog OK command.
        /// </summary>
        public RelayCommand DialogOKCommand { get; set; }

        /// <summary>
        /// Gets or sets the dialog cancel command.
        /// </summary>
        public RelayCommand DialogCancelCommand { get; set; }

        /// <summary>
        /// Gets or sets the add command.
        /// </summary>
        public RelayCommand AddCommand { get; set; }

        /// <summary>
        /// Gets or sets the edit command.
        /// </summary>
        public RelayCommand EditCommand { get; set; }

        /// <summary>
        /// Gets or sets the delete command.
        /// </summary>
        public RelayCommand DeleteCommand { get; set; }

        protected override void OnValidating()
        {
            base.OnValidating();
            ValidationErrors.Clear();

            foreach (var prop in typeof(T).GetPropertiesWithAttribute<ColumnAttribute>(BindingFlags.Public | BindingFlags.Instance).Where(x => !x.PropertyType.IsGenericType && x.PropertyType.IsClass && !x.Name.Contains("Guid")))
            {
                if (prop.GetValue(EditEntity) == null)
                {
                    ValidationErrors.Add(prop.Name + " is required");
                }
            }
        }

        /// <summary>
        /// Called when delete command invoked.
        /// </summary>
        protected virtual async void OnDelete()
        {
            using (_notification.PushTaskItem("Saving changes to database..."))
            {
                try
                {
                    SelectedEntity.Detach(Adapter.Context);
                    await Adapter.Context.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    Adapter.Invalidate();
                    _notification.ShowError("Could not delete entity." + Environment.NewLine + ex.Message);
                }

                SelectedEntity = null;
            }
        }

        /// <summary>
        /// Called when edit command invoked.
        /// </summary>
        protected virtual void OnEdit()
        {
            ValidationErrors.Clear();
            DialogOpenMode = DialogOpenMode.Editing;
            EditEntity = GetEditableEntity(DialogOpenMode);
            TangoMessenger.Default.Send(new OpenEntityEditViewMessage(DialogOpenMode, this, typeof(T)));
            IsDialogOpen = true;
        }

        /// <summary>
        /// Called when add command invoked.
        /// </summary>
        protected virtual void OnAdd()
        {
            ValidationErrors.Clear();
            DialogOpenMode = DialogOpenMode.Adding;
            EditEntity = GetEditableEntity(DialogOpenMode);

            var codeProp = EditEntity.GetType().GetProperty("Code");

            if (codeProp != null)
            {
                if (EditEntity.GetDbSet<T>(Adapter.Context).Count() > 0)
                {
                    int lastCode = EditEntity.GetDbSet<T>(Adapter.Context).ToList().Max(x => (int)codeProp.GetValue(x));
                    codeProp.SetValue(EditEntity, lastCode + 1);
                }
            }

            TangoMessenger.Default.Send(new OpenEntityEditViewMessage(DialogOpenMode, this, typeof(T)));
            IsDialogOpen = true;
        }

        /// <summary>
        /// Called when dialog closes with OK button.
        /// </summary>
        /// <param name="mode">The mode.</param>
        protected virtual async void OnDialogOKPressed(DialogOpenMode mode, T entity)
        {
            if (!Validate()) return;

            if (ValidationErrors.Count > 0) return;

            var codeProp = entity.GetType().GetProperty("Code");

            if (codeProp != null)
            {
                int code = (int)codeProp.GetValue(entity);

                if (entity.GetDbSet<T>(Adapter.Context).ToList().Where(x => x.Guid != entity.Guid).Select(x => (int)codeProp.GetValue(x)).Contains(code))
                {
                    _notification.ShowError("The entity code specified already exists.");
                    return;
                }
            }

            TangoMessenger.Default.Send(new CloseEntityEditViewMessage());

            if (mode == DialogOpenMode.Editing)
            {
                entity.ShallowCopyTo(SelectedEntity);
                entity = SelectedEntity;
            }

            OnBeforeEntitySave(mode, entity);

            using (_notification.PushTaskItem("Saving changes to database..."))
            {
                if (mode == DialogOpenMode.Adding)
                {
                    entity.Attach(Adapter.Context);
                }

                try
                {
                    await entity.SaveAsync(Adapter.Context);
                }
                catch (DbUpdateException ex)
                {
                    if (mode == DialogOpenMode.Adding)
                    {
                        entity.Detach(Adapter.Context);
                    }
                    Adapter.Invalidate();
                    _notification.ShowError("Could not save entity." + Environment.NewLine + ex.InnerException.InnerException != null ? ex.InnerException.InnerException.Message : ex.InnerException.Message);
                }
                catch (Exception)
                {
                    Adapter.Invalidate();
                    _notification.ShowError("Could not save entity." + Environment.NewLine + "Please make sure all fields are properly populated.");
                }
                IsDialogOpen = false;
                SelectedEntity = EditEntity;
                SelectedEntity = null;
            }
        }

        /// <summary>
        /// Called when [before entity save].
        /// </summary>
        /// <param name="mode">The mode.</param>
        /// <param name="entity">The entity.</param>
        protected virtual void OnBeforeEntitySave(DialogOpenMode mode, T entity)
        {

        }

        /// <summary>
        /// Called when dialog closes with cancel button.
        /// </summary>
        /// <param name="mode">The mode.</param>
        protected virtual void OnDialogCancelPressed(DialogOpenMode mode, T entity)
        {
            TangoMessenger.Default.Send(new CloseEntityEditViewMessage());
            IsDialogOpen = false;
        }

        /// <summary>
        /// Gets the editable entity.
        /// </summary>
        /// <param name="mode">The mode.</param>
        /// <returns></returns>
        private T GetEditableEntity(DialogOpenMode mode)
        {
            if (mode == DialogOpenMode.Adding)
            {
                var newEntity = Activator.CreateInstance<T>();
                InitializeEntity(newEntity);
                return newEntity;
            }
            else
            {
                return SelectedEntity.ShallowClone();
            }
        }

        protected virtual void OnFilterChanged(String filter)
        {
            String viewSourceName = this.GetType().Name.Replace("ViewVM", "ViewSource");
            ICollectionView collectionView = Adapter.GetType().GetProperty(viewSourceName).GetValue(Adapter) as ICollectionView;

            collectionView.Filter = (entity) =>
            {
                return FilterEntity((T)entity, filter);
            };
        }

        private bool FilterEntity(T entity, String filter)
        {
            foreach (var prop in entity.GetType().GetPropertiesWithAttribute<ColumnAttribute>(BindingFlags.Public | BindingFlags.Instance).Where(x => x.PropertyType.IsClass && x.PropertyType != typeof(String) && x.PropertyType != typeof(byte[]) && !x.PropertyType.IsGenericType))
            {
                object obj = prop.GetValue(entity);

                if (obj != null)
                {
                    foreach (var innerProp in obj.GetType().GetPropertiesWithAttribute<ColumnAttribute>(BindingFlags.Public | BindingFlags.Instance).Where(x => x.Name != "Deleted" && x.Name != "ID" && x.Name != "LastUpdated").Where(x => !x.PropertyType.IsGenericType && (x.PropertyType.IsClass || x.PropertyType == typeof(String))))
                    {
                        object value = innerProp.GetValue(obj);

                        if (value != null)
                        {
                            if (value.ToString().ToLower().Contains(filter.ToLower()))
                            {
                                return true;
                            }
                        }
                    }
                }
            }

            return
              entity.
              GetType().
              GetPropertiesWithAttribute<ColumnAttribute>(BindingFlags.Public | BindingFlags.Instance).
              Where(x => x.Name != "Deleted" && x.Name != "ID" && x.Name != "LastUpdated").
              Where(x => !x.PropertyType.IsGenericType && (x.PropertyType.IsClass || x.PropertyType == typeof(String))).
              Select(prop => prop.GetValue(entity).ToString()).
              ToList().
              Any(x => x.ToLower().Contains(filter.ToLower()));
        }

        protected virtual void InitializeEntity(T entity)
        {

        }
    }
}