如何Moq实体框架SqlQuery调用 [英] How to Moq Entity Framework SqlQuery calls
问题描述
我已经能够使用这个 DbSet gb / data / dn314429.aspx>链接。
然而,我现在想知道如何可以模拟对SqlQuery的调用。不知道这是否可行,或者它依赖于嘲弄的数据库环境,知道正在调用什么查询。
下面是我试图嘲笑的内容。 / p>
var myObjects = DbContext.Database
.SqlQuery< MyObject>(exec [dbo]。[my_sproc] {0 },some_value)
.ToList();
我目前还没有尝试过,因为不知道如何开始嘲笑这个例子。 >
嘲笑 DbSet
在下面,并重新迭代,我可以正确地模拟返回一个 DbSet
的 MyObject
,但现在我试图模拟一个SqlQuery,返回一个 MyObject
的。
var dbContext = new Mock< MyDbContext>();
dbContext.Setup(m => m.MyObjects).Returns(mockObjects.Object);
dbContext.Setup(m => m.Database.SqlQuery ...沿着这些行的东西
Database.SqlQuery< T>
未标记为虚拟,但 Set< T> .SqlQuery
被标记为虚拟。
根据 Database.SqlQuery< T>
文档
结果即使返回的
类型的对象是实体类型,这个查询也不会被上下文跟踪。使用'SqlQuery(String,
Object [])'方法返回由
上下文跟踪的实体。
和
设置< T> .SqlQuery
文档
默认情况下,返回的实体被上下文跟踪;这可以通过在返回的DbRawSqlQuery上调用AsNoTracking来更改
。
然后$ code Database.SqlQuery< ; T>(String,Object [])应该等价于
Set< T> .SqlQuery(String,Object [])AsNoTracking()
(仅当T
是EF实体,而不是DTO / VM)。
所以如果你可以替换实现到:
var myObjects = DbContext
.Set< MyObject>()
.SqlQuery( exec [dbo]。[my_sproc] {0},some_value)
.AsNoTracking()
.ToList();
您可以按照以下方式嘲笑
var list = new []
{
new MyObject {Property =some_value},
new MyObject {Property =some_value},
new MyObject {Property =another_value}
};
var setMock = new Mock< DbSet< MyObject>>();
setMock.Setup(m => m.SqlQuery(It.IsAny< string>(),It.IsAny< object []>()))
.Returns< string,object [] >((sql,param)=>
{
//按属性过滤
var filteredList = param.Length == 1
?list.Where(x = > x.Property == param [0] as string)
:list;
var sqlQueryMock = new Mock< DbSqlQuery< MyObject>>();
sqlQueryMock.Setup(m = > m.AsNoTracking())
.Returns(sqlQueryMock.Object);
sqlQueryMock.Setup(m => m.GetEnumerator())
.Returns(filteredList.GetEnumerator() );
return sqlQueryMock.Object;
});
var contextMock = new Mock< MyDbContext>();
contextMock.Setup(m => m.Set< MyObject>())。Returns(setMock.Object);
I've been able to mock
DbSet
's from entity framework with Moq using this link.However, I would now like to know how I could mock the call to SqlQuery. Not sure if this is possible or how as it relies on the mocked db context knowing what "query" is being called.
Below is what I am trying to mock.
var myObjects = DbContext.Database .SqlQuery<MyObject>("exec [dbo].[my_sproc] {0}", "some_value") .ToList();
I currently haven't tried anything as did not know how to start mocking this example.
The mocking of the
DbSet
is below and to re-iterate, I can correctly mock returning aDbSet
ofMyObject
's but now am trying to mock a SqlQuery that returns a list ofMyObject
's.var dbContext = new Mock<MyDbContext>(); dbContext.Setup(m => m.MyObjects).Returns(mockObjects.Object); dbContext.Setup(m => m.Database.SqlQuery... something along these lines
解决方案
Database.SqlQuery<T>
is not marked as virtual, butSet<T>.SqlQuery
is marked as virtual.Based on
Database.SqlQuery<T>
documentationThe results of this query are never tracked by the context even if the type of object returned is an entity type. Use the 'SqlQuery(String, Object[])' method to return entities that are tracked by the context.
and
Set<T>.SqlQuery
documentationBy default, the entities returned are tracked by the context; this can be changed by calling AsNoTracking on the DbRawSqlQuery returned.
then the
Database.SqlQuery<T>(String, Object[])
should be equivalent withSet<T>.SqlQuery(String, Object[]).AsNoTracking()
(only ifT
is EF entity, not a DTO / VM).So if you can replace the implementation into:
var myObjects = DbContext .Set<MyObject>() .SqlQuery("exec [dbo].[my_sproc] {0}", "some_value") .AsNoTracking() .ToList();
you can mock it as follow
var list = new[] { new MyObject { Property = "some_value" }, new MyObject { Property = "some_value" }, new MyObject { Property = "another_value" } }; var setMock = new Mock<DbSet<MyObject>>(); setMock.Setup(m => m.SqlQuery(It.IsAny<string>(), It.IsAny<object[]>())) .Returns<string, object[]>((sql, param) => { // Filters by property. var filteredList = param.Length == 1 ? list.Where(x => x.Property == param[0] as string) : list; var sqlQueryMock = new Mock<DbSqlQuery<MyObject>>(); sqlQueryMock.Setup(m => m.AsNoTracking()) .Returns(sqlQueryMock.Object); sqlQueryMock.Setup(m => m.GetEnumerator()) .Returns(filteredList.GetEnumerator()); return sqlQueryMock.Object; }); var contextMock = new Mock<MyDbContext>(); contextMock.Setup(m => m.Set<MyObject>()).Returns(setMock.Object);
这篇关于如何Moq实体框架SqlQuery调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!