2010-04-07 30 views
2

我正在嘗試爲我的實體編寫一些通用的LINQ查詢,但我在做更復雜的事情時遇到了問題。現在,我使用了我所有的仿製藥的EntityDao類和我的每一個對象類的DAO(如成績DAO)繼承它,是例如:LINQ與繼承基類的通用查詢?

using LCFVB.ObjectsNS; 
using LCFVB.EntityNS; 

namespace AccomplishmentNS 
{ 
    public class AccomplishmentDao : EntityDao<Accomplishment>{} 
} 

現在我entityDao具有下面的代碼:

using LCFVB.ObjectsNS; 
using LCFVB.LinqDataContextNS; 

namespace EntityNS 
{ 
public abstract class EntityDao<ImplementationType> where ImplementationType : Entity 
{ 
public ImplementationType getOneByValueOfProperty(string getProperty, object getValue) 
{ 
    ImplementationType entity = null; 
     if (getProperty != null && getValue != null) { 
      //Nhibernate Example: 
      //ImplementationType entity = default(ImplementationType); 
      //entity = Me.session.CreateCriteria(Of ImplementationType)().Add(Expression.Eq(getProperty, getValue)).UniqueResult(Of InterfaceType)() 

      LCFDataContext lcfdatacontext = new LCFDataContext(); 

      //Generic LINQ Query Here 
      lcfdatacontext.GetTable<ImplementationType>(); 


      lcfdatacontext.SubmitChanges(); 

      lcfdatacontext.Dispose(); 
     } 


     return entity; 
    } 

    public bool insertRow(ImplementationType entity) 
    { 
     if (entity != null) { 
      //Nhibernate Example: 
      //Me.session.Save(entity, entity.Id) 
      //Me.session.Flush() 

      LCFDataContext lcfdatacontext = new LCFDataContext(); 

      //Generic LINQ Query Here 
      lcfdatacontext.GetTable<ImplementationType>().InsertOnSubmit(entity); 

      lcfdatacontext.SubmitChanges(); 
      lcfdatacontext.Dispose(); 

      return true; 
     } 
     else { 
      return false; 
     } 
    } 

} 
} 

我已經得到了的insertRow功能的工作,但是我甚至不知道如何去這樣做getOnebyValueOfProperty,我能找到這個網站上最接近的事情是:

Generic LINQ TO SQL Query

如何傳遞列名和我檢查的值是否一般使用當前的設置?從這個鏈接看來,這是不可能的,因爲使用where謂詞是因爲實體類不知道任何屬性是什麼,直到我通過它們。

最後,我需要某種方式來設置一個新的對象作爲返回類型設置爲實現類型,在NHibernate的(我想從轉換),它只是這行做了它:

ImplentationType entity = default(ImplentationType); 

不過默認是NHibernate的命令,我會怎麼對LINQ做到這一點?

編輯:

getOne似乎沒有工作,即使只是要關閉的基類(這是一個局部類自動生成的LINQ類)。我甚至刪除了仿製藥。我想:

namespace ObjectsNS 
{  
    public partial class Accomplishment 
    { 
     public Accomplishment getOneByWhereClause(Expression<Action<Accomplishment, bool>> singleOrDefaultClause) 
    { 
     Accomplishment entity = new Accomplishment(); 
     if (singleOrDefaultClause != null) { 
       LCFDataContext lcfdatacontext = new LCFDataContext(); 

       //Generic LINQ Query Here 
       entity = lcfdatacontext.Accomplishments.SingleOrDefault(singleOrDefaultClause); 

       lcfdatacontext.Dispose(); 
       } 
      return entity; 
       } 
      } 
     } 

收到以下錯誤:

Error 1 Overload resolution failed because no accessible 'SingleOrDefault' can be called with these arguments: 
Extension method 'Public Function SingleOrDefault(predicate As System.Linq.Expressions.Expression(Of System.Func(Of Accomplishment, Boolean))) As Accomplishment' defined in 'System.Linq.Queryable': Value of type 'System.Action(Of System.Func(Of LCFVB.ObjectsNS.Accomplishment, Boolean))' cannot be converted to 'System.Linq.Expressions.Expression(Of System.Func(Of LCFVB.ObjectsNS.Accomplishment, Boolean))'. 
Extension method 'Public Function SingleOrDefault(predicate As System.Func(Of Accomplishment, Boolean)) As Accomplishment' defined in 'System.Linq.Enumerable': Value of type 'System.Action(Of System.Func(Of LCFVB.ObjectsNS.Accomplishment, Boolean))' cannot be converted to 'System.Func(Of LCFVB.ObjectsNS.Accomplishment, Boolean)'.  14 LCF 

好了沒問題,我改變:

public Accomplishment getOneByWhereClause(Expression<Action<Accomplishment, bool>> singleOrDefaultClause) 

到:

public Accomplishment getOneByWhereClause(Expression<Func<Accomplishment, bool>> singleOrDefaultClause) 

錯誤消失。好吧,但現在當我嘗試通過調用方法:

Accomplishment accomplishment = new Accomplishment(); 
var result = accomplishment.getOneByWhereClause(x=>x.Id = 4) 

它不起作用,它說x未聲明。

我還試圖

getOne<Accomplishment> 
Expression<Func< 
Expression<Action< 
以各種格式

,但任何這些參數不會如在函數調用的表達式正確地識別,或者它不能轉換我有類型作爲參數到內部中使用的類型singleofDefault()。所以這兩個錯誤就像上面一樣。而班級成績確實有ID。最後,我也試過聲明x作爲新的成績,因此將宣佈,在該點代碼更改=>到>自動=說:

