태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

Lucene.Linq with Entity Framework, Linq To Entities

.Net 2009/12/27 20:53

.NET 개발자를 위한 오픈소스 검색엔진 라이브러리로 Lucene.Net 이 있습니다.

자바로 진행중인 Lucene 프로젝트를 .NET Framework 으로 포팅하는 프로젝트 입니다.

아파치의 인큐베이터에 포함된 프로젝트이며, 2.4 버전이 릴리즈 되어 있으며, 알파 버전으로는 2.9.1 버전이 진행 중입니다.

Lucene의 자바는 3.0 버전이 2009.11.25일 릴리즈 되어 있습니다.

자바 루씬 프로젝트 : Lucene Docs
Lucene.Net 프로젝트 :  Lucene.Net
Linq to Lucene 프로젝트 : Linq to Lucene

Linq to Lucene은 Lucene.Net 라이브러리를 Linq로 이용할 수 있도록 진행되는 프로젝트 입니다.

Lucene.Net을 Linq의 범용 확장성의 날개를 가질 수 있는 프로젝트가 Linq to Lucene 입니다.

Linq to Lucene은 Linq to SQL을 기반으로 작성되어 있으며, Linq to SQL 기반으로 진행되는 프로젝트에서는 같은 방법을 사용하는 Linq to Lucene을 그대로 사용하는 것이 프로젝트 통합 관리에 유리할 것입니다.

하지만, Linq to Entities 또는 Entity Framework 기반으로 프로젝트를 진행 한다면, Linq to Lucene을 그대로 사용하는 것이 껄끄러울 것입니다.

Linq to SQL 기반의 Linq to Lucene은 DatabaseIndexSet<DataContext>:IndexSet 을 상속받은 구상 DataBase  , e.g NorthwindIndexContext  를 직접 정의 하여 사용하는 방식을 취합니다.

Entity Framework(EF) 기반의 프로젝트에 직접 사용하기 위해서 구글링을 하였으나, EF용 코드가 존재 하지 않아, 코드를 작성하였습니다.
L2S 기반의 DatabaseIndexSet 에 대응하는 EF 기반 DatabaseEFIndexSet 을 Lucene.Linq 프로젝트에 포함하고 사용하면 됩니다.

