MongoDB용 WCF Data Services Provider 구현 시도

23839 단어 Provider
WCF Data Services 이전에는 ADO라고 불렀습니다.NET Data ServicesNET 4.0에서는 두 번째 버전이 발표되었습니다.WCF Data Services를 통해 ODAta 표준에 맞는 데이터 인터페이스를 발표하여 다양한 클라이언트가 이 데이터를 소비할 수 있게 하고 일부 술어를 통해 데이터를 조작할 수도 있다.
WCF Data Services에 대한 설명은 다음과 같습니다http://www.cnblogs.com/shanyou/archive/2010/02/14/1668210.html.
데이터 노출 서비스로서 백엔드의 각종 데이터 원본의 전시를 지원할 수 있다. WCF 데이터 서비스는 기본적으로 실체 프레임워크(Entity Framework)를 지원하고 자신의 Provider를 실현할 수 있도록 확장 인터페이스를 제공한다.
먼저 Provider를 직접 구현해야 하는지 확인해야 합니다.
  • 만약에 데이터가EF로 접근할 수 있다면 실현할 필요가 없다
  • 만약에 당신의 데이터가LINQtoSQL을 통해 방문한다면 기존의 Provider도 사용할 수 있습니다. ADO.NET Data Services IUpdateable implementation for Linq to Sql
  • 만약에 데이터가 사용자 정의 실체 대상과 일부 대상의 집합으로 구성된다면 Reflection Provider(반사 공급자)를 사용하여 데이터를 편집할 필요가 있으면 IUpdatable를 동시에 실현합니다.실제로 LINQtoSQL의 Provider는 이렇게 이루어졌다.
  • 여러 인터페이스를 실현하여 완전히 사용자 정의를 진행한다.

  • 대부분의 경우 Reflection Provider는 이미 충분하다. 예를 들어 대상 데이터베이스(dbo4), 현재 핫한 NosQL, 즉 Document(-based) DataBase도 쉽게 실현할 수 있다.
    http://www.cnblogs.com/tansm/archive/2010/06/10/1755250.html의 번역문을 읽으면 자동적으로Provider를 사용자 정의할 수 있습니다.
    최근 며칠 동안 MongoDB의 WCF Data Services Provider를 실현해 봤습니다.
    먼저, MongoDB의 NoRM 드라이브를 시도했습니다. 소개: http://www.cnblogs.com/shanyou/archive/2010/06/04/1751734.html
    하지만 이 드라이버로 인해 ObjectId 를 솔리드 객체에 명시적으로 추가해야 합니다.id의 속성을 저장할 수 있습니다. 즉 콜렉션을 쉽게 호출할 수 있습니다.Save 메서드,이 속성이 없으면 Update 방법을 통해서만 데이터를 업데이트할 수 있지만 Update 방법은 Data 서비스에서 엉뚱한 문제에 부딪히기 때문에 여러 가지 기교를 시도한 후에 이 드라이브를 포기합니다.
    그리고 사용mongodb-csharp driver을 바꾸면 이 구동도 완벽하지 않은 부분이 많다. 특히 LINQ에 대한 지원은 NoRM이 좋지 않았지만 최종적으로 몇 차례의 회전을 거쳐 기본 기능을 실현했다.이 드라이버를 사용하여Provider를 실현하는 가장 간단한 방법은 바로 이 글에서 말한 방법입니다. http://blog.dynamicprogrammer.com/2009/11/10/UsingMongoDBFromC.aspx 실체 클래스에 Document InternalDocument {get; set;},그러나 이렇게 하면 실체류에 대해 매우 큰 침입성을 가진다.나는 이런 방식을 채택하지 않았다.나의 최종 실현 방법은 실체류에 대한 영향을 최소화할 수 있다.
    예를 들면 다음과 같습니다.
    public class Team
    {
       public int ID { get; set; }// Document Id
       public string Name { get; set; }
       public string Odds { get; set; }
    }
    public class Group
    {
       [MongoId]
       public string Name { get; set; }// Document Id
       public List<Team> Teams { get; set; }
    }
    전체Provider는 IUpdatable 인터페이스를 실현한 클래스로 이 클래스는 정적 방법으로 대응하는 데이터베이스를 얻을 수 있다. 예를 들어 다음과 같다.
    public class MongoDBDataContext : IUpdatable
    {
        private static IMongoDatabase _db;
        public IMongoDatabase DB
        {
        get
        {
            if (_db == null)
            {
                Mongo mongo = new Mongo();
                mongo.Connect();
                _db = mongo.GetDatabase(this.DataBaseName);
            }
            return _db;
        }
        }
        
        public virtual string DataBaseName 
        { 
            get { return "temp"; } 
        }
    }
    이 Provider를 실현하려면 이 MongoDBDataContext를 계승하고 DataBaseName 속성을 다시 써서 자신의 데이터베이스 이름을 설정하고 DataServices를 설치하는 규범에 IQueryable의 속성을 추가하십시오. 예를 들어:
    public class WorldCupData : MongoDBDataContext
    {
       public override string DataBaseName
       {
           get
           {
               return "WorldCup";
           }
       }
    
       public IQueryable<Team> Teams
       {
           get
           {
               return DB.GetCollection<Team>("Team").Linq();
           }
       }
    
       public IQueryable<Group> Groups
       {
           get
           {
               return DB.GetCollection<Group>("Group").Linq();
           }
       }
    }
    구현 과정에서 가장 어려운 것은 Document를 정확하게 가져오고 저장하는 것입니다.반사를 통해 Document와 Entity를 동적으로 변환하고 Entity의 ID(또는 MongoId로 표시)의 속성의 ToString을 Document의 로 설정하는 절충안을 취했습니다.id,id도 항상 문자열입니다.핵심 코드는 다음과 같습니다.
    private static BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty;
    private static Document GetDocumentFromEntity(object entity,Type entityType)
    {
      if (entity == null) return null;
      Document doc = new Document();
      var properties = entityType.GetProperties(flags);
      foreach (var pro in properties)
      {
          object proGetValue = pro.GetValue(entity, null);
          if (pro.Name.ToLower() == "id" || pro.Name.ToLower() == "_id")// Document Id
              doc.Id = proGetValue.ToString();
          else if (Attribute.IsDefined(pro, typeof(MongoIdAttribute)))// Document Id
              doc.Id = proGetValue.ToString();
          doc[pro.Name] = proGetValue;
      }
      return doc;
    }
    
    private static object GetEntityFromDocument(Document doc, string fullTypeName)
    {
      if (doc == null) return null;
      Type t = Type.GetType(fullTypeName, true);
      object entity = Activator.CreateInstance(t);
      var properties = t.GetProperties(flags);
      foreach (var pro in properties)
      {
          if (doc.ContainsKey(pro.Name))
              pro.SetValue(entity, doc[pro.Name], null);
      }
      return entity;
    }
    
    public object GetResource(IQueryable query, string fullTypeName)
    {
      object resource = null;
    
      //query , , 
      //foreach (var item in query)
      //{
      //    resource = item;
      //}
    
      var exp = query.Expression as MethodCallExpression;
      var arg1 = exp.Arguments[1] as UnaryExpression;
      var expStr = arg1.Operand.ToString();//element => (element.ID == 0)
    
      string[] fullTypeNameSplit = fullTypeName.Split('.');
      var col= DB.GetCollection(fullTypeNameSplit[fullTypeNameSplit.Length - 1]);
      
      //like to translate (element.ID == 0) to { ID : 0 }
      string expStrSplit1 = expStr.Split('>')[1].Trim();//(element.ID == 0)
      var valueStr = expStrSplit1.Split(new string[] { "==" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim();//0)
      valueStr = valueStr.TrimEnd(')');
      
      var selector = new Document { Id = valueStr };
      var doc = col.FindOne(selector);
      
      resource = GetEntityFromDocument(doc, fullTypeName);
      
      
      // fullTypeName can be null for deletes
      if (resource != null && fullTypeName != null && resource.GetType().FullName != fullTypeName)
          throw new Exception("Unexpected type for resource");
      return resource;
    }
    GetResource 방법에서 안전하지 않은 작은 기교를 사용했음을 주의하십시오.이 구동의 LINQ가 완벽하지 않아서query가 작동하지 않기 때문에 표현식을 가져와 조건값을 해석할 수 밖에 없습니다.더욱이 앞의 약속에 의하면 이 조건값은 Document의 이다id.
    전체 Provider의 원본 코드와 테스트 클라이언트는 http://code.msdn.microsoft.com/DSPforNoSQL에서 다운로드할 수 있습니다.
     

    좋은 웹페이지 즐겨찾기