【问题标题】:LINQ Generic Query with inherited base class?具有继承基类的 LINQ 通用查询?
【发布时间】:2010-04-07 20:57:00
【问题描述】:

我正在尝试为我的实体编写一些通用 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);

但是默认是 nhibernate 命令,我将如何为 LINQ 执行此操作?

编辑:

即使只是离开基类(这是自动生成的 LINQ 类的部分类),getOne 似乎也不起作用。我什至删除了泛型。我试过了:

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'.  

=(

【问题讨论】:

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


    【解决方案1】:

    如果我了解您想要什么,您所链接的问题描述(某种程度)您需要做什么。

    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 都实现的基类的一部分。 Editable 基类和我的 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;
    }
    

    【讨论】:

    • Hmmmm 无论如何都可以在不从函数调用中传递谓词的情况下做到这一点?这才是我真正想要避免的。主要问题是因为我的 DAO 类没有名为 ID 的成员。我喜欢将我的对象类与数据库逻辑类 (DAO) 和业务逻辑类(服务)分开。只是看起来很奇怪。是否没有表达式或 .command 来表示将列名/属性作为字符串输入?
    • 实际上,这一点是您的谓词可以是任何可以缩小到单个实体的东西。例如 x=>x.name == "some Name" && x.created == "02/03/2010" 对谓词有效,只要它返回单个实体。如果您想要单独的 DAO 和服务类,那么无论如何您都必须转换逻辑。如果你想使用列名和值,我不确定你会怎么做。
    • 是否可以在字符串参数之外构建谓词?我猜不会,因为 x.Id 中的 id 是一个已知属性。如果可能的话,那么我想这只是一个两步的过程,即根据提供的参数构建一个谓词,然后将该谓词放入上面的示例中。
    • 哦,我想我找到了答案:stackoverflow.com/questions/125400/generic-linq-query-predicate 看起来正是我需要的,字符串作为参数!
    • 极客,你能扩展你关于使用反射的更新吗?我的方法有效,但我更喜欢你的方法,因为它更灵活,允许使用多个参数,但我真的很想将它保留在我的 DAO 中。在我的 DAO 中拥有除一个之外的所有 db 方法会有点令人困惑。将函数设置为 getOne 有效吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-06
    • 1970-01-01
    • 2011-06-20
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多