Обновление иерархической нумерации - PullRequest
0 голосов
/ 27 августа 2018

В моем приложении ниже классы, которые содержат иерархические данные, как показано ниже:

Class A 
{
   string Id{get;set;}
   string Name{get;set;}
   string Order{get;set;}
   string ParentId{get;set;}
}
Class B 
{
   string Id{get;set;}
   string Name{get;set;}
   string Order{get;set;}
   string ClassAId{get;set;}
}
Class C 
{
   string Id{get;set;}
   string Name{get;set;}
   string Order{get;set;}
   string ClassBId{get;set;}
}

Пример данных для класса A будет

Id = "1.1"                   Id = "2.1"
Name = "SomeName"            Name = "Name2"
Order = 1                    Order = 1
ParentId = "1"               ParentId = 2

Id = "1.2"                   Id = "2.2"
Name = "Name2"               Name = "Name3"
Order = 2                    Order = 2
ParentId = "1"               ParentId = 2

Пример данных для класса B будет

 Id = "1.1.1"                   Id = "2.1.1"
    Name = "SomeName"            Name = "Name2"
    Order = 1                    Order = 1
    ParentId = "1.1"               ParentId = 2.1

    Id = "1.2.1"                   Id = "2.1.2"
    Name = "Name2"               Name = "Name3"
    Order = 2                    Order = 2
    ParentId = "1.2"               ParentId = 2.1

Аналогично для класса C данные будут выглядеть как

Id = "1.1.1.1"                   Id = "2.1.1.1"
Name = "SomeName"            Name = "Name2"
Order = 1                    Order = 1
ParentId = "1.1.1"               ParentId = 2.1.1

