2012-02-17 32 views
1

我正在設計一個數據信息接口層。我希望這一層的用戶不知道數據源,並仍然使用LINQ語法的優點。我想使用標準LINQ提供程序作爲此層的實現,並且希望避免編寫自定義LINQ提供程序LINQ - 在運行時改變數據源(和LINQ提供程序)在C#

請考慮以下示例。

信息接口層被聲明爲以下

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實現? 還是有更好的方法來實現我在這裏要做的事情嗎? 在此先感謝。

回答

2

我認爲您正在尋找類似​​的東西。您將有一個界面如下:(這裏使用依賴注入)

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調用數據庫,然後在內存中執行查詢。

這樣,您可以將LINQ to SQL的ORM更改爲實體框架或任何可以將查詢抽象爲IQueryable或IEnumerable的東西。

+0

哇......那很快。我會嘗試你的答案爲實際的實現。但從邏輯上講,它對我來說看起來是正確感謝Repository模式鏈接。 – 2012-02-17 16:10:54

1

看起來您的IMyDataProviderLayer基本上是您的「存儲庫」抽象。您可以擁有該接口的實現或模擬,該接口返回List<T>支持的IQueryable,而不是使用訪問數據庫的普通提供程序。

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

您可以通過自定義的堵塞IQueryable實現,封裝協議的IList實現這一目標。例如(使用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()調用變成了List到一個IQueryable你,而不是用我上面的包裝。

對不起,我感到困惑:)

+0

我在思考類似的問題,但無法插入現成的IQueryable。你的例子清楚地表明瞭這一點我也會嘗試這個解決方案。肖恩麥克萊恩的解決方案很簡單,但你的解決方案似乎對我來說更加優雅。我也在考慮使用依賴注入來實現實際數據提供者的運行時綁定,並且您的解決方案聽起來更適合於這種情況。謝謝。 – 2012-02-17 16:45:08