C# LINQ—在C中运行时更改数据源(和LINQ提供程序)#
我正在设计一个数据信息接口层。我希望这一层的用户不知道数据源,仍然使用LINQ语法的优点。我希望使用标准LINQ提供程序作为该层的实现,并希望避免编写自定义LINQ提供程序 考虑下面的例子 信息接口层声明如下C# LINQ—在C中运行时更改数据源(和LINQ提供程序)#,c#,linq,C#,Linq,我正在设计一个数据信息接口层。我希望这一层的用户不知道数据源,仍然使用LINQ语法的优点。我希望使用标准LINQ提供程序作为该层的实现,并希望避免编写自定义LINQ提供程序 考虑下面的例子 信息接口层声明如下 interface IMyData { int Intdata { get; } double DoubleData { get; } } interface IMyDataProviderLayer { IQueryable< IMyData >
interface IMyData
{
int Intdata { get; }
double DoubleData { get; }
}
interface IMyDataProviderLayer
{
IQueryable< IMyData > Context { get; }
}
接口实现将访问来自真实数据源的数据,并且需要使用标准LINQ提供程序
有可能像上面那样做吗?即使数据源有标准的LINQ实现,我也需要从头开始实现LINQ提供程序吗?
还是有更好的方法来实现我在这里的目标?
提前谢谢。我想你是在找一种类似的。您将拥有如下界面:
public interface IMyRepository
{
IEnumberable<MyObject> GetObjects();
}
您还可以在存储库中使用IQueryable
而不是IEnumerable
。我解释了两者之间的一些区别。但基本上,IQueryable生成SQL并发送到数据库,而IEnumerable调用数据库,然后在内存中执行查询
通过这种方式,您可以将ORM从LINQ改为SQL,再改为实体框架,或者任何可以将查询抽象为IQueryable或IEnumerable的东西。看起来您的
IMyDataProviderLayer
基本上就是您的“存储库”抽象。您可以使用该接口的一个实现或模拟,该接口返回一个列表备份IQueryable
,而不是使用访问数据库的普通提供程序
您可以通过插入一个定制的IQueryable
实现来实现这一点,该实现包装了IList
:
public class QueryableList<T> : System.Linq.IQueryable<T>
{
private IList<T> _data;
public QueryableList()
{
_data = new List<T>();
}
public QueryableList(IList<T> data)
{
_data = data;
}
public IEnumerator<T> GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
public Expression Expression
{
get { return Expression.Constant(_data.AsQueryable()); }
}
public IQueryProvider Provider
{
get { return _data.AsQueryable().Provider; }
}
public Type ElementType
{
get { return typeof(T); }
}
}
编辑:
在我写了这篇文章后不久,我又回到这里,意识到我制作了IQueryable列表包装器来解决一个不同的问题。实际上,您完全忽略了这一点,只需执行以下操作:
using System.Linq;
IQueryable<IMyData> mydata = new List<IMyData>()
{
new MyData() { Intdata = 5, DoubleData = 1.2 },
new MyData() { Intdata = 2, DoubleData = 6.8 }
}.AsQueryable();
使用System.Linq;
IQueryable mydata=新列表()
{
new MyData(){Intdata=5,DoubleData=1.2},
new MyData(){Intdata=2,DoubleData=6.8}
}.AsQueryable();
调用.AsQueryable()
将该列表转换为IQueryable,而不是使用上面的包装器
抱歉给您带来困惑:)哇。。。太快了。我将用您的答案进行实际实现的实验。但从逻辑上讲,我认为这是正确的。感谢您提供的存储库模式链接。我也在考虑类似的问题,但无法插入现成的IQueryable。你的例子清楚地说明了这一点。我也会尝试这个解决方案。肖恩·麦克莱恩(Shawn McLean)的解决方案很简单,但我觉得你的解决方案更优雅一些。我还考虑使用依赖注入来实现实际数据提供者的运行时绑定,您的解决方案听起来更适合这种情况。谢谢
var dataCollection = from data in repository.GetObjects()
where data.Intdata == 5
select data;
public class QueryableList<T> : System.Linq.IQueryable<T>
{
private IList<T> _data;
public QueryableList()
{
_data = new List<T>();
}
public QueryableList(IList<T> data)
{
_data = data;
}
public IEnumerator<T> GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
public Expression Expression
{
get { return Expression.Constant(_data.AsQueryable()); }
}
public IQueryProvider Provider
{
get { return _data.AsQueryable().Provider; }
}
public Type ElementType
{
get { return typeof(T); }
}
}
// Make a mock data access layer, that is backed by a List.
var mockedDataLayer = new Mock<IMyDataProviderLayer>();
mockedDataLayer.SetupGet(x => x.Context, new QueryableList<IMyData>()
{
new MyData() { Intdata = 5, DoubleData = 1.2 },
new MyData() { Intdata = 2, DoubleData = 6.8 },
});
// Now we can use this.
var dataCollection = from data in mockedDataLayer.Object.Context
where data.Intdata == 5
select data;
using System.Linq;
IQueryable<IMyData> mydata = new List<IMyData>()
{
new MyData() { Intdata = 5, DoubleData = 1.2 },
new MyData() { Intdata = 2, DoubleData = 6.8 }
}.AsQueryable();