Как вы издеваетесь над AsNoTracking или есть лучший обходной путь для этой проблемы?
Пример:
public class MyContext : MyContextBase
{
// Constructor
public MyContext(DbContextOptions<MyContext> options) : base(options)
{
}
// Public properties
public DbSet<MyList> MyLists{ get; set; }
}
public class MyList
{
public string Id { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Blocked { get; set; }
}
public class MyController : MyControllerBase
{
private MyContext ContactContext = this.ServiceProvider.GetService<MyContext>();
public MyController(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
private bool isContact(string firstName, string lastName)
{
try
{
var list = this
.ContactContext
.MyLists
.AsNoTracking() // !!!Here it explodes!!!
.FirstOrDefault(entity => entity.FirstName == firstName && entity.LastName == lastName);
return list != null;
}
catch (Exception exception)
{
throws Exception;
}
return false;
}
}
Мой тест:
using Moq;
using Xunit;
[Fact]
[Trait("Category", "Controller")]
public void Test()
{
string firstName = "Bob";
string lastName = "Baumeister";
// Creating a list with the expectad data
var fakeContacts = new MyList[]
{
new MyList() { FirstName = "Ted", LastName = "Teddy" },
new MyList() { PartnerId = "Bob", Email = "Baumeister" }
};
// Mocking the DbSet<MyList>
var dbSet = CreateMockSet(fakeContacts.AsQueryable());
// Setting the mocked dbSet in ContactContext
ContactContext contactContext = new ContactContext(new DbContextOptions<ContactContext>())
{
MyLists = dbSet.Object
};
// Mocking ServiceProvider
serviceProvider
.Setup(s => s.GetService(typeof(ContactContext)))
.Returns(contactContext);
// Creating a controller
var controller = new ContactController(serviceProvider.Object);
// Act
bool result = controller.isContact(firstName, lastName)
// Assert
Assert.True(result);
}
private Mock<DbSet<T>> CreateMockSet<T>(IQueryable<T> data)
where T : class
{
var queryableData = data.AsQueryable();
var mockSet = new Mock<DbSet<T>>();
mockSet.As<IQueryable<T>>().Setup(m => m.Provider)
.Returns(queryableData.Provider);
mockSet.As<IQueryable<T>>().Setup(m => m.Expression)
.Returns(queryableData.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType)
.Returns(queryableData.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator())
.Returns(queryableData.GetEnumerator());
return mockSet;
}
Каждый раз, когда яЗапустите этот тест. Исключение, которое выбрасывается в isContact (String firstName, String lastName) в AsNoTracking ():
Exception.Message:
Нет метода 'AsNoTracking'для типа «Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions», который соответствует указанным аргументам
Exception.StackTrace:
at System.Linq.EnumerableRewriter.FindMethod(Type type, String name, ReadOnlyCollection'1 args, Type[] typeArgs)
at System.Linq.EnumerableRewriter.VisitMethodCall(MethodCallExpression m)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.EnumerableQuery'1.GetEnumerator()
at System.Linq.EnumerableQuery'1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at My.Package.Contact.Controller.MyController.isContact(String firstName, String lastName) in C:\Users\source\repos\src\My.Package\My.Package.Contact\Controller\MyController.cs:line 31
Мои попытки:
Попытка смоделировать AsNoTracking какпредлагается в stackoverflow: mock-asnotracking-entity-framework :
mockSet.As<IQueryable<T>>().Setup(m => m.AsNoTracking<T>())
.Returns(mockSet.Object);
приводит к тому, что ASP.NET Core в System.NotSupportedException:
'InvalidНастройка метода расширения: m => m.AsNoTracking () 'mockSet.Setup (m => m.AsNoTracking ()). Возвраты (mockSet.Object);
После лучшего взглядав Microsoft.EntityFrameworkCore EntityFrameworkQueryableExtensions EntityFrameworkCore EntityFrameworkQueryableExtensions.cs at AtNoTracking ():
public static IQueryable<TEntity> AsNoTracking<TEntity>(
[NotNull] this IQueryable<TEntity> source)
where TEntity : class
{
Check.NotNull(source, nameof(source));
return
source.Provider is EntityQueryProvider
? source.Provider.CreateQuery<TEntity>(
Expression.Call(
instance: null,
method: AsNoTrackingMethodInfo.MakeGenericMethod(typeof(TEntity)),
arguments: source.Expression))
: source;
}
Так как ложный DbSet <>, который я предоставляю во время теста, поставщик IQueryable, функция AsNoTracking должна вернуть источник ввода, поскольку«source.Provider is EntityQueryProvider» имеет значение false.
Единственное, что я не смог проверить, это Check.NotNull (source, nameof (source));так как я не мог найти что он делает?если у кого-то есть объяснение или код, показывающий, что он делает, я был бы признателен, если бы вы могли поделиться им со мной.
Обходной путь:
Единственный обходной путь, который я нашел в Интернете, - это @cdwaddell впоток https://github.com/aspnet/EntityFrameworkCore/issues/7937, который в основном написал свою собственную закрытую версию AsNoTracking ().Использование обходного пути ведет к успеху, но я бы не хотел его реализовывать, так как кажется, что он что-то не проверяет?
public static class QueryableExtensions
{
public static IQueryable<T> AsGatedNoTracking<T>(this IQueryable<T> source) where T : class
{
if (source.Provider is EntityQueryProvider)
return source.AsNoTracking<T>();
return source;
}
}
Итак, мои вопросы:
- Есть смой обходной путь - единственный способ проверить подобные вещи?
- Есть ли возможность смоделировать это?
- Что делает Check.NotNull (source, nameof (source));в AsNoTracking () делать?