DataContractSerializer, добавление сериализации T к сериализации List <T> - PullRequest
0 голосов
/ 24 сентября 2018

Ради обучения я пытаюсь абстрагироваться от доступа к БД, надеясь сделать возможным просто подключить XML-файл или JSON-файл для обслуживания доступа к данным.

Теперь мой тип имеет следующееконструктор

public XmlRepository(XElement root)
{
        _rootElement = root;
        Load();
}

Зависимость (root) предоставляется типом XmlContext следующим образом:

private void Load()
    {
        if (!File.Exists(_fileName))
        {
            var schoolsXElement = new XElement("Schools");
            var gradesXElement = new XElement("Grades");
            var teachersXElement = new XElement("Teachers");
            var studentsXElement = new XElement("Students");

            _document = new XDocument(new XElement("DB"));
            _document.Root.Add(schoolsXElement);
            _document.Root.Add(gradesXElement);
            _document.Root.Add(teachersXElement);
            _document.Root.Add(studentsXElement);
            using (var fs = new FileStream(_fileName, FileMode.Create))
            {
                _document.Save(fs);
            }

        }
        else
        {
            _document = XDocument.Load(_fileName);
        }

        Schools = new XmlRepository<School>(_document.Root.Element("Schools"));
        Grades = new XmlRepository<Grade>(_document.Root.Element("Grades"));
        Teachers = new XmlRepository<Teacher>(_document.Root.Element("Teachers"));
        Students = new XmlRepository<Student>(_document.Root.Element("Students"));
    }

Эти методы определены в XmlRepository<T>, которые можно вызывать при внесении изменений впросмотр данных в памяти должен быть сохранен в файл.

private void Load()
    {
        if (!_rootElement.HasElements)
        {
            _persistentStorage = new List<T>();
            _memoryStorage = new List<T>();
            return;
        }

        var xmlDeserializer = new DataContractSerializer(typeof(List<T>));
        var obj = xmlDeserializer.ReadObject(_rootElement.FirstNode.CreateReader()) as List<T>;
        _persistentStorage = new List<T>(obj);
        _memoryStorage = new List<T>(obj);
    }

    private void Save()
    {
        var xmlSerializer = new DataContractSerializer(typeof(List<T>));
        var newAdditions = _memoryStorage.Except(_persistentStorage).ToList();
        _persistentStorage.AddRange(newAdditions);
        _rootElement.RemoveAll();
        using (var fs = _rootElement.CreateWriter())
        {
            xmlSerializer.WriteObject(fs, _persistentStorage);
        }
    }

private void Save()
    {
        var xmlSerializer = new DataContractSerializer(typeof(List<T>));
        var newAdditions = _memoryStorage.Except(_persistentStorage).ToList();
        _persistentStorage.AddRange(newAdditions);
        _rootElement.RemoveAll();
        using (var fs = _rootElement.CreateWriter())
        {
            xmlSerializer.WriteObject(fs, _persistentStorage);
        }
    }

Все это отображает следующий XML (из тестового прогона)

<?xml version="1.0" encoding="utf-8"?>
<DB>
  <Schools>
    <ArrayOfSchool xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/LearningProject.Models" />
  </Schools>
  <Grades>
    <ArrayOfClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="LearningProject.Models">
      <Class>
        <Id xmlns="http://schemas.datacontract.org/2004/07/LearningProject.Models">0</Id>
        <Grade>126368128361</Grade>
        <Students xmlns:d3p1="http://schemas.datacontract.org/2004/07/LearningProject.Models" i:nil="true" />
        <Teacher i:nil="true" />
      </Class>
      <Class>
        <Id xmlns="http://schemas.datacontract.org/2004/07/LearningProject.Models">1</Id>
        <Grade>126368128361</Grade>
        <Students xmlns:d3p1="http://schemas.datacontract.org/2004/07/LearningProject.Models" i:nil="true" />
        <Teacher i:nil="true" />
      </Class>
    </ArrayOfClass>
  </Grades>
  <Teachers>
    <ArrayOfTeacher xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/LearningProject.Models" />
  </Teachers>
  <Students>
    <ArrayOfStudent xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/LearningProject.Models" />
  </Students>
</DB>

Теперь моя проблема сметод сохранения, я не чувствую себя комфортно, удаляя то, что было там, и заменяя его тем, что находится в постоянном хранилище.Предположим, что у меня есть 10K элементов там, и я добавляю только 1, я бы удалил 10K элементов, чтобы добавить еще 1.

Как мне вместо этого добавить XML-код?

1 Ответ

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

Форматы, такие как xml, просто не подходят для добавления, и ни один стандартный сериализатор xml не поддерживает то, что вы хотите сделать.

Чтобы избежать риска потери данных, вы, возможно, можете загрузить существующие данные, добавив новыеобъект, сериализуйте в другой файл , затем поменяйте местами (переименуйте) файлы.

Существуют другие форматы, более удобные для добавления.Например, protobuf не завершает корневой элемент, поэтому, если у вас есть сообщение вида:

message SomeRoot {
    repeated SomeType items = 1;
}

, вы можете объединить два списка (один на диске, другой в памяти), просто добавив второй список (с нулем, одним или несколькими элементами) в конце существующего файла;так;SomeRoot с 5 SomeType пунктами, просто добавленными SomeRoot с 3 SomeType элементами, идентичны с SomeRoot с 8 SomeType элементами.

...