Как создать пустой объект запроса типа generi c IMongoQueryable <TEntity> - PullRequest
1 голос
/ 17 апреля 2020

Метод, который я использую, возвращает запрашиваемый объект типа IMongoQueryable<TEntity>. Результат этого метода возвращает default(IMongoQueryable<TEntity>), когда база данных mongodb выдает ошибку. Вместо результата по умолчанию я хочу заменить эту строку пустым запрашиваемым объектом, однако библиотека MongoDb Linq не предоставляет ничего.

//Sample of the code
public IMongoQueryable<TEntity> AllQueryable<TEntity>(AggregateOptions options = null) where TEntity : Entity
{
    try
    {
        return GetCollection<TEntity>().AsQueryable(options);
    }
    catch (Exception ex)
    {
        return default(IMongoQueryable<TEntity>);
    }
}

Итак, как мне реализовать пользовательский тип, эквивалентный * 1006? * или что-то вроде IEnumerable<TEntity>().AsMongoQueryable()?

//I need something like this
public IMongoQueryable<TEntity> AllQueryable<TEntity>(AggregateOptions options = null) where TEntity : Entity
{
    try
    {
        return GetCollection<TEntity>().AsQueryable(options);
    }
    catch (Exception ex)
    {
        return Enumerable.Empty<TEntity>().AsMongoQueryable();
    }
}

1 Ответ

1 голос
/ 18 апреля 2020

При отладке приложения C# вы можете заметить, что запуск .AsQueryable<T> в коллекции MongoDB возвращает экземпляр класса MongoQueryableImpl , который внутренний в MongoDB.Driver.Linq пространстве имен. Вы можете попытаться создать экземпляр этого класса, используя отражение, но есть более простой способ.

Вы можете реализовать собственную реализацию интерфейса IMongoQueryable<T>, следуя шаблону проектирования Null Object.

Для интерфейса требуется несколько методов, но вы можете оставить большинство из них нереализованными - они вам никогда не понадобятся. Таким образом, ваш EmptyMongoQueryable<T> может выглядеть так:

public class EmptyMongoQueryable<T> : IMongoQueryable<T>
{
    public Expression Expression => Expression.Constant(this, typeof(IMongoQueryable<T>));
    public Type ElementType => typeof(T);
    public IQueryProvider Provider => new EmptyQueryProvider();
    public IEnumerator<T> GetEnumerator()
    {
        yield break;
    }

    public QueryableExecutionModel GetExecutionModel() => throw new NotImplementedException();
    public IAsyncCursor<T> ToCursor(CancellationToken cancellationToken = default(CancellationToken)) => throw new NotImplementedException();
    public Task<IAsyncCursor<T>> ToCursorAsync(CancellationToken cancellationToken = default(CancellationToken)) => throw new NotImplementedException();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

Тогда вы можете запустить следующий код:

var queryable = new EmptyMongoQueryable<YourType>();
var emptyList = queryable.ToList();

РЕДАКТИРОВАТЬ: так как вы упомянули в комментарии, что вы хотите запустить .Where() вам необходимо предоставить IQueryProvider. Та же история - драйвер MongoDB использует внутренний класс, но вы можете создать свой собственный:

public class EmptyQueryProvider : IQueryProvider
{
    public IQueryable CreateQuery(Expression expression) => null;
    public IQueryable<TElement> CreateQuery<TElement>(Expression expression) => new EmptyMongoQueryable<TElement>();
    public object Execute(Expression expression) => default(object);
    public TResult Execute<TResult>(Expression expression) => default(TResult);
}

Это позволит вам запустить Where() на вашем EmptyMongoQueryable<T>.

...