如何以动态方式获取模型的关系?

时间:2014-06-27 07:10:13

标签: c# xamarin

所以我有一个使用SQLite数据库的应用程序。我有一些方法可以从我的数据库中获取模型。我有一个与我的数据库通信的存储库。它看起来像这样:

public class PhotoRepository
    {

        AppDatabase db = null;

        public PhotoRepository ()
        {
            db = new AppDatabase (Constants.DatabaseFilePath);
        }

        public Photo GetPhoto(int id)
        {
            return db.GetItem<Photo>(id);
        }

        public IEnumerable<Photo> GetPhotos (int album_id)
        {
            return db.GetItems<Photo>().Where( x => x.Album_Id == album_id );
        }

        public int SavePhoto (Photo item)
        {
            return db.SaveItem<Photo>(item);
        }

        public int DeletePhoto(int id)
        {
            return db.DeleteItem<Photo>(id);
        }

    }

我关注GetPhotos(int album_id)方法,因为它在我的数据库类中接近的方法如下所示:

public IEnumerable<T> GetItems<T> () where T : BL.Contracts.IBusinessEntity, new ()
        {
            lock (locker) {
                return (from i in Table<T> () select i).ToList ();
            }
        }

正如您所看到的,它从我的数据库中检索所有照片模型,之后我将过滤那些与右album_id对应的照片模型。

我的问题不是:

如何重写我的方法,以便它只取出与album_id对应的模型。或者甚至更好,我如何重写此方法来过滤任何属性上的任何关系?

1 个答案:

答案 0 :(得分:0)

所以我设法解决了自己的答案。也许人们对结果很感兴趣,所以来吧。

我读了一篇关于动态LINQ查询的帖子。我正在谈论的帖子可以找到here。所以我做的第一件事是创建一个Filter类看起来像这样:

public class Filter
    {

        public enum Op 
        {
            Equals,
            GreaterThan,
            LessThan,
            GreaterThanOrEqual,
            LessThanOrEqual,
            Contains,
            StartsWith,
            EndsWith
        }

        public string PropertyName { get ; set ; }
        public Op Operation { get ; set ; }
        public object Value { get ; set ; }
    }

然后我创建了ExpressionBuilder类,如下所示:

public static class ExpressionBuilder 
{
    private static MethodInfo containsMethod = typeof(string).GetMethod("Contains" );
    private static MethodInfo startsWithMethod = 
        typeof(string).GetMethod("StartsWith", new Type [] {typeof(string)});
    private static MethodInfo endsWithMethod = 
        typeof(string).GetMethod("EndsWith", new Type [] { typeof(string)});


    public static Expression<Func<T, 
    bool >> GetExpression<T>(IList<Filter> filters)
    {            
        if  (filters.Count == 0)
            return null ;

        ParameterExpression param = Expression.Parameter(typeof (T), "t" );
        Expression exp = null ;

        if  (filters.Count == 1)
            exp = GetExpression<T>(param, filters[0]);
        else  if  (filters.Count == 2)
            exp = GetExpression<T>(param, filters[0], filters[1]);
        else 
        {
            while  (filters.Count > 0)
            {
                var  f1 = filters[0];
                var  f2 = filters[1];

                if  (exp == null )
                    exp = GetExpression<T>(param, filters[0], filters[1]);
                else 
                    exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1]));

                filters.Remove(f1);
                filters.Remove(f2);

                if  (filters.Count == 1)
                {
                    exp = Expression .AndAlso(exp, GetExpression<T>(param, filters[0]));
                    filters.RemoveAt(0);
                }
            }
        }

        return Expression.Lambda<Func<T, bool>>(exp, param);
    }

    private static Expression GetExpression<T>(ParameterExpression param, Filter filter)
    {
        MemberExpression member = Expression.Property(param, filter.PropertyName);
        ConstantExpression constant = Expression.Constant(filter.Value);

        switch (filter.Operation)
        {
        case  PhotoWapp.DL.Filter.Op.Equals:
            return Expression.Equal(member, constant);

        case  PhotoWapp.DL.Filter.Op.GreaterThan:
            return Expression.GreaterThan(member, constant);

        case PhotoWapp.DL.Filter.Op.GreaterThanOrEqual:
            return Expression.GreaterThanOrEqual(member, constant);

        case PhotoWapp.DL.Filter.Op.LessThan:
            return Expression.LessThan(member, constant);

        case PhotoWapp.DL.Filter.Op.LessThanOrEqual:
            return Expression.LessThanOrEqual(member, constant);

        case PhotoWapp.DL.Filter.Op.Contains:
            return Expression.Call(member, containsMethod, constant);

        case PhotoWapp.DL.Filter.Op.StartsWith:
            return Expression.Call(member, startsWithMethod, constant);

        case PhotoWapp.DL.Filter.Op.EndsWith:
            return Expression.Call(member, endsWithMethod, constant);
        }

        return null ;
    }

    private static BinaryExpression GetExpression<T>
    (ParameterExpression param, Filter filter1, Filter  filter2)
    {
        Expression bin1 = GetExpression<T>(param, filter1);
        Expression bin2 = GetExpression<T>(param, filter2);

        return  Expression.AndAlso(bin1, bin2);
    }
}

然后我添加了如下所示的方法GetItems<T>(List<Filter> filters)

public IEnumerable<T> GetItems<T> (List<Filter> filters) where T : BL.Contracts.IBusinessEntity, new ()
    {
        lock (locker) {
            var deleg = ExpressionBuilder.GetExpression<T> (filters).Compile ();
            return (from i in Table<T>().Where(deleg) select i).ToList();
        }
    }

为了检索我需要的记录,我使用了以下代码。

public IEnumerable<Photo> GetPhotos (int album_id)
    {
        List<Filter> filters = new List<Filter> () { 
            new Filter{
                PropertyName = "Album_Id",
                Operation = Filter.Op.Equals,
                Value = album_id
            }
        };
        return db.GetItems<Photo>(filters);
    }

现在我可以很好地过滤我需要的所有属性!关于这个解决方案的好处是我可以使用任何类和属性来过滤。

我希望这对某人有用!