Best way to implement “ReOrderable Collection” and Persist it to database

前端 未结 6 753
执笔经年
执笔经年 2021-01-03 12:12

My domain object :

public class MyDomainObject
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public int DisplayOrder { get; set         


        
6条回答
  •  执念已碎
    2021-01-03 12:38

    I maybe founded a solution by creating a custom List which take an Lamba Expression in constructor parameter in order the list to be able to self update items property "DisplayOrder".

    The sample class

    public class MyItem
    {
        public string Name { get; set; }
        public int DisplayOrder { get; set; }
    }
    

    The sample program

    public class Program
    {
        static void Main(string[] args)
        {
            var list = new DisplayOrderableList(p => p.DisplayOrder)
                           {
                               new MyItem{ Name = "Item 1"},
                               new MyItem{ Name = "Item 2"},
                               new MyItem{ Name = "Item 3"},
                           };
    
            var item = list.Where(p => p.Name == "Item 2").FirstOrDefault();
    
            list.MoveUp(item);
    
            list.ForEach(p => Console.WriteLine("{0}-{1}", p.Name, p.DisplayOrder));
            Console.WriteLine();
    
            list.MoveDown(item);
    
            list.ForEach(p => Console.WriteLine("{0}-{1}", p.Name, p.DisplayOrder));
            Console.WriteLine();
    
            Console.ReadLine();
        }
    }
    

    The custom implementation of DisplayOrderableList

    public class DisplayOrderableList : List
    {
        #region Private Fields
    
        private PropertyInfo _property;
    
        #endregion
    
        #region Constructors
    
        public DisplayOrderableList(Expression> expression)
        {
            ValidateExpression(expression);
        }
    
        #endregion
    
        #region Public Methods
    
        public void MoveUp(T item)
        {
            if (!Contains(item))
                throw new ArgumentNullException("item", "item doesn't exists in collection");
    
            var idx = IndexOf(item);
    
            RemoveAt(idx);
            if (idx > 0)
                Insert(idx - 1, item);
            else
                Insert(0, item);
    
            UpdateDisplayOrder();
        }
    
        public void MoveDown(T item)
        {
            if (!Contains(item))
                throw new ArgumentNullException("item", "item doesn't exists in collection");
    
            var idx = IndexOf(item);
    
            RemoveAt(idx);
            if (idx + 1 > Count)
                Add(item);
            else
                Insert(idx + 1, item);
    
            UpdateDisplayOrder();
        }
    
        #endregion
    
    
        #region Private Methods
    
        private void UpdateDisplayOrder()
        {
            foreach (var item in this)
            {
                _property.SetValue(item, IndexOf(item), null);
            }
        }
    
        #endregion
    
        #region Expression Methods
    
        private void ValidateExpression(Expression> expression)
        {
            var lamba = ToLambaExpression(expression);
    
            var propInfo = ToPropertyInfo(lamba);
    
            if (!propInfo.CanWrite)
            {
                throw new ArgumentException(String.Format("Property {0} as no setters", propInfo.Name));
            }
    
            _property = propInfo;
        }
    
        private static LambdaExpression ToLambaExpression(Expression expression)
        {
            var lambda = expression as LambdaExpression;
            if (lambda == null)
            {
                throw new ArgumentException("Invalid Expression");
            }
            var convert = lambda.Body as UnaryExpression;
            if (convert != null && convert.NodeType == ExpressionType.Convert)
            {
                lambda = Expression.Lambda(convert.Operand, lambda.Parameters.ToArray());
            }
            return lambda;
        }
    
        private static PropertyInfo ToPropertyInfo(LambdaExpression expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression", "Expression cannot be null.");
            }
    
            var prop = expression.Body as MemberExpression;
            if (prop == null)
            {
                throw new ArgumentException("Invalid expression");
            }
    
            var propInfo = prop.Member as PropertyInfo;
            if (propInfo == null)
            {
                throw new ArgumentException("Invalid property");
            }
    
            return propInfo;
        }
    
        #endregion
    }
    

    This now get the following output :

    Item 2-0
    Item 1-1
    Item 3-2
    
    Item 1-0
    Item 2-1
    Item 3-2
    

    It's a proof of concept and should be enhanced but it's a beggining.

    What do you think about this ?

提交回复
热议问题