具有继承基类的LINQ通用查询?

时间:2010-04-07 20:57:00

标签: c# .net linq linq-to-sql generics

我正在尝试为我的实体编写一些通用的LINQ查询,但是在处理更复杂的事情时遇到了问题。现在我正在使用一个包含所有泛型的EntityDao类,并且每个对象类Daos(例如Accomplishments Dao)都继承它,例如:

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);

但是default是一个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声明为新的成就,因此它将被声明,此时代码会更改=&gt; to&gt; =自动说:

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

=(

1 个答案:

答案 0 :(得分: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并调用setter。 (可能更好的方法来做到这一点,但我还没想出来。)例如它看起来像:

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可以将其作为内部方法调用。

  

我的方法有效,但我更喜欢你的方法,因为它允许多个参数更灵活,但我真的很想把它保存在我的DAO中。除了一个之外,在我的DAO中使用所有db方法会有点令人困惑。设置函数是getOne吗?

我不确定我明白你在问我什么。是的,您可以将getOne函数设置为通用方法,这实际上是我所做的,尽管我已经更进一步,并且所有方法都是通用的。这简化了我的UI / BL界面边界,到目前为止至少具有足够的表现力/灵活性,可以覆盖我的所有使用要求,而无需进行重大更改。如果它有帮助我已经包含BL对象实现和暴露给UI的接口。我的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;
}