Error 1 Operator '>=' is not defined for types 'LCFVB.ObjectsNS.Accomplishment' and 'Integer'. 

=(

回答

2

如果我明白你希望您鏈接到介紹的問題(在某種程度上),你需要做的事情。

public ImplementationType getOne(Expression<Func<ImplementationType , bool> singleOrDefaultClause) 
{ 
    ImplementationType entity = null; 
    if (singleOrDefaultClause != null) 
    { 

     LCFDataContext lcfdatacontext = new LCFDataContext(); 

     //Generic LINQ Query Here 
     entity = lcfdatacontext.GetTable<ImplementationType>().SingleOrDefault(singleOrDefaultClause); 


     lcfdatacontext.Dispose(); 
    } 


    return entity; 
} 

當你調用該方法,會看起來像

//note assumption that ConcreteClass DAO has member called Id 
var myEntity = ConcreteClass.getOne(x=>x.Id == myIdVariable); 

我還沒有編譯這個,所以我不能說它是100%正確的,但這個想法很有效。我使用類似的東西,除了我定義我的方法與基類通用以實現通用代碼。

更新 難道你不能只用new來創建你需要的類的實例嗎?如果你需要更通用的東西,那麼我認爲你將不得不使用反射來調用構造函數。對不起,如果我誤解了你的問題。響應

更新,以瞭解更多詳細信息 擴展更新POCO的評論:有很多的方法可以做到這一點,但一個是從表達式獲得的PropertyInfo和調用設置。從我的代碼基礎上,我把這個(除去一些其他的東西):(可能更好的方法來做到這一點,但我還沒有想出一個出來。)例如,它可能看起來像:

protected internal bool Update<TRet>(Expression<Func<T, TRet>> property, TRet updatedValue) 
{ 
    var property = ((MemberExpression)member.Body).Member as PropertyInfo; 
    if (property != null) 
    { 
     property.SetValue(this, updatedValue, null); 
     return true; 
    } 
    return false; 
} 

注我正在工作的一個項目。這個方法是我所有POCO實現的基類的一部分。可編輯的基類和我的POCO的基類位於同一個程序集中,因此Editable可以將其作爲內部方法調用。

I got my methods working but I like yours more because it is more flexible allowing for multiple parameters, but I really really want to keep this in my DAO. It would be kind of confusing to have all db methods in my DAO except one. Would setting the function to be getOne work?

我不太確定我明白你在問我什麼。是的,您可以將getOne函數設置爲通用方法,但實際上我已經完成了這一操作,儘管我已經採取了更進一步的操作,並且所有方法都是通用的。這簡化了我的UI/BL界面邊界,至少到目前爲止,表現力/靈活性足以覆蓋我所有的使用要求,而無需進行重大更改。如果有幫助,我已經包含了BL對象實現並公開給用戶界面的界面。我的DAL本質上是NHibernate,所以我沒有任何東西可以告訴你。

public interface ISession : IDisposable 
{ 
    bool CanCreate<T>() where T : class,IModel; 
    bool CanDelete<T>() where T : class, IModel; 
    bool CanEdit<T>() where T : class, IModel; 
    bool CanGet<T>() where T : class, IModel; 

    T Create<T>(IEditable<T> newObject) where T:class,IModel; 

    bool Delete<T>(Expression<Func<T, bool>> selectionExpression) where T : class, IModel; 

    PageData<T> Get<T>(int page, int numberItemsPerPage, Expression<Func<T, bool>> whereExpression) where T : class, IModel; 
    PageData<T> Get<T, TKey>(int page, int numberItemsPerPage, Expression<Func<T, bool>> whereExpression, Expression<Func<T, TKey>> orderBy, bool isAscending) where T : class, IModel; 

    T Get<T>(Expression<Func<T, bool>> selectionExpression) where T : class, IModel; 

    IEnumerable<T> GetAllMatches<T>(Expression<Func<T, bool>> whereExpression) where T : class, IModel; 

    IEditable<T> GetForEdit<T>(Expression<Func<T, bool>> selectionExpression) where T : class, IModel; 

    IEditable<T> GetInstance<T>() where T : class, IModel; 

    IQueryable<T> Query<T>() where T : class, IModel; 

    bool Update<T>(IEditable<T> updatedObject) where T : class, IModel; 
} 
+0

嗯,無論如何要做到這一點,而不通過函數調用的謂詞?這是我真正想避免的。 主要問題是因爲我的DAO類沒有名爲ID的成員。我喜歡將我的對象類與數據庫邏輯類(DAO)和業務邏輯類(服務)分開。 這似乎很奇怪。是否沒有表達式或.command來表示將字段名稱/屬性輸入爲字符串? – SventoryMang 2010-04-08 02:12:23

+0

其實這一點是你的謂詞可以是範圍縮小到單個實體的任何東西。例如x => x.name ==「some Name」&& x.created ==「02/03/2010」只要它返回一個實體就會對謂詞有效。如果你想單獨的DAO和服務類,那麼你將不得不在任何情況下翻譯邏輯。如果你想使用列名和值,我不知道你會怎麼做。 – 2010-04-08 02:35:11

+0

是否有可能建立一個斷言字符串參數?我會猜測沒有,因爲x.Id中的id是已知屬性。 如果可能的話,那麼我想這只是一個兩步的過程,從所提供的參數中構建一個謂詞,然後將這個謂詞放到上面的示例中。 – SventoryMang 2010-04-08 02:47:35