/// <summary>
        /// 지정한 Company 정보를 삭제합니다.
        /// </summary>
        /// <param name="company"></param>
        public void DeleteCompany(Company company)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"Company를 삭제합니다... company=" + company);

            DeleteEntityTransactional(company);

            if(log.IsInfoEnabled)
                log.Info(@"Company를 삭제했습니다!!! company=" + company);
        }
        /// <summary>
        /// 사용자 로그인 계정 정보로 사용자를 인증합니다.
        /// </summary>
        /// <param name="company"></param>
        /// <param name="loginId"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public bool AuthenticateUser(Company company, string loginId, string password)
        {
            company.ShouldNotBeNull("company");
            loginId.ShouldNotBeWhiteSpace("loginId");
            // password.ShouldNotBeWhiteSpace("password");

            if(log.IsDebugEnabled)
                log.Debug(@"사용자 인증을 실시합니다... companyId={0}, loginId={1}, password={2}", company.Id, loginId, password);

            return BuildQueryableOfUser(company, loginId, password).Any();

            //return NAccessContext.Linq.Users.Any(u => u.Company == company &&
            //                                          u.LoginId == loginId &&
            //                                          u.Password == password);
        }
        /// <summary>
        /// 지정된 회사의 모든 사원 직급 정보를 가져옵니다.
        /// </summary>
        public IList<EmployeeGrade> FindAllEmployeeGradeByCompany(Company company, int? firstResult, int? maxResults, params INHOrder<EmployeeGrade>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"사원 직급 정보(EmployeeGrade)를 조회합니다. company=" + company);

            var query =
                QueryOver.Of<EmployeeGrade>()
                    .AddWhere(g => g.Company == company)
                    .AddOrders(orders);

            return Repository<EmployeeGrade>.FindAll(query,
                                                     firstResult.GetValueOrDefault(),
                                                     maxResults.GetValueOrDefault());
        }
        /// <summary>
        /// 지정된 부서 Id를 가진 부서 정보를 로드한다. 만약 없다면 새로 생성하여 저장한 후 로드한다.
        /// </summary>
        /// <param name="company">소속 회사</param>
        /// <param name="code">부서 코드</param>
        /// <returns></returns>
        public Department GetOrCreateDepartment(Company company, string code)
        {
            company.ShouldNotBeNull("company");
            code.ShouldNotBeWhiteSpace("code");

            var department = FindOneDepartmentByCode(company, code);

            if(department == null)
            {
                if(IsDebugEnabled)
                    log.Debug(@"지정된 회사['{0}']에 부서['{1}']가 없습니다. 새로 생성합니다.", company.Code, code);

                lock(_syncLock)
                {
                    using(UnitOfWork.Start(UnitOfWorkNestingOptions.CreateNewOrNestUnitOfWork))
                    {
                        // Depatment.Name이 not-null이기 때문에 값이 들어가야 한다!!!
                        Repository<Department>.Save(new Department(company, code));
                        UnitOfWork.Current.TransactionalFlush();
                    }
                }

                department = FindOneDepartmentByCode(company, code);
                department.AssertExists("department");

                if(log.IsInfoEnabled)
                    log.Info("새로운 Department 정보를 생성했습니다. Department=" + department);
            }

            return department;
        }
        /// <summary>
        /// 특정 회사의 모든 코드 정보를 조회합니다.
        /// </summary>
        /// <param name="company">회사</param>
        /// <param name="firstResult">첫번째 결과 셋의 인덱스 (0부터 시작. null이면 0으로 간주)</param>
        /// <param name="maxResults">결과 셋의 최대 레코드 수 (null 또는 0 이하의 값은 무시된다)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IList<Code> FindAllCodeByCompany(Company company, int? firstResult, int? maxResults, params INHOrder<Code>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"특정 회사의 모든 코드 정보를 조회합니다... " +
                          @"companyCode={0}, firstResult={1}, maxResults={2}, orders={3}",
                          company.Code, firstResult, maxResults, orders.CollectionToString());

            var query = QueryOver.Of<Code>().AddWhere(c => c.Group.CompanyCode == company.Code).AddOrders(orders);

            return Repository<Code>.FindAll(query,
                                            firstResult.GetValueOrDefault(),
                                            maxResults.GetValueOrDefault());
        }
        /// <summary>
        /// 지정한 구성원이 속한 그룹구성원 정보를 조회합니다.
        /// </summary>
        /// <param name="company">그룹이 소속된 회사</param>
        /// <param name="actorCode">그룹 소속원 코드 (Actor 코드 : 회사|부서|그룹|사용자 코드)</param>
        /// <param name="actorKind">그룹 소속원 종류 (사용자|부서| 타 그룹)</param>
        /// <param name="firstResult">첫번째 결과 셋의 인덱스 (0부터 시작. null이면 0으로 간주)</param>
        /// <param name="maxResults">결과 셋의 최대 레코드 수 (null 또는 0 이하의 값은 무시된다)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IList<GroupActor> FindAllGroupActorByActor(Company company, string actorCode, ActorKinds? actorKind,
                                                          int? firstResult, int? maxResults, params INHOrder<GroupActor>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(log.IsDebugEnabled)
                log.Debug(@"지정한 구성원이 속한 그룹-구성원 정보를 조회합니다... " +
                          @"actorCode={0}, actorKind={1}, company={2}, firstResult={3}, maxResults={4}, orders={5}",
                          actorCode, actorKind, company, firstResult, maxResults, orders);

            var query = BuildQueryOverOfGroupActor(company.Code, null, actorCode, actorKind).AddOrders(orders);

            return Repository<GroupActor>.FindAll(query,
                                                  firstResult.GetValueOrDefault(),
                                                  maxResults.GetValueOrDefault());
        }
        /// <summary>
        /// 지정된 회사에 소속된 모든 사용자의 UserConfig 정보를 Paging 처리해서 로드합니다.
        /// </summary>
        /// <param name="product">검색 대상 제품</param>
        /// <param name="company">검색 대상 회사</param>
        /// <param name="pageIndex">Page Index (0부터 시작합니다.)</param>
        /// <param name="pageSize">Page Size (보통 10입니다. 0보다 커야 합니다.)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IPagingList<UserConfig> GetPageOfUserConfigByProductAndCompany(Product product, Company company,
                                                                              int pageIndex, int pageSize, params INHOrder<UserConfig>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"지정된 회사에 소속된 사용자의 UserConfig 정보를 Paging 처리해서 로드합니다... " +
                          @"productCode={0}, companyCode={1}, pageIndex={2}, pageSize={3}, orders={4}",
                          product.Code, company.Code, pageIndex, pageSize, orders);

            return Repository<UserConfig>.GetPage(pageIndex,
                                                  pageSize,
                                                  BuildQueryOverOfUserConfig(product.Code, company.Code),
                                                  orders);
        }
        /// <summary>
        /// 지정된 회사의 모든 사용자 정보를 조회합니다.
        /// </summary>
        /// <param name="company"></param>
        /// <returns></returns>
        public IList<User> FindAllUserByCompany(Company company)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"지정된 회사의 모든 사용자 정보를 조회합니다... companyCode=" + company.Code);

            return NAccessContext.Linq.Users.Where(u => u.Company == company).ToList();
        }
        /// <summary>
        /// 특정 사용자 정보를 Load합니다.
        /// </summary>
        public User FindOneUserByCode(Company company, string code)
        {
            company.ShouldNotBeNull("company");
            code.ShouldNotBeWhiteSpace("code");

            if(IsDebugEnabled)
                log.Debug(@"사용자 정보를 조회합니다. Company={0}, code={1}", company.Id, code);

            return
                NAccessContext.Linq.Users
                    .Where(u => u.Company == company &&
                                u.Code == code)
                    .SingleOrDefault();
        }
        /// <summary>
        /// 지정된 Company의 모든 부서정보를 삭제합니다.
        /// </summary>
        /// <param name="company"></param>
        public void DeleteAllDepartmentByCompany(Company company)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"지정된 회사의 모든 부서 정보를 삭제합니다. company=" + company);

            Repository<Department>.DeleteAll(QueryOver.Of<Department>().AddWhere(dept => dept.Company == company));
        }
 /// <summary>
 /// 코드 Identity 값으로부터 코드 정보를 조회합니다.
 /// </summary>
 /// <param name="company">회사</param>
 /// <param name="groupCode">그룹 코드</param>
 /// <param name="itemCode">아이템 코드</param>
 /// <returns></returns>
 public Code FindOneCodeByCode(Company company, string groupCode, string itemCode)
 {
     company.ShouldNotBeNull("company");
     return FindOneCodeByCode(company.Code, groupCode, itemCode);
 }
        /// <summary>
        /// 지정한 회사에 속한 그룹-구성원(GroupActor) 정보를 Paging 처리해서 로드합니다
        /// </summary>
        /// <param name="company">검색할 회사</param>
        /// <param name="pageIndex">페이지 인덱스 (0부터 시작)</param>
        /// <param name="pageSize">페이지 크기 (0보다 커야 한다. 보통 10)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IPagingList<GroupActor> GetPageOfGroupActorByCompany(Company company, int pageIndex, int pageSize, params INHOrder<GroupActor>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(log.IsDebugEnabled)
                log.Debug(@"지정한 회사에 속한 그룹-구성원(GroupActor) 정보를 Paging 처리해서 로드합니다... " +
                          @"company={0}, pageIndex={1}, pageSize={2}, orders={3}",
                          company, pageIndex, pageSize, orders);

            return Repository<GroupActor>.GetPage(pageIndex,
                                                  pageSize,
                                                  BuildQueryOverOfGroupActor(company.Code, null, null, null),
                                                  orders);
        }
        /// <summary>
        /// 특정 회사의 Group 정보를 Paging 조회합니다
        /// </summary>
        public IPagingList<Group> GetPageOfGroupByCompany(Company company, int pageIndex, int pageSize, params INHOrder<Group>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"특정 회사의 Group 정보를 Paging 조회합니다... company={0}, pageIndex={1}, pageSize={2}, orders={3}",
                          company, pageIndex, pageSize, orders);

            var query = QueryOver.Of<Group>().AddWhere(g => g.Company == company);

            return Repository<Group>.GetPage(pageIndex, pageSize, query, orders);
        }
        /// <summary>
        /// 지정된 회사의 <paramref name="code"/>를 가지는 그룹 정보를 로드한다. 만약 없다면, 새로 생성해서 반환한다.
        /// </summary>
        /// <param name="company">소속 회사</param>
        /// <param name="code">그룹 Id</param>
        /// <returns></returns>
        public Group GetOrCreateGroup(Company company, string code)
        {
            company.ShouldNotBeNull("comapny");

            if(IsDebugEnabled)
                log.Debug(@"그룹 정보를 조회합니다... companyCode={0}, code={1}", company.Code, code);

            var group = FindOneGroupByCode(company, code);

            if(group == null)
            {
                if(IsDebugEnabled)
                    log.Debug(@"새로운 Group 정보를 생성합니다... company={0}, code={1}", company.Id, code);

                lock(_syncLock)
                    using(UnitOfWork.Start(UnitOfWorkNestingOptions.CreateNewOrNestUnitOfWork))
                    {
                        UnitOfWork.CurrentSession.Save(new Group(company, code));
                        UnitOfWork.Current.TransactionalFlush();
                    }

                group = FindOneGroupByCode(company, code);
                group.AssertExists("group");

                if(log.IsInfoEnabled)
                    log.Info("새로운 Group 정보를 생성했습니다!!! " + group);
            }

            return group;
        }
        /// <summary>
        /// 특정 회사의 모든 Group 정보를 조회합니다.
        /// </summary>
        /// <param name="company">회사</param>
        /// <param name="firstResult">첫번째 결과 셋의 인덱스 (0부터 시작. null이면 0으로 간주)</param>
        /// <param name="maxResults">결과 셋의 최대 레코드 수 (null 또는 0 이하의 값은 무시된다)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IList<Group> FindAllGroupByCompany(Company company, int? firstResult, int? maxResults, params INHOrder<Group>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"특정 회사의 모든 Group 정보를 조회합니다... company={0}, firstResult={1}, maxResults={2}, orders={3}",
                          company, firstResult, maxResults, orders);

            var query = QueryOver.Of<Group>().AddWhere(g => g.Company == company).AddOrders(orders);

            return Repository<Group>.FindAll(query,
                                             firstResult.GetValueOrDefault(),
                                             maxResults.GetValueOrDefault());
        }
        /// <summary>
        /// 지정된 회사의 모든 그룹-구성원(GroupActor) 정보를 조회합니다.
        /// </summary>
        /// <param name="company">그룹이 소속된 회사</param>
        /// <param name="firstResult">첫번째 결과 셋의 인덱스 (0부터 시작. null이면 0으로 간주)</param>
        /// <param name="maxResults">결과 셋의 최대 레코드 수 (null 또는 0 이하의 값은 무시된다)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IList<GroupActor> FindAllGroupActorByCompany(Company company, int? firstResult, int? maxResults, params INHOrder<GroupActor>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(log.IsDebugEnabled)
                log.Debug(@"지정한 회사에 속한 그룹-구성원(GroupActor) 정보를 조회합니다... company={0}, firstResult={1}, maxResults={2}, orders={3}",
                          company, firstResult, maxResults, orders);

            return Repository<GroupActor>.FindAll(BuildQueryOverOfGroupActor(company.Code, null, null, null).AddOrders(orders),
                                                  firstResult.GetValueOrDefault(),
                                                  maxResults.GetValueOrDefault());
        }
        /// <summary>
        /// 지정한 코드 그룹의 코드 정보들을 조회합니다.
        /// </summary>
        /// <param name="company">회사</param>
        /// <param name="groupCode">그룹 코드</param>
        /// <param name="firstResult">첫번째 결과 셋의 인덱스 (0부터 시작. null이면 0으로 간주)</param>
        /// <param name="maxResults">결과 셋의 최대 레코드 수 (null 또는 0 이하의 값은 무시된다)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IList<Code> FindAllCodeByGroup(Company company, string groupCode, int? firstResult, int? maxResults, params INHOrder<Code>[] orders)
        {
            company.ShouldNotBeNull("company");
            groupCode.ShouldNotBeWhiteSpace("groupCode");

            if(IsDebugEnabled)
                log.Debug(@"지정한 코드 그룹의 코드 정보들을 조회합니다... " +
                          @"companyCode={0}, groupCode={1}, firstResult={2}, maxResults={3}, orders={4}",
                          company.Code, groupCode, firstResult, maxResults, orders.CollectionToString());

            var query = BuildQueryOverOfCode(company.Code, groupCode, null, null, null, null).AddOrders(orders);

            return Repository<Code>.FindAll(query,
                                            firstResult.GetValueOrDefault(),
                                            maxResults.GetValueOrDefault());
        }
        /// <summary>
        /// 지정된 회사의 모든 부서-직원 소속 정보를 로드합니다.
        /// </summary>
        /// <param name="company">회사</param>
        /// <param name="firstResult">첫번째 결과 셋의 인덱스 (0부터 시작. null이면 0으로 간주)</param>
        /// <param name="maxResults">결과 셋의 최대 레코드 수 (null 또는 0 이하의 값은 무시된다)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IList<DepartmentMember> FindAllDepartmemtMemberByCompany(Company company, int? firstResult, int? maxResults, params INHOrder<DepartmentMember>[] orders)
        {
            company.ShouldNotBeNull("company");

            Department @departmentAlias = null;

            var query =
                QueryOver.Of<DepartmentMember>()
                    .JoinAlias(dm => dm.Department, () => @departmentAlias)
                    .AddWhere(() => @departmentAlias.Company == company);

            return Repository<DepartmentMember>.FindAll(query.AddOrders(orders),
                                                        firstResult.GetValueOrDefault(),
                                                        maxResults.GetValueOrDefault());
        }
 /// <summary>
 /// 지정된 회사의 코드 그룹 정보를 가져온다.
 /// </summary>
 /// <param name="company">회사</param>
 /// <returns></returns>
 public IList<CodeGroup> FindAllCodeGroupByCompany(Company company)
 {
     company.ShouldNotBeNull("company");
     return FindAllCodeGroupByCompany(company.Code);
 }
        /// <summary>
        /// 지정된 회사의 모든 부서 정보를 조회합니다.
        /// </summary>
        /// <param name="company">회사</param>
        /// <param name="firstResult">첫번째 결과 셋의 인덱스 (0부터 시작. null이면 0으로 간주)</param>
        /// <param name="maxResults">결과 셋의 최대 레코드 수 (null 또는 0 이하의 값은 무시된다)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IList<Department> FindAllDepartmentByCompany(Company company, int? firstResult, int? maxResults, params INHOrder<Department>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"지정된 회사의 모든 부서 정보를 조회합니다... company={0}, firstResult={1}, maxResults={2}, orders={3}",
                          company, firstResult, maxResults, orders.CollectionToString());

            var query = QueryOver.Of<Department>().AddWhere(dept => dept.Company == company);
            return Repository<Department>.FindAll(query.AddOrders(orders),
                                                  firstResult.GetValueOrDefault(),
                                                  maxResults.GetValueOrDefault());
        }
 /// <summary>
 /// 지정된 코드를 조회한다. 없다면, 새로 생성하여 저장한 후, 반환한다.
 /// </summary>
 /// <param name="company">회사</param>
 /// <param name="groupCode">그룹 코드</param>
 /// <param name="itemCode">아이템 코드</param>
 /// <returns></returns>
 public Code GetOrCreateCode(Company company, string groupCode, string itemCode)
 {
     company.ShouldNotBeNull("company");
     return GetOrCreateCode(company.Code, groupCode, itemCode);
 }
        /// <summary>
        /// 사번으로 직원 찾기
        /// </summary>
        /// <param name="company"></param>
        /// <param name="empNo"></param>
        /// <returns></returns>
        public User FindOneUserByEmpNo(Company company, string empNo)
        {
            company.ShouldNotBeNull("company");
            empNo.ShouldNotBeWhiteSpace("empNo");

            if(IsDebugEnabled)
                log.Debug("특정 사번의 사용자 정보를 조회합니다. Company={0}, empNo={1}", company, empNo);

            return
                NAccessContext.Linq.Users
                    .Where(u => u.Company == company &&
                                u.EmpNo == empNo)
                    .SingleOrDefault();
        }
        /// <summary>
        /// 지정된 회사에서, 지정된 이름과 매칭되는 (LIKE 검색) 사용자 정보를 조회합니다.
        /// </summary>
        /// <param name="company"></param>
        /// <param name="nameToMatch"></param>
        /// <param name="matchMode"></param>
        /// <returns></returns>
        public IList<User> FindAllUserByCompanyAndNameToMatch(Company company, string nameToMatch, MatchMode matchMode)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug("사용자 이름과 매칭 검색을 수행합니다. nameToMatch={0}, matchMode={1}", nameToMatch, matchMode);

            var query =
                QueryOver.Of<User>()
                    .AddWhere(u => u.Company == company)
                    .AddInsensitiveLike(u => u.Name, nameToMatch, matchMode ?? MatchMode.Anywhere);

            return Repository<User>.FindAll(query);
        }
        /// <summary>
        /// 지정한 회사의 사원 정보를 로드합니다. 만약 없다면, 새로 생성해서 저장한 후 로드 합니다. (그냥 Load 시에는 <see cref="FindOneUserByCode"/>로 호출하시기 바랍니다.
        /// </summary>
        public User GetOrCreateUser(Company company, string code)
        {
            company.ShouldNotBeNull("company");
            code.ShouldNotBeWhiteSpace("code");

            var user = FindOneUserByCode(company, code);

            if(user != null)
                return user;

            if(IsDebugEnabled)
                log.Debug(@"지정된 회사[{0}]에 사용자[{1}]가 없습니다. 새로 생성합니다.", company.Code, code);

            lock(_syncLock)
            {
                using(UnitOfWork.Start(UnitOfWorkNestingOptions.CreateNewOrNestUnitOfWork))
                {
                    Repository<User>.Save(new User(company, code));
                    UnitOfWork.CurrentSession.Flush();
                }
            }

            user = FindOneUserByCode(company, code);
            user.AssertExists("user");

            if(log.IsInfoEnabled)
                log.Info("새로운 User 정보를 생성했습니다!!! New User = " + user);

            return user;
        }
        /// <summary>
        /// 조직명 매칭 검색 (LIKE 검색)을 수행합니다.
        /// </summary>
        /// <param name="company">소속 회사</param>
        /// <param name="nameToMatch">검색할 조직명</param>
        /// <param name="matchMode">검색 매칭 모드</param>
        /// <param name="firstResult">첫번째 결과 셋의 인덱스 (0부터 시작. null이면 0으로 간주)</param>
        /// <param name="maxResults">결과 셋의 최대 레코드 수 (null 또는 0 이하의 값은 무시된다)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IList<Department> FindAllDepartmentByNameToMatch(Company company, string nameToMatch, MatchMode matchMode, int? firstResult, int? maxResults,
                                                                params INHOrder<Department>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(nameToMatch.IsWhiteSpace())
                return FindAllDepartmentByCompany(company, firstResult, maxResults, orders);

            if(IsDebugEnabled)
                log.Debug(@"조직명 매칭 검색 (LIKE 검색)을 수행합니다... " +
                          @"company={0}, nameToMatch={1}, matchMode={2}, firstResult={3}, maxResults={4}, orders={5}",
                          company.Code, nameToMatch, matchMode, firstResult, maxResults, orders.CollectionToString());

            var query =
                QueryOver.Of<Department>()
                    .AddWhere(dept => dept.Company == company)
                    .AddInsensitiveLike(dept => dept.Name, nameToMatch, matchMode ?? MatchMode.Anywhere)
                    .AddOrders(orders);

            return Repository<Department>.FindAll(query,
                                                  firstResult.GetValueOrDefault(),
                                                  maxResults.GetValueOrDefault());
        }
        /// <summary>
        /// 즐겨찾기 생성
        /// </summary>
        /// <param name="product">제품</param>
        /// <param name="company">소유자 회사</param>
        /// <param name="ownerCode">소유자 코드</param>
        /// <param name="ownerKind">소유자 종류</param>
        /// <param name="content">즐겨찾기 내용</param>
        /// <returns></returns>
        public Favorite CreateFavorite(Product product, Company company, string ownerCode, ActorKinds ownerKind, string content)
        {
            product.ShouldNotBeNull("product");
            company.ShouldNotBeNull("company");
            ownerCode.ShouldNotBeWhiteSpace("owernCode");

            if(IsDebugEnabled)
                log.Debug(@"새로운 즐겨찾기 정보를 생성합니다... product={0}, company={1}, ownerCode={2}, ownerKind={3}, content={4}",
                          product, company, ownerCode, ownerKind, content);

            var favorite = new Favorite(product, company, ownerCode, ownerKind, content);
            return Repository<Favorite>.SaveOrUpdate(favorite);
        }
        /// <summary>
        /// 로그인 정보를 가진 사용자 정보를 로드합니다.
        /// </summary>
        /// <param name="company"></param>
        /// <param name="loginId"></param>
        /// <param name="password"></param>
        /// <returns>반환되는 User 정보가 있다면, 로그인 성공, 없다면 비밀번호가 틀렸다는 의미이다.</returns>
        public User FindOneUserByLogin(Company company, string loginId, string password)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug("사용자 계정으로 검색을 실시합니다... company.Code={0}, loginId={1}, password={2}", company.Code, loginId, password);

            var query =
                QueryOver.Of<User>()
                    .AddWhere(u => u.Company == company)
                    .AddWhere(u => u.LoginId == loginId);

            if(password.IsNotEmpty())
                query.AddWhere(u => u.Password == password);

            return Repository<User>.FindOne(query);
        }
 /// <summary>
 /// 지정된 회사의 부서 코드에 해당하는 부서정보를 로드합니다.
 /// </summary>
 public Department FindOneDepartmentByCode(Company company, string code)
 {
     company.ShouldNotBeNull("company");
     return FindOneDepartmentByCode(company.Code, code);
 }
        /// <summary>
        /// 지정된 회사의 모든 사용자 정보를 Paging 처리하여 로드합니다
        /// </summary>
        /// <param name="company">회사</param>
        /// <param name="pageIndex">페이지 인덱스 (0부터 시작)</param>
        /// <param name="pageSize">페이지 크기 (0보다 커야 한다. 보통 10)</param>
        /// <param name="orders">정렬 순서</param>
        /// <returns></returns>
        public IPagingList<User> GetPageOfUserByCompany(Company company, int pageIndex, int pageSize, params INHOrder<User>[] orders)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"지정된 회사의 모든 사용자 정보를 Paging 처리하여 로드합니다... company={0}, pageIndex={1}, pageSize={2}, orders={3}",
                          company.Code, pageIndex, pageSize, orders.CollectionToString());

            return Repository<User>.GetPage(pageIndex,
                                            pageSize,
                                            QueryOver.Of<User>().AddWhere(u => u.Company == company),
                                            orders);
        }
        /// <summary>
        /// 최상위 부서들의 정보를 조회한다.
        /// </summary>
        /// <param name="company"></param>
        /// <returns></returns>
        public IList<Department> FindRootDepartmentByCompany(Company company)
        {
            company.ShouldNotBeNull("company");

            if(IsDebugEnabled)
                log.Debug(@"지정된 회사의 최상위 부서 (Parent 가 Null인) 정보를 조회합니다... company=" + company);

            var query =
                QueryOver.Of<Department>()
                    .AddWhere(dept => dept.Company == company)
                    .WhereRestrictionOn(dept => dept.Parent).IsNull;

            return Repository<Department>.FindAll(query);
        }