0

在继续之前,我需要介绍一些背景知识:我有一个项目,它使用 nHibernate 和一些通用存储库来转发谓词并返回实体,如下所示:

public abstract class GenericRepository< T >
{
...
    public virtual T Single( Expression< Func< T, bool > > predicates )
    {
        // Get object from nHibernate session object
        var retObj = Session
            .Query< T >()
            .Where( predicates ).SingleOrDefault();

        return retObj;
    }
...
}

然后,我可以通过这种方式获取实体:

var entity = Context.MyGenericEntityRepository.Single( e => e.Id == id );
// or
var entity = Context.MyGenericEntityRepository.Single( e => e.Name == name );

但是,由于项目的性质,我也有一些实体没有保存到数据库,而是保存到文件系统(文件束)。因此,我使用派生存储库,该存储库使用某种 DataAccess 类从文件系统中获取实体,如下所示:

public class NotGenericRepository
{
...
    // for example
    public IList<Entity> All()
    {
        return _entityDataAccess.All();
    }
...
}

如前所述,第二种类型的实体没有存储在数据库中,但是,为了方便我的旅程,我使用 DataSets 和 DataTables 创建了一种内存数据库系统。因此,当解决方案第一次启动时,我有一个名为 CustomDatabase 的单例,它被初始化,在内存中创建 DataTables,添加 DataTalbes 之间的关系,并在扫描文件系统以填充表之前将它们添加到通用 DataSet。

使用它,我现在可以查询我的数据表,而不是每次都扫描文件系统树。然后我在我的 CustomDatabase 中设置了一些事件,因此每当添加/删除/更新一行时,更改都会反映到文件系统上。

所以...这就是背景,抱歉太长了...

我的问题现在相当简单,我正在寻找一种方法来以某种方式将存储库转发的 lambda 表达式转换为我的 DataAccess 类,这样我就可以分析它并相应地从我的 DataTables 中选择......

例如,对存储库的调用,例如:

var entity = Context.MyNotGenericEntityRepository.Single( e => e.Id == id );
// or
var entity = Context.MyNotGenericEntityRepository.Single( e => e.Name == name );

应在 DataAccess 中翻译为:

DataRow entityRow = CustomDatabase.Tables[ "EntityName" ].AsEnumerable().Where( e => e.Field< Guid >( "Id" ) == id);
// or
DataRow entityRow = CustomDatabase.Tables[ "EntityName" ].AsEnumerable().Where( e => e.Field< string >( "Name" ) == name);

或者:

var entity = from myRow in CustomDatabase.Tables[ "EntityName" ].AsEnumerable()
             where myRow.Field<Guid>( "Id" ) == id
             select myRow;
// or
var entity = from myRow in CustomDatabase.Tables[ "EntityName" ].AsEnumerable()
             where myRow.Field<string>( "Name" ) == name
             select myRow;

我完全不知道该怎么做,我一直在网上寻找,但问题是我真的不知道如何命名这个问题,所以到目前为止我还没有找到太多...... :(

感谢任何帮助,因为我希望有几种方法可以解决这个问题:)

谢谢!!

4

2 回答 2

0

很难说出派生存储库类示例中跳过了什么,但它可以像覆盖(或重载)Single 以返回 All().Single(..) 一样简单。

于 2012-06-24T13:27:09.000 回答
0

假设您的谓词表达式是您问题中的形式,您可以将表达式转换为 a DataRow,然后使用它来过滤与实体对应的表:

public static DataRow GetSingleRow<T>(Expression<Func<T, bool>> expr)
{
    var bodyExpr = ((LambdaExpression)expr).Body;
    var binExpr = (BinaryExpression)bodyExpr;
    var propExpr = (MemberExpression)binExpr.Left;
    PropertyInfo targetProperty = (PropertyInfo)propExpr.Member;
    Type targetType = targetProperty.DeclaringType;
    var valueExpr = binExpr.Right;
    string entityName = targetType.Name;

    var fieldMethod = typeof(DataRowExtensions).GetMethod("Field", new[] { typeof(DataRow), typeof(string) });
    var methodInfo = fieldMethod.MakeGenericMethod(targetProperty.PropertyType);
    var propNameExpr = Expression.Constant(targetProperty.Name);
    var rowParamExpr = Expression.Parameter(typeof(DataRow), "dr");
    var fieldInvocationExpr = Expression.Call(methodInfo, rowParamExpr, propNameExpr);

    var eqExpr = Expression.Equal(fieldInvocationExpr, valueExpr);
    Func<DataRow, bool> predicate = Expression.Lambda<Func<DataRow, bool>>(eqExpr, rowParamExpr).Compile();

    return CustomDatabase.Tables[entityName].AsEnumerable().Single(predicate);
}
于 2012-06-24T14:04:31.517 回答