我正在设计一个数据信息接口层。我希望这个层的用户不知道数据源,仍然使用LINQ语法的优点。我想使用标准LINQ提供程序作为此层的实现,并希望避免编写Custom LINQ提供程序
请考虑以下示例。
信息接口层声明如下
interface IMyData
{
int Intdata { get; }
double DoubleData { get; }
}
interface IMyDataProviderLayer
{
IQueryable< IMyData > Context { get; }
}
以及使用此图层的客户端代码
//dataProvider implements IMyDataProviderLayer
var dataCollection = from data in dataProvider.Context
where data.Intdata == 5
select data;
接口实现将从真实数据源访问数据,并且需要使用标准LINQ提供程序。
是否有可能做上面这样的事情?我是否需要从头开始实现LINQ提供程序,即使数据源具有标准的LINQ实现? 或者有更好的方法来实现我在这里尝试做的事情吗? 提前谢谢。
答案 0 :(得分:2)
我认为你正在寻找像Repository Pattern这样的东西。您将拥有如下界面:
public interface IMyRepository
{
IEnumberable<MyObject> GetObjects();
}
实现(在这里使用依赖注入):
public class MyRepository : IMyRepository
{
private Context dbContext;
IEnumberable<MyObject> GetObjects()
{
return dbContext.MyObjects;
}
}
使用:
var dataCollection = from data in repository.GetObjects()
where data.Intdata == 5
select data;
您也可以在存储库中使用IQueryable
代替IEnumerable
。我解释了2 here之间的一些区别。但基本上,IQueryable生成SQL并将其发送到数据库,而IEnumerable调用数据库然后在内存中进行查询。
这样,您可以将ORM从LINQ更改为SQL实体框架或任何可以将查询抽象为IQueryable或IEnumerable的内容。
答案 1 :(得分:1)
看起来你的IMyDataProviderLayer
基本上就是你的“存储库”抽象。您可以使用该接口的实现或模拟返回List<T>
支持的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); }
}
}
然后你可以制作一个模拟IMyDataProviderLayer
,将其中一个作为Context
返回。例如(使用Moq):
// 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;
编辑:
在我写完这篇文章后我回过头来了,并意识到我已经制作了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();
对.AsQueryable()
的调用会将该列表转换为IQueryable,而不是使用上面的包装器。
很抱歉这个混乱:)