如何Moq实体框架SqlQuery调用 [英] How to Moq Entity Framework SqlQuery calls

查看:150
本文介绍了如何Moq实体框架SqlQuery调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经能够使用这个 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 a DbSet of MyObject's but now am trying to mock a SqlQuery that returns a list of MyObject'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, but Set<T>.SqlQuery is marked as virtual.

Based on Database.SqlQuery<T> documentation

The 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 documentation

By 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 with Set<T>.SqlQuery(String, Object[]).AsNoTracking() (only if T 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