Теперь, если пользователь хочет обновить значение между существующими значениями, то, как оно должно работать, предположим, что я ввожу значение от 1,2 до 1,3 для класса A, он должен сначала создать новое значение с именем 1,4, а затем переместить все содержимое 1.3 и его потомков до 1.4 (т. е. если у 1.3 есть свои дочерние элементы, такие как 1.3.1 и т. д., 1.3.1.1 и т. д., то все должны быть переименованы в 1.4.1 и 1.4.1.1 соответственно, а в 1.3 не должно быть любая иерархия с пустым значением. В основном между вставками следует обновить полную иерархию записи. Я могу правильно генерировать следующую последовательность, находя текущий Id и находя максимальный порядок и добавляя к нему 1. Проблема, с которой я сталкиваюсь, находится между вставками и обновление всей иерархии. Любые идеи помогут. Ниже приведен код, который я написал для ввода нового значения. Класс A:

// Находим максимальный ордер, увеличиваем его на 1 и вставляем новую запись.

var currentClass = listOfClassA.Where(x => x.Id = currentId).SingleOrDefault();
var maxOrder = listOfClassA.Max(x => x.Order);
var objClassA = new A();
objClassA.Order = maxOrder + 1;
objClassA.ParentId = currentClassA.ParentId;
objClassA.Name = "";
objClassA.Id = currentClassA.ParentId + "." + objClassA.Order;

Ответы [ 2 ]

0 голосов
/ 02 сентября 2018

Мы решили изменить наш дизайн, чтобы использовать динамические объекты расширения и использовать их для генерации иерархической нумерации [Наши требования заключались в использовании динамических коллекций (mongodb) и создании их на лету]. Хотя структура классов останется такой же, как указано выше. Ниже приведен код, который мы написали для иерархической нумерации. Этот код принимает Id в качестве ввода (например, 1.1 или 1.2 или 1.1.1 или 1.1.1.1)

                dynamic expando = new ExpandoObject();
                var collectionModel = expando as IDictionary<string, Object>;

                var lastDotPosition = value.LastIndexOf('.');
                var parentId = value.Substring(0, lastDotPosition);
                collectionModel.Add("ParentId", parentId);
                var order = Convert.ToInt32(value.Split('.').Last());


                var newOrder = order + 1;
                var Id = parentId + '.' + newOrder.ToString();

                collectionModel.Add("Index", newOrder);//newOrder
                collectionModel["Id"] = Id;

                var filter = Builders<dynamic>.Filter.Gt("Index", order);
                filter = filter & Builders<dynamic>.Filter.Eq("ParentId", parentId);
                var collection = _db.GetCollection<dynamic>(collectionName);

                var remainingList = collection.Find(filter).ToList();

                var dynamicList = new List<ExpandoObject>();
                dynamicList.Add((ExpandoObject)collectionModel);
                // below updates the next record ids and parent id to ensure numbering is maintained
                for (int i = 0; i < remainingList.Count; i++)
                {
                    var remainingRecord = remainingList[i] as IDictionary<string, object>;
                    var newRecord = new ExpandoObject() as IDictionary<string, Object>;
                    for(int j = 0; j < listOfFieldNames.Count; j++)
                    {
                        var fieldName = listOfFieldNames[j];
                        Object dictValue = "";
                        remainingRecord.TryGetValue(fieldName, out dictValue);
                        if (fieldName == "Id")
                        {
                            newRecord[fieldName] = parentId + "." + (newOrder + 1);
                        }
                        else
                        {
                            newRecord[fieldName] = dictValue;
                        }
                    }
                    newRecord["Index"] = newOrder + 1;
                    newRecord["ParentId"] = parentId;
                    newOrder++;

                    dynamicList.Add((ExpandoObject)newRecord);
                }


                //Now update child or grandchild if any

                var updateForChildList = remainingList.OrderByDescending(x => ((IDictionary<string, object>)x)["Index"]).ToList();

                for (int k = 0; k < updateForChildList.Count; k++)
                {
                    var oldRecord = updateForChildList[k] as IDictionary<string, object>;
                    var oldParentId = oldRecord["Id"];
                    Object dictValue = "";
                    oldRecord.TryGetValue("Index", out dictValue);

                    var newParentId = oldRecord["ParentId"] + "." + Convert.ToString(Convert.ToInt32(dictValue.ToString()) + 1);
                    UpdateParentIdForChildren(oldParentId.ToString(), newParentId, Convert.ToInt32(collectionOrder + 1));
                }
                collection.DeleteMany(filter);
                collection.InsertMany(dynamicList);

Используйте рекурсию, чтобы найти детей и внуков и обновить их парентиды и идентификаторы

public void UpdateParentIdForChildren(string oldParentId, string newParentId, int collectionIndex)
        {


            if (collectionIndex > collectionList.Count)
            {
                return;
            }


            var currentCollection = _db.GetCollection<dynamic>(collectionName);
            var filter = Builders<dynamic>.Filter.Eq("ParentId", oldParentId);
            var oldParentIdList = currentCollection.Find(filter).ToList();
            var reoldParentIdList = oldParentIdList.OrderByDescending(x => ((IDictionary<string, object>)x)["Index"]).ToList();
            if (reoldParentIdList.Count > 0)
            {
                for (int i = 0; i < reoldParentIdList.Count; i++)
                {
                    var remainingRecord = reoldParentIdList[i] as IDictionary<string, object>;

                    Object OldIdValue = "";
                    remainingRecord.TryGetValue("Id", out OldIdValue);

                    Object indexValue = "";
                    remainingRecord.TryGetValue("Index", out indexValue);

                    var newId = newParentId + '.' + indexValue;

                    currentCollection.UpdateOne(filter, Builders<dynamic>.Update.Set("Id", newId));
                    currentCollection.UpdateOne(filter, Builders<dynamic>.Update.Set("ParentId", newParentId));

                    UpdateParentIdForChildren(OldIdValue.ToString(), newId, collectionIndex + 1);
                }
            }
        }
0 голосов
/ 27 августа 2018

Просто идея, как по вашему запросу, но не будет ли проще включить классы в вашу иерархическую структуру данных, например ::100100

class A 
{
   public string Id{get;set;}
   public string Name{get;set;}
   public string Order{get;set;}
   //this is the tricky one.
   public string ParentId{get;set;}
}

class B 
{
   public string Id{get;set;}
   public string Name{get;set;}
   public string Order{get;set;}
   public A ClassA{get;set;}
}

class C 
{
   public string Id{get;set;}
   public string Name{get;set;}
   public string Order{get;set;}
   public B ClassB{get;set;}
}

Другая идея: поскольку ваши классы очень похожи, вы также можете создать настоящую иерархическую структуру, подобную этой:

public class Foo
{
    public string Id{get;set;}
    public string Name{get;set;}
    public string Order{get;set;}

    public Foo Parent {get;set;}
    public Foo Child{get;set;}
}


Развивая предыдущую идею, вы обнаружите, что вы создали что-то вроде LinkedList, например ::.
public class Foo
{
    public string Id{get;set;}
    public string Name{get;set;}
    public string Order{get;set;}
}

var list = new LinkedList<Foo>();


Еще один вариант: это более tree подобная структура, я думаю, что она называется составной шаблон :
public class Foo
{
    public string Id{get;set;}
    public string Name{get;set;}
    public string Order{get;set;}

    public Foo Parent {get;set;}
    public IEnumerable<Foo> Children{get;set;}
}

Надеюсь, это поможет. Использование одного из приведенных выше шаблонов облегчит создание иерархической строки идентификатора, например 1.2.3.4.e.t.c., если вам это даже нужно; потому что также очень легко сериализовать все это. Остерегайтесь круговых ссылок, хотя; -)

Также другие операции, чтобы найти максимумы или минимумы вполне выполнимы, используя SelectMany или рекурсивные вызовы.

...