我的WCF数据服务(二)独立

来源:互联网 发布:博客源码 编辑:程序博客网 时间:2024/06/05 18:51

由于当时正在学WCF,就使用了WCF作为数据提供,由于需要常驻内存,所以使用了WINDOWS服务作为载体。
当时觉得难点有1个,就是传递查询和排序条件,委托是不能在进程间传递的,幸亏有了 Expression 这个类,改一下参数的类型就行了,原来的代码基本不用动。但是 Expression 也不能直接就在进程间传递。后来读到了一篇文章介绍了 ExpressionSerializer 这个类,可以把表达式转换成XML,或者再转换回来。理论上可以了,就开始动手了。请看代码:

public class ModelPvd<T> : IModelPvd where T : class    {        protected ReaderWriterLock LockerRW = new ReaderWriterLock();//数据操作锁        protected object lockerForOp = new object();//反序列化锁        protected ExpressionSerializer serializer { private set; get; }//序列化器        public string Name { private set; get; }//类名称        protected List<T> Lm;//数据        Func<int, T> FModelPrvd;//获取实体对象的委托,在类初始化时,会获取所有数据保存在这个变量。        Action<List<T>, int> ADelDlgt;//列表删除器,当数据库删除了一条数据,也从Lm里删除这条数据。        protected ILogWriter lw;//日志记录器        public ModelPvd(Func<List<T>> dataPrvd, Func<int, T> modelPrvd, Action<List<T>, int> delDlgt, bool isAd, ILogWriter ilog)        {            List<Assembly> assemblies = new List<Assembly> { typeof(T).Assembly, typeof(ExpressionType).Assembly, typeof(IQueryable).Assembly };            var resolver = new TypeResolver(assemblies, new[] { typeof(T), typeof(DateTime), typeof(decimal), typeof(object) });            var knownTypeConverter1 = new KnownTypeExpressionXmlConverter(resolver);            serializer = new ExpressionSerialization.ExpressionSerializer(resolver, new CustomExpressionXmlConverter[] { knownTypeConverter1 });            //上边这一段是序列化器的生成,是从ExpressionSerializer的例子里拷来的。            Lm = dataPrvd.Invoke();//获取数据            Name = typeof(T).ToString();//因为有好些数据表都要做这个功能,这个名字用来区分。            FModelPrvd = modelPrvd;            ADelDlgt = delDlgt;            lw = ilog;        }        public object[] GetList(int pageSize, int pageIndex, XElement match, XElement orderKeySelector, bool desc, out int recordCount)//查询数据功能。        {            Expression<Func<T, bool>> p;            lock (lockerForOp)            {                p = serializer.Deserialize<Func<T, bool>>(match);            }            lw.Write(Name + "  " + p.ToString() + " l " + pageSize.ToString());            int orderWay;//排序方式,0:按照表达式排序,1,随机排序。            Expression<Func<T, int>> o = null;                orderWay = orderKeySelector == null ? 1 : 0;                if (orderWay == 0)                {                    lock (lockerForOp)                    {                        o = serializer.Deserialize<Func<T, int>>(orderKeySelector);                    }                }            List<T> r;            LockerRW.AcquireReaderLock(200);            try            {                var l = Lm.Where(p.Compile());                recordCount = l.Count();                switch (orderWay)                {                    case 1:                        r = l.OrderByDescending(x => Guid.NewGuid()).Take(pageSize).ToList();                        break;                    default:                        if (desc)                            r = l.OrderByDescending(o.Compile()).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();                        else                            r = l.OrderBy(o.Compile()).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();                        break;                }            }            finally            {                LockerRW.ReleaseReaderLock();            }            if (r == null)                return null;            return r.ToArray();        }        //////查询符合条件的数据数量。        public int GetCount(XElement match)        {            int rst;            Expression<Func<T, bool>> p;            lock (lockerForOp)            {                p = serializer.Deserialize<Func<T, bool>>(match);            }            lw.Write(Name + " " + p.ToString() + "c");            LockerRW.AcquireReaderLock(200);            try            {                rst = Lm.Count(p.Compile());            }            finally { LockerRW.ReleaseReaderLock(); }            return rst;        }        某一条数据发生变化(增删改)时,调用这个方法同步。        public bool UpdateData(int Id)        {            var model = FModelPrvd.Invoke(Id);            LockerRW.AcquireWriterLock(1000);            try            {                ADelDlgt.Invoke(Lm, Id);                if (model != null)                    Lm.Add(model);            }            finally            {                LockerRW.ReleaseWriterLock();            }            return true;        }    }

下面是实现的接口。

public interface IModelPvd    {        string Name { get; }        object[] GetList(int pageSize, int pageIndex, XElement match, XElement orderKeySelector, bool desc, out int recordCount);        int GetCount(XElement match);        bool UpdateData(int Id);    }

在WCF的服务实现类里,代码是这样的:

public class Service1 : IService1    {    static List<IModelPvd> Limp;        static LogWriter Lw = new LogWriter();        static Service1()        {            GetAllData();        }        static void GetAllData()        {        Limp = new List<IModelPvd>();            Limp.Add(new ModelPvdAd<Model.XXX>(DAL.XXX.GetListByDAL, DAL.XXX.GetModel, (x, y) => x.RemoveAll(z => z.Id == y),  Lw));            }            public int GetCount(string typeName, XElement match)        {            var m = Limp.Find(x => x.Name == typeName);            if (m != null)                return m.GetCount(match);            else                return 0;        }        public object[] GetList(string typeName, int pageSize, int pageIndex, XElement match, XElement orderKeySelector, bool desc, out int recordCount)        {            var m = Limp.Find(x => x.Name == typeName);            if (m != null)                return m.GetList(pageSize, pageIndex, match, orderKeySelector, desc, out recordCount);            else            {                recordCount = 0;                return null;            }        }        public bool UpdateData(string typeName, int Id)        {        var m = Limp.Find(x => x.Name == typeName);                    if (m != null)                        return m.UpdateData(Id);                    else                        return false;}    }

还有WCF的接口代码:

public interface IService1{[OperationContract]        [ServiceKnownType(typeof(Model.XXX))]        object[] GetList(string typeName, int pageSize, int pageIndex, XElement match, XElement orderKeySelector, bool desc, out int recordCount);        [OperationContract]        int GetCount(string typeName, XElement match);        [OperationContract]        bool UpdateData(string typeName, int Id);}

上边这几段代码,是服务器端。ExpressionSerializer 这个类会把传过来的 XML 转化成原始的LAMBDA表达式,一个 Expression<<Func<Model.XXX,bool>> 这样的条件表达式,或者一个 Expression<Func<Model.XXX,int>>这样的排序表达式。如果想随机排序,就把排序的 XML 传个 null 过来。
再来看看客户端:

public class ModelPvd<T> where T : class    {        protected object locker = new object();//序列化锁        protected ExpressionSerializer serializer { private set; get; }//序列化器        public string Name { private set; get; }//类名称        public Expression<Func<T, int>> PrimaryKey;        public ModelPvd(Expression<Func<T, int>> primaryKey)        {            List<Assembly> assemblies = new List<Assembly> { typeof(T).Assembly, typeof(ExpressionType).Assembly, typeof(IQueryable).Assembly };            var resolver = new TypeResolver(assemblies, new[] { typeof(T), typeof(DateTime), typeof(decimal), typeof(object) });            var knownTypeConverter1 = new KnownTypeExpressionXmlConverter(resolver);            serializer = new ExpressionSerialization.ExpressionSerializer(resolver, new CustomExpressionXmlConverter[] { knownTypeConverter1 });            Name = typeof(T).ToString();            PrimaryKey = primaryKey;        }        public List<T> GetList<Tm>(int pageSize, int pageIndex, Expression<Func<T, bool>> Efma, Expression<Func<T, Tm>> orderBy, bool desc, out int recordCount)        {            System.Xml.Linq.XElement xmlOrder = null;            if ((typeof(Tm) != typeof(int)) || orderBy == null)            {                xmlOrder = null;            }            else            {                lock (locker)                {                    xmlOrder = serializer.Serialize(orderBy);                }            }            System.Xml.Linq.XElement xmlPredicate;            lock (locker)            {                xmlPredicate = serializer.Serialize(Efma);            }            DataCenter.Service1Client Dcsc = All.GetDataCenterService();            object[] l = Dcsc.GetList(typeof(T).ToString(), pageSize, pageIndex, xmlPredicate, xmlOrder, desc, out recordCount) as object[];            All.CloseDc(Dcsc);            var Lado = new List<T>();            foreach (object i in l)            {                Lado.Add(i as T);            }            return Lado;        }        public int GetCount(Expression<Func<T, bool>> Efma, bool IsRebuild = true)        {            System.Xml.Linq.XElement xmlPredicate;            lock (locker)            {                xmlPredicate = serializer.Serialize(Efma);            }            DataCenter.Service1Client Dcsc = All.GetDataCenterService();            int rst = Dcsc.GetCount(typeof(T).ToString(), xmlPredicate);            All.CloseDc(Dcsc);            return rst;        }        public bool UpdateData(int id)        {            DataCenter.Service1Client Dcsc = All.GetDataCenterService();            var l = Dcsc.UpdateData(typeof(T).ToString(), id);            All.CloseDc(Dcsc);            return l;        }    }

具体的BLL.XXX 里,代码是这样的:

static ModelPvdAd<Model.XXX> Pvd = new ModelPvdAd<Model.XXX>(x => x.Id);        public List<Model.XXX> GetList(int pageSize, int pageIndex, Expression<Func<Model.XXX, bool>> Efma, Expression<Func<Model.XXX, int>> orderBy, bool desc, out int recordCount)        {            return Pvd.GetList(pageSize, pageIndex, Efma, orderBy, desc, out recordCount);        }

这样就基本完成了,建个测试页面试一下。

Expression<Func<Model.XXX,bool>> q = x=>x.id>3 && x.id<100;int rc;var l = BLL.XXX.GetList(30,1,q,x=>x.id,true,out rc);

绑定到 Repeater 没有问题。
但是继续测试的时候遇到了问题。一旦表达式中含有变量,服务端就报错了。比如上边的例子改成:

int i=3,j=100,rc;var l = BLL.XXX.GetList(30,1,x=>x.id>i && x.id<j,x=>x.id,true,out rc);

这样就不行了,原因是 表达式中的 i 和 j 在传递的时候,是临时类的变量,而不是 3 和 100。
要想知道我怎么解决的,看下一篇吧。

0 0