2014-02-13 3 views
0

Я создал для объектов пользователя объекты ObservableCollection объектов UserModule, называемые UserModules.Создание объектов из IDataReader

У меня приблизительно. 100000 записей пользователя, каждый пользователь может иметь до 10 записей модулей, и для этого требуется несколько минут.

Это может означать изменение из IDataReader, открытого для предложения. Может ли кто-нибудь предложить более эффективный способ сделать это?

public void LoadUsers() 
{ 
    clsDAL.SQLDBAccess db = new clsDAL.SQLDBAccess("USERS"); 
    clsDAL.SQLDBAccess db_user_modules = new clsDAL.SQLDBAccess("USERS"); 
    try 
    { 
     db.setCommandText(@"SELECT * FROM Users"); 

     using (var reader = db.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       var user = new User(); 
       MapUser(reader, user); 
       _users.Add(user); 

       db_user_modules.setCommandText(@"SELECT MODULE_ID, USER_MODULE_ACCESS FROM USER_MODULE_SECURITY Where USER_ID = " + user.User_ID); 

       using (var reader_user_modules = db_user_modules.ExecuteReader()) 
       { 
        while (reader_user_modules.Read()) 
        { 
         MapUserModule(reader_user_modules, user); 
        } 
       } 
      } 
     } 
    } 
    catch(Exception ex) 
    { 
     MessageBox.Show(ex.Message); 
     throw; 
    } 
    finally 
    { 
     db = null; 
    } 

} 

MapUser

public static void MapUser(IDataRecord record, User user) 
{ 
    try 
    { 
     user.User_ID = NullSafeGetter.GetValueOrDefault<int>(record, "USER_ID"); 
     user.Username = NullSafeGetter.GetValueOrDefault<string>(record, "USERNAME"); 
     user.Name = NullSafeGetter.GetValueOrDefault<string>(record, "NAME"); 
     user.Job_Title = NullSafeGetter.GetValueOrDefault<string>(record, "JOB_TITLE"); 
     user.Department = NullSafeGetter.GetValueOrDefault<string>(record, "DEPARTMENT"); 
     user.Company = NullSafeGetter.GetValueOrDefault<string>(record, "COMPANY"); 
     user.Phone_Office = NullSafeGetter.GetValueOrDefault<string>(record, "PHONE_OFFICE"); 
     user.Phone_Mobile = NullSafeGetter.GetValueOrDefault<string>(record, "PHONE_MOBILE"); 
     user.Email = NullSafeGetter.GetValueOrDefault<string>(record, "EMAIL"); 
     user.Password = NullSafeGetter.GetValueOrDefault<string>(record, "PASSWORD"); 
     user.Last_Login = NullSafeGetter.GetValueOrDefault<DateTime>(record, "LAST_LOGIN"); 
     user.Status = NullSafeGetter.GetValueOrDefault<int>(record, "STATUS"); 
     user.Session_Timeout = NullSafeGetter.GetValueOrDefault<int>(record, "SESSION_TIMEOUT"); 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show("Mapping User error: " + ex.Message); 
     throw; 
    } 
} 

MapUserModule

private static void MapUserModule(IDataRecord record, User user) 
{ 
    try 
    { 
     int m_id = NullSafeGetter.GetValueOrDefault<int>(record, "MODULE_ID"); 
     int uma = NullSafeGetter.GetValueOrDefault<int>(record, "USER_MODULE_ACCESS"); 

     user.UserModules.Add(new Users.UserModule(user.User_ID, m_id, uma)); 
    } 
    catch (Exception ex) 
    { 
     throw new Exception("Mapping UserModule error:\n" + ex.Message); 
    } 
} 
+1

Поиск проблемы с n + 1. Большая часть вашей медлительности должна быть из-за того, что вы замкнуты в запросе 'UserModule'. Предполагая, что у вас 100000 пользователей, этот запрос выполняется 100000 раз. Предполагая, что в вашей базе данных будет латентность 1 мс (невероятно быстро), это займет 100000 мс или 100 с, что равно примерно 2 минутам. Короче говоря, 2 минуты (по крайней мере) в вашем коде составлены из задержек в сети. – Aron

+0

Если я запустил его без добавления пользовательских модулей, это займет около секунды. – Hank

+0

Мой совет, выберите все UserModules в одном запросе, поместите их все в 'ILookup'. Затем получите всех пользователей, а затем выполните user.UserModules = userModuleLookup [user.Id] .ToList() '. – Aron

ответ

3
public IEnumerable<UserModule> GetUserModules() 
{ 
    using(var db = ....) 
    db.setCommandText("SELECT * FROM USERMODULES"); 
    using (var reader = db.ExecuteReader()) 
    { 
     while (reader.Read()) 
     { 
      var userId = reader[...]; 
      var m_id = reader[...]; 
      var uma = reader[...]; 
      yield return new UserModule (userid, m_id, uma) 
     } 
    } 
} 

public IEnumerable<User> GetUsers() 
{ 
    var userModulesLookup = GetUserModules().ToLookup(x => x.UserId); 
    using (var db = ...) 
    { 
     db.setCommandText("SELECT * FROM USERS"); 
     using (var reader = db.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       var userId = reader["userId"]; 
       ...blah blah blah... 
       var user = return new User(); 
       user.Modules = new ObservableCollection<UserModule> 
            (userModulesLookup[userId]); 
       ...blah blah blah... 
       yield return user; 
      } 
     } 
    } 
} 

public void LoadUsers() 
{ 
    var users = GetUsers(); 
    foreach(var u in users) 
     _users.Add(u); 
} 
+0

Это здорово, однако у меня есть user.Modules, определяемый как ObservableCollection, есть ли способ лишить userModulesLookup в коллекции? На данный момент он бросает Can not неявно преобразовывать тип List в ObservableCollection. – Hank

+0

Просто используйте новый ObservableCollection (userModulesLookup [userId]) – Aron

+0

Хорошо, как было использовано обновление ObservableCollection (userModulesLookup [userId]). Протестировано, и теперь это быстрее, чем раньше, спасибо! – Hank

1

Насколько я знаю, нет быстрее, чем решение с использованием DataReader.

Я бы порекомендовал вам профиль кода, чтобы узнать, что занимает большую часть времени. IIRC, добавляя большое количество предметов в наблюдаемую коллекцию по одному, медленно. Попытайтесь добавить их в список <> временно, чтобы попытаться изолировать проблему.

+0

Это звучит реалистично из-за того, что ObservableCollection будет наблюдать каждое дополнение. ObservableCollection имеет конструктор, который принимает список, чтобы он мог быть лучшим способом. Однако нет метода AddRange, так что это не помогает существующей коллекции, и нет способа временно приостановить наблюдение, что было бы неплохо. – jmcilhinney

Смежные вопросы