使用LINQ从我的数据库中查询IQueryable结果,如何向IQueryable结果添加新记录.
我目前正在为MVC4应用程序中的存储库实现编写单元测试.为了模拟数据上下文,我开始采用这篇文章中的一些想法,但我现在发现了一些限制,让我怀疑是否有可能正确模拟IQueryable
.
特别是,我已经看到了一些测试通过但代码在生产中失败的情况,并且我无法找到任何方法来模拟导致此失败的行为.
例如,以下代码段用于选择Post
属于预定义类别列表的实体:
var posts = repository.GetEntities<Post>(); // Returns IQueryable<Post>
var categories = GetCategoriesInGroup("Post"); // Returns a fixed list of type Category
var filtered = posts.Where(p => categories.Any(c => c.Name == p.Category)).ToList();
Run Code Online (Sandbox Code Playgroud)
在我的测试环境中,我试图嘲弄posts
使用假DbSet
上面提到的实施,同时也通过创建List
的Post
实例并将其转换为IQueryable
使用AsQueryable()
扩展方法.这两种方法都在测试条件下工作,但代码实际上在生产中失败,但有以下例外:
System.NotSupportedException : Unable to create a constant value of type 'Category'. Only primitive types or enumeration types are supported in this context.
虽然像这样的LINQ问题很容易解决,但真正的挑战是找到它们,因为它们不会在测试环境中显示出来.
我期望我可以嘲笑实体框架的实施行为,这是不现实的IQueryable
吗?
谢谢你的想法,
蒂姆.
我目前正在使用IQueryable OrderBy方法订购自定义对象列表,如下所示:
mylist.AsQueryable().OrderBy("PropertyName");
Run Code Online (Sandbox Code Playgroud)
现在我希望按多个属性排序.有没有办法做到这一点?
谢谢,Yannis
我需要能够得到类似以下的东西才能工作:
Type type = ??? // something decided at runtime with .GetType or typeof;
object[] entityList = context.Resources.OfType<type>().ToList();
Run Code Online (Sandbox Code Playgroud)
这可能吗?如果有任何新内容允许,我可以使用.NET 4.
我正在尝试为我的IRepository
界面创建一个模拟:
public interface IRepository<T> : ICollection<T>, IQueryable<T>
{
}
Run Code Online (Sandbox Code Playgroud)
有了这个实现:
public class RepositoryFake<T> : List<T>, IRepository<T>
{
public Expression Expression
{
get
{
return this.AsQueryable().Expression;
}
}
public Type ElementType
{
get
{
return this.AsQueryable().ElementType;
}
}
public IQueryProvider Provider
{
get
{
return this.AsQueryable().Provider;
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我使用它时,我会遇到StackOverflow
异常.如何正确实现此接口才能只使用List
一个存储库?
用法很简单
[Test]
public void Test()
{
RepositoryFake<User> users = new RepositoryFake<User>();
users.Add(new User());
List<User> list = (from user in users
where user.Id == "5"
select …
Run Code Online (Sandbox Code Playgroud) 有没有办法知道是否IQueryable<T>
已订购(使用OrderBy
或OrderbyDescending
)?
所以我知道是打电话OrderBy
还是ThenBy
收集.
IQueryable<Contact> contacts = Database.GetContacts();
Run Code Online (Sandbox Code Playgroud)
我试过了contacts is IOrderedQueryable<Contact>
,但它总是如此.
编辑:我刚刚改变了我的例子,前一个并没有真正表明我的观点.假设GetContacts
使用Entity Framework并简单地返回表的所有记录.
后来,我应用了几个函数contacts
,我不知道这些函数是做什么的.他们可以排序或过滤IQueryable<Contact>
.
当我收回集合时,我需要再次对它进行排序.为此,我需要知道是否需要打电话OrderBy
,或者ThenBy
.因此,如果已经对整个集合进行了排序,我不会重新排序.
请看这行代码.这是一个存储过程的调用,它返回一个ObjectResult<long?>
.为了提取长值,我添加了Select:
dbContext.FindCoursesWithKeywords(keywords).Select(l => l.Value);
Run Code Online (Sandbox Code Playgroud)
基于intellisense,这个Select返回IEnumerable<long>
.
我不确定我是否在某处读过它或者只是习惯了这个假设 - 我一直认为当EF API返回IEnumerable
(而不是IQueryable
)时,这意味着结果已经实现.意味着他们已从数据库中撤出.
我今天发现我错了(或者这可能是个错误?).我一直收到错误
"不允许新事务,因为会话中还有其他线程在运行"
基本上,此错误告诉您在db阅读器仍在读取记录时尝试保存更改.
最终我通过(我认为是一个长镜头)解决了这个问题并增加ToArray()
了实现IEnumerable<long>
......
那么 - 底线 - 我应该期望IEnumerable
EF的结果包含尚未实现的结果吗?如果是,那么有没有办法知道一个IEnumerable
是否已实现?
如果这是'duhhh'问题之一,感谢并道歉...... :)
混淆的场景:一个人有零个,一个或多个宠物.
使用Linq to Sql,需要获取IQueryable
给定personID的宠物列表.这是ERD中受损严重/被屠宰/混淆的部分:
码:
public IQueryable<Pet> GetPersonPets(int personID)
{
var personPets= from p in Person
where p.ID == somePersonID
select p.Pets;
return personPets; //fail
// return (IQueryable<Pet>)personPets //also fail
// return personPets.AsQueryable<Pet>() //also fail
}
Run Code Online (Sandbox Code Playgroud)
提出异常:
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable (System.Data.Linq.EntitySet(Pet))' to 'System.Linq.IQueryable(Pet)'. An explicit conversion exists (are you missing a cast?)
尝试失败:
直接投射不起作用: (IQueryable<MyType>)
调用收集方法AsQueryable
不起作用: .AsQueryable<MyType>()
问题:
如何正确地将LinqToSql查询的结果转换为IQueryable
?
知道为什么LINQ OrderBy不能在下面的代码中工作,(没有错误,但方法不排序......)
首先是我自己的类型
public class IQLinksView
{
public int id { get; set; }
public int catid { get; set; }
public int? viewed {get;set;}
public string name {get;set;}
public string desc {get;set;}
public string url {get;set;}
public string pic {get;set;}
public string cat {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
然后查询:
IQueryable<IQLinksView> newView =
from links in this.emContext.tbl_otherlinks
select new IQLinksView { id = links.pklinkid, catid =
links.tbl_catgeory.pkcategoryid, viewed = links.linkviewed, name = links.linkname,
desc = links.linkdesc, pic = links.linkpicture, url = links.linkurl, cat …
Run Code Online (Sandbox Code Playgroud) 所以,我已经阅读了所有关于是否将IQueryable暴露给你项目的其余部分的问题所在的问题(见这里和这里),我最终决定我不想要将IQueryable暴露给我的模型以外的任何东西.因为IQueryable与某些持久性实现有关,所以我不喜欢将自己锁定在其中的想法.同样,我不确定我对调用链中的类进一步修改不在存储库中的实际查询的感觉有多好.
那么,有没有人有任何关于如何编写一个干净简洁的存储库而不这样做的建议?我看到的一个问题是,我的存储库将从大量方法中爆炸,我需要过滤掉我的查询.
有一堆:
IEnumerable GetProductsSinceDate(DateTime date);
IEnumberable GetProductsByName(string name);
IEnumberable GetProductsByID(int ID);
Run Code Online (Sandbox Code Playgroud)
如果我允许传递IQueryable,我可以很容易地拥有一个看起来像这样的通用存储库:
public interface IRepository<T> where T : class
{
T GetById(int id);
IQueryable<T> GetAll();
void InsertOnSubmit(T entity);
void DeleteOnSubmit(T entity);
void SubmitChanges();
}
Run Code Online (Sandbox Code Playgroud)
但是,如果你没有使用IQueryable,那么像GetAll()这样的方法并不实用,因为延迟评估不会发生.我不想只返回10,000条记录,以后再使用其中的10条.
这是什么答案?在Conery的MVC店面中,他创建了另一个名为"服务"层的层,该层从存储库接收了IQueryable结果,并负责应用各种过滤器.
这是我应该做的,或类似的东西?让我的存储库返回IQueryable但是通过将其隐藏在一堆过滤器类(如GetProductByName)后限制对它的访问,这将返回像IList或IEnumerable这样的具体类型?
iqueryable ×10
linq ×6
c# ×4
linq-to-sql ×2
sql-order-by ×2
.net ×1
c#-4.0 ×1
collections ×1
entity ×1
frameworks ×1
ienumerable ×1
mocking ×1
reflection ×1
repository ×1
sorting ×1