Создание общего метода обновления для хранилища MongoDb - PullRequest
0 голосов
/ 13 октября 2018

Я пытаюсь реализовать BaseRepository следующим образом:

public interface IRepository<T>
{    
   Task<T> Update(T entity, IEnumerable<UpdateFieldDefinition> update);
}
public class BaseRepository<T> : IRepository<T> where T : BaseEntity{
}

С BaseEntity - простым классом, который используется для всех сущностей, хранящихся в монго.Поскольку репозиторий будет вызываться из основного проекта через интерфейс, а основной проект не должен знать, что реализация БД - MongoDb, я использовал объект для передачи в Update, называемый UpdateFieldDefinition, определенный следующим образом:

public class UpdateFieldDefinition
    {
        public UpdateFieldDefinition(string propertyName, object propertyValue)
        {
            PropertyName = propertyName;
            PropertyValue = propertyValue;
        }
        public string PropertyName { get; set; }
        public object PropertyValue { get; set; }
    }

Итак, когда мне нужно обновить роль, я сделаю что-то вроде этого:

    var updateFields = new List<UpdateFieldDefinition>();
    var newNameValue = "Test";
    var newListValue = new List<string> { "1", "2" };
    updateFields.Add(new UpdateFieldDefinition("Name", newNameValue));
    updateFields.Add(new UpdateFieldDefinition("ListValues", newListValue));
    var testObj = await testRepository.Update(updateEntity, updateFields);

И реализация обновления будет такой:

public async Task<T> Update(T entity, IEnumerable<UpdateFieldDefinition> updateFieldDefinitions)
{
    var builder = new UpdateDefinitionBuilder<T>();
    var options = new FindOneAndUpdateOptions<T>
    {
        ReturnDocument = ReturnDocument.After,
        IsUpsert = false
    };
    //setting the fields to update based on what has been set from outside based on the Implemented BaseEntity T
    var updates = updateFieldDefinitions
        .Select(updateFieldDefinition =>
            builder.Set(updateFieldDefinition.PropertyName, updateFieldDefinition.PropertyValue))
        .ToList();
    //add update for LastModifiedDate => 
    updates.Add(builder.Set(x => x.LastModifiedDate, DateTime.Now));

    var filter = Builders<T>.Filter.Eq(en => en.Id, entity.Id);
    var updateCmd = builder.Combine(updates);
    var result = await DbContext.GetCollection<T>().FindOneAndUpdateAsync(filter, updateCmd, options);
    return result;
}

Но это не работает, потому что, когда он встречает «ListValue», который является списком, но внутри UpdateFieldDefinition хранится как объект, система пытается преобразовать его в строку, выдав эту ошибку: Cannot deserialize a 'List<String>' from BsonType 'String'.

Есть ли способ справиться с этим?Данный код является упрощенной версией проблемы, так как я создал метод расширения для BaseEntity, который создаст список UpdateFieldDefinition, используя отражение во всех свойствах типа T.

// EDIT1, добавив пример того, какя получаю для сущности список UpdateFieldDefinitions

public static class EntityHelper
    {
        public static IEnumerable<UpdateFieldDefinition> GetUpdateDefinition<T>(this T entity)
        {
            return entity.GetType().GetProperties()
                .Where(x =>
                {
                    switch (x.Name)
                    {
                        case nameof(BaseEntity.Id):
                        case nameof(BaseEntity.CreationDate):
                        case nameof(BaseEntity.LastModifiedDate):
                        case nameof(BaseEntity.CreatorId):
                        case nameof(BaseEntity.LastModifierUserId):
                            return false;
                        default:
                            return true;
                    }
                })
                .Select(x => new UpdateFieldDefinition(x.Name, x.GetValue(entity)));
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...