我的WCF數據服務(二)獨立

由於當時正在學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。
要想知道我怎麼解決的,看下一篇吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章