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

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

但是默认是 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() 中使用的类型。所以这两个错误就像上面一样。而且类(class)成绩确实有ID。最后,我还尝试将 x 声明为一项新成就,这样它就会被声明,此时代码会自动将 => 更改为 >= 并说:

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

=(

最佳答案

如果我明白你想要什么,你链接到的问题描述了(某种程度上)你需要做什么。

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% 正确,但这个想法是可行的。我正在使用类似的东西,除了我将我的方法定义为具有基类的通用方法来实现公共(public)代码。

更新 你不能只使用 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 可以将其作为内部方法调用。

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 界面边界,到目前为止,至少在表现力/灵 active 上足以涵盖我所有的使用需求,而无需进行重大更改。如果有帮助,我已经包含了由 BL 对象实现并向 UI 公开的接口(interface)。我的 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;
}

关于c# - 具有继承基类的 LINQ 通用查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2595862/

相关文章:

c# - 启动一个新线程——我需要关心垃圾回收吗

c# - '|' vs ' ||' C#中的编译器优化

c# - ILMerge问题

c# - 如何在 IQueryable<> 中选择日期间隔?

c# - 什么是不断变化的表格表示的最佳集合类型

c# - MongoDB C# Driver 2.0 - 更新文档

c# - 协助重构 LINQ 方法

c# - 将连续日期组合成范围

C# UWP ScrollViewer 改变 Horizo​​ntalScrollBarVisibility

c# - 从静态函数调用 InsertAsync 会引发 ThreadAbortException