EF용 DatabaseEFIndexSet

 public class DatabaseEFIndexSet<TObjectContext>: IndexSet
        where TObjectContext : ObjectContext {
        #region Fields/Properties

        readonly ReaderWriterLockSlim _dataContextLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
        TObjectContext _dataContext;
        

        /// <summary>
        /// The data context instance. 
        /// Data Contexts should be recycled periodically based on unit-of-work basis.
        /// 
        /// </summary>
        public TObjectContext ObjectContext
        {
            get
            {
                return _dataContext;
            }
            set {
                if (value == null) 
                    throw new ArgumentNullException("value");

                using (_dataContextLock.WriteLock()) {
                    _dataContext = value;
                }
            }
        }

        #endregion

        #region Ctors/Init

        /// <summary>Creates RAM Indexes from data context</summary>
        /// <param name="dataContext">The data context instance</param>
        public DatabaseEFIndexSet(TObjectContext dataContext)
            : base() {
            if (dataContext == null)
                throw new ArgumentNullException("dataContext");

            ObjectContext = dataContext;
            Init();
        }

        ///<summary>Creates File System Indexes from data context</summary>
        ///<param name="path">File System path</param>
        /// <param name="dataContext">The data context instance</param>
        public DatabaseEFIndexSet(string path, TObjectContext dataContext):base(path) {
            if (dataContext == null)
                throw new ArgumentNullException("dataContext");

            ObjectContext = dataContext;
            Init();
        }

        ///<summary>Creates file system indexes from data context</summary>
        ///<param name="directory">File system directory info</param>
        /// <param name="dataContext">The data context instance.</param>
        public DatabaseEFIndexSet(DirectoryInfo directory, TObjectContext dataContext)
            : base(directory) {

            if (dataContext == null)
                throw new ArgumentNullException("dataContext");

            ObjectContext = dataContext;
            Init();
        }



        private void Init() {

            Type dcType = typeof(TObjectContext);

            // get all tables in db context
            var linqTableTypes = GetTableTypes();

            int linqTableCount = linqTableTypes.Count();

            // Throw if there are no tables
            if (linqTableCount == 0)
            {
                throw new ArgumentException("The data context type has no Tables");
            }

            // if there are any tables on the context, add them to the set
            foreach (var linqTableType in linqTableTypes)
            {
                try
                {
                    Add(linqTableType);
                }
                catch (ArgumentException)
                {
                    // linq table type doesn't have Document attribute
                    // for now, skipping this table type makes sense
                }
            }

                
            

        }

        #endregion
        
        #region Private Methods

        private IEnumerable<Type> GetTableTypes() {

            Type iTableType = typeof(EntityObject);
            var linqTableTypes = from prop in typeof(TObjectContext).GetProperties()
                                 where prop.PropertyType.IsClass && prop.PropertyType.Name =="ObjectQuery`1"
                                 select prop.PropertyType.GetGenericArguments()[0];
            //var linqTableTypes = from prop in typeof(TObjectContext).GetProperties()
            //                     where prop.PropertyType.IsGenericType &&
            //                           iTableType.IsAssignableFrom(prop.PropertyType)
            //                     select prop.PropertyType.GetGenericArguments()[0];

            return linqTableTypes;
        }

        private int GetTableRecordCount(ITable table, Type tableType) {
            Expression expr = Expression.Call(typeof(Queryable), "Count", new Type[] { tableType }, Expression.Constant(table));
            int count = table.Provider.Execute<int>(expr);
            return count;
            
        }


        #endregion

        #region Public Methods

        /// <summary>Write all the records from the table type into their respective indexes</summary>
        /// <typeparam name="TEntity">Table type to index</typeparam>
        public void Write<TEntity>() {
            //Write(typeof(TEntity));


            using (_dataContextLock.ReadLock())
            {
                Type tableType = typeof(TEntity);
                string name = tableType.Name;

                IIndex index = this.Get(tableType);

                ObjectQuery<TEntity> objectQuery = _dataContext.CreateQuery<TEntity>(name);
                if (objectQuery == null)
                    throw new ArgumentException("tableType doesnt belong to db");

                int itemCount = objectQuery.Execute(MergeOption.NoTracking).Count();

                var items = objectQuery.AsEnumerable();

                Console.WriteLine("About to write " + name + "s...");


                if (itemCount == index.Count)
                {
                    Console.WriteLine("Not adding " + name + "s, because index is up to date.");
                }
                else
                {
                    index.Add(items);
                    Console.WriteLine("Added " + index.Count + " " + name + "s.");
                } 
            }




        }

}


사용예: 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data.Common;
using Lucene.Linq;
using System.Data.Linq;
using Lucene.Linq.Expressions;
using System.Diagnostics;
using Lucene.Linq.Utility;
using Lucene.Net.Search;
using Lucene.Net.Index;

namespace Lucene.Linq.EntityDemo
{
    class Program
    {
        static NorthwindIndexContext index = null;

        static void Main(string[] args)
        {

            var path = @"C:\temp\index";
            try
            {
                System.IO.Directory.Delete(path, true);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            System.IO.Directory.CreateDirectory(path);
            Console.WriteLine("Northwind Db index:" + path);

            Type cType = typeof(Customers);

            index = new NorthwindIndexContext(path, new NorthwindContext());

            // add all the customers/orders to the index
            //index.Write(); // uncomment this line to write both Orders and Customers
            index.Write<Customers>();

            DefaultFieldsDemo();

            System.Console.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

        }


        static void SimpleDemo()
        {
            var query = from c in index.Customer
                        where c.ContactTitle == "Owner"
                        select c;

            Console.WriteLine("Simple Query:");
            ObjectDumper.Write(query);
            Console.WriteLine("Query Output: {0}", query.ToString());
            Console.WriteLine();

            var results = query.ToList();
            Console.WriteLine("SimpleDemo returned {0} results", results.Count);
        }

        static void DefaultFieldsDemo()
        {
            var query = from c in index.Customer
                        where (c.Match("Folies"))
                        select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };

            Console.WriteLine("Default Fields Query:");
            ObjectDumper.Write(query);
            Console.WriteLine("Query Output: {0}", query.ToString());
            Console.WriteLine();
        }

    }




}


저작자 표시

현재글 : Lucene.Linq with Entity Framework, Linq To Entities posted By - 반더빌트 2009/12/27 20:53
Trackback 0 : Comment 0

Trackback Address :: http://smack.kr/trackback/346 관련글 쓰기


[생각을 적어 주세요~ 댓글은 작은 인연의 씨앗입니다.]

◀ PREV : [1] : ... [7] : [8] : [9] : [10] : [11] : [12] : [13] : [14] : [15] : ... [296] : NEXT ▶