태터데스크 관리자

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

태터데스크 메시지

저장하였습니다.

'2009/12'에 해당되는 글 3건

  1. 2009/12/30 LINQ to SQL Behind the Scene
  2. 2009/12/30 트위터(Twitter)의 3가지 성공 요인
  3. 2009/12/27 Lucene.Linq with Entity Framework, Linq To Entities

LINQ to SQL Behind the Scene

.Net/.Net Framework Design Guide Line 2009/12/30 21:53

MS의 LINQ to SQL , LINQ to Entities , ENTITY FRAMEWORK는 .NET 개발자 진영에서 많은 논쟁을 벌여 왔습니다.

ORM의 역사가 짧은 .NET 진영에서 얼리아답터 들은 NHibernate 와 iBatis.NET을 받아 들였고, LINQ to SQL을 받아들인 개발 그룹, Enterprise Library를 이용하고 있는 그룹, MS Database Application Building Block을 이용하는 그룹, Raw기술인 DataSet을 이용하는 그룹 등이 혼재되어 있습니다. 국내에서는 아직  EF 는 보고 되지 않고 있군요.
심지어는 아직까지 ASP와 VBScript를 사용하고 있는 서비스도 많습니다. - Active Server Page가 나쁘다는 의미가 아닙니다.  개발 언어와 플렛폼이 개발자와 서비스를 제한하기 때문에 '심지어'라고 표현 한 것이니 오해 하진 말아 주세요.

이런 상황이니 L2S의 등장과 지원 중단이라는 말이 상당히 이해하기 힘들 수가 있음을 느끼고 있습니다.

또한, LINQ to SQL이 중단 되나? 라는 어휘가 명확하지 않아 오해의 소지가 있음을 권효중님의 댓글을 보고 새로운 포스트를 작성하게 되었습니다.

Julie Lerman 의 Programing Entity Framework 책을 기반으로  LINQ to SQL (이하 L2S)의 뒷면(Behind the Scene)를 적어 봅니다.

Julie Lerman은 Entity Framework 팀 구성과 개발에 참여한 개발자이며, Programing Entity Framework의 저자입니다. 블로그 및 사이트를 운영하고 있습니다.

2008년 10월 중순의 PDC2008에서 LINQ to SQL에 대한 더 이상의 지원이 중단 된다는 발표에 이미 CTP 때부터 L2S를 학습 및 적용했던 개발자들은 일제히 MS에 분개하며  'LINQ to SQL is Dead' 또는 'Is LINQ to SQL Dead'라는 블로그 포스트 들이 올라 오기 시작합니다.

이에 ADO.NET 블로그 팀은 해명에 나섭니다. L2S에서 Entity Framework로의 마이그레이션 가이드 라인과 함께, L2S가 Line up에서 제외 되지는 않는다. 다만 지속적인 evolution이 EF만큼 되지는 않을 것이다. 라는 공식 입장을 표명합니니다.

새로운 기술 또는 프레임워크를 도입한다는 것은 익숙해 지기까지 학습 비용과 적용 비용을 수반합니다. 또한 시간 투자도 요구 합니다. 앞으로의 유지 보수 및 추가 개발 문제도 고려 됩니다.

ADO.NET 팀 블로그의 공식 발표에도 불구하고 공식 발표가 명확하지 않아 L2S의 생사에 관한 논쟁은 1년이 넘도록 진행 중 입니다.

공식발표의 늬앙스에서도 읽을 수 있듯이 L2S의 더 이상의 향상이 어렵다는 것을 읽을 수 있습니다. 서비스나 프로그램이 지속성을 가지는 것이기 때문에 L2S 보다는 EF를 선택하는 것이 유리하다는 것이 저의 견해입니다.

Julie Lerman은 그의 책(1.7장)에서 왜 비슷한 기술이 만들어 졌을까?의 질문에 답을 밝힙니다. 

L2S는 LINQ Language를 개발하는 도중에  LINQ 프로젝트로 부터 나왔습니다.
EF는 Data Programmability team으로 부터 나왔고,  Entity SQL language 에 집중하엿습니다. 그로 부터 두개의 기술은 서로 별개로 개발되어져 왔습니다.  두 팀에게 기술이 보여 졌을 때에 MS는 두개의 기술이 서로 다른 목표를 만족 시킬수 있다고 판단 했습니다.
EF팀은 LINQ를 받아 들여 LINQ to Entities를 만듭니다(L2E가 L2S보다 10개월여 늦게 포함 된 것은 이 이유로 추측됩니다.). 하지만 L2S와 L2E가 너무 비슷하게 되어서 서로 다른 목표를 만족 시키는 시나리오가 틀려 버리게 됩니다.
결국에는 L2S가 EF팀에 통합되었습니다. L2S는 Language보다는 데이터 팀에 더 가까웠기 때문이라고 판단됩니다.

이윽고 PDC2008 에서 L2S의 개발 지원 중단이 발표 되게 되죠, SQL에만 한정되어 있으면서 또한 같은 역할을 하는 2개의 기술을 병행 개발하는 것은 비효율이라고 판단 한 것 같습니다.

Lerman은 그의 책 23.1장의 The Future of LINQ to SQL에서 L2S와 EF가 ADO.NET팀의 통제하에 있고, MS는 EF를 주요 전략으로 선택했음을 명확하게 결정 했다고 합니다. L2S 도 지속해서 유지보수( Maintain ) 와 미세조정( Tweak ) 될 것이지만 EF 만큼 투자 되지는 않을 것임을 결정 했다고 합니다. 또한 EF 로의 마이그레이션을 추천(Recommend) 합니다.

결론은 개발자와 회사의 입장으로서 앞으로의 서비스 및 제품의 유지보수와 진화를 위해 EF를 선택하는 것이 더 나은 판단으로 사료 됩니다.

관련 포스트  합니다. 1년 전에 작성 했었던 PDC 관련 내용이군요.
Linq to Entities 와 ADO.NET ENTITY FRAMEWORK 가 승리자가 되다.

 

 

저작자 표시
이올린에 북마크하기(0) 이올린에 추천하기(0)

현재글 : LINQ to SQL Behind the Scene posted By - 반더빌트 2009/12/30 21:53
Trackback 0 : Comment 0

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


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


트위터(Twitter)의 3가지 성공 요인

Human Information Interaction 2009/12/30 11:32
구글로 대변되는 검색 혁명, 유튜브의 리치 미디어(동영상) 이후 웹 생태계는 근 2년간 정체되어 있었으나, 올해는 마이크로 블로그라는 이름의 트위터(twitter)가 성공 신화의 역사를 장식했다. 깨질 것 같지 않던 정적을 깰수 있었던 힘은 무엇이었을까?


1. 빠른 생산 및 소비 속도 (Frequency)
빈도(Frequency)는 서비스 성공에 중요한 요소이다. 아무리 좋은 정보가 있어도 사용 빈도가 높지 않으면 성공하지 못한다.

커뮤니케이의션의 형태는 중앙집중적 성격의 위키, 개인 미디어의 블로그, 블로그의 소형화 또는 메신저의 영속화의 마이크로 블로그를 들 수 있다.

정보 생산 및 소비 속도를 미디어 별로 나타내자면

위키 -  10 km/h
블로그 - 20 km/h
마이크로 블로그 - 100 km/h

라고 말 할 수 있다.

위키는 3가지 미디어중에서 가장 영속적 이지만 생산 속도가 느려서 지속적으로 방문할 또는 관찰할 필요성이 적다.

블로그는 위키보다는 빠르지만 정보 수요 속도를 충족 시키지 못한다. 구독하고 있는 블로그가 하루에 1개 이상의 포스트가 업데이트 되는 경우는 별로 없을 것이다. 구독하고 있는 블로그를 하루에 1번 이상 방문할 필요성이 없게 된다.

마이크로 블로그는 가장 빈도수가 높은 인스턴트 메신저를 영속화 하고, 통신 대상을 개방한 형태이다. 생산 속도가 빠르고 빈도도 높으며, 지속적인 방문 및 관찰을 요구한다. 트위터는 높은 빈도를 만족 시키는 서비스 이다.


2. 정보습득의 새로운 방법 제시
소셜 미디어 이전의 정보 습득 방법은 검색(Search) 또는 찾기(Finding)이었다. 소셜미디어는 마치 거실에 TV를 켜놓은 것과 같다. 주의(Attention)만 유지하면 다른 일을 하면서도 관심 있는 주제에 대해서 집중해서 낚으면 된다.

트위터는 소셜미디어의 성격을 가지고 있다. 메신저가 Private 소셜 이라면, 트위터는 Public 소셜이다. 소셜 미디어는 정보 자체 보다는 사람과 사람의 행위(Behavior)에 주목한다. 정보 과잉 시점이 오면서 소비자들은 사람에 의한 정보 필터링이라는 검색엔진 이외의 필터링 도구를 사용하게 되었다.

Attention과 Person Behavior에 의한 정보 필터링 방법을 광범위하게 전파한 것이 트위터이다.

트위터의 주 이용자 층이 30~40대의 남성인 것은 정보 자체 보다는 관계의 행동이 중요한 계층이기 때문이다.


3. 모바일 환경의 전개
근 몇년 모바일 통신 대역폭이 급속히 증가하였다.  모바일은 언제(Every Time), 어디(Every Where)든 소비자와 함께 있는 정보 단말기 이다. 모바일 기반의 정보 통신에 가장 적합한 미디어가 단문 메세지 중심인 트위터의 서비스에 적합했던 것이다.


트위터의 성공은 지속 가능한가?
답은 글쎄다.

140 byte의 미디어는 다른 영역의 가치를 생산해 낼 수 있는 만큼의 정보를 담을 수 없는 한계를 가지고 있다. 즉, 자신의 영역에서 가치를 생산해 낼 만한 정보를 트위터의 미디어가 담아 줄 수 없는 것이다.
트위터, 아저씨들의 놀이터? - 트위터 사용자의 성별 및 연령

정보의 내용 자체가 휘발성과 불연속성을 가지고 있다.
웹에 기록 된다고 모든 정보가 영속성을 갖는 것은 아니다. 내용 자체의 생명기간이 짧은 한계를 가지고 있다.

대화라는 속성은 불연속적이며 종종 관계없는 내용들로 가득찬다. 또한 재구성 비용이 매우 높다.

트위터는 아이 러브 스쿨의 경우를 경계해야 한다. 관계 형성의 필요성이 충족 되고 나면 서비스의 가치도 하락하기 때문이다.



관련 포스트
저작자 표시
이올린에 북마크하기(0) 이올린에 추천하기(0)

현재글 : 트위터(Twitter)의 3가지 성공 요인 posted By - 반더빌트 2009/12/30 11:32
Trackback 0 : Comment 0

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


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


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 관련글 쓰기


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