Рефакторинг Linq в Sql - PullRequest
       18

Рефакторинг Linq в Sql

2 голосов
/ 22 сентября 2009

Есть ли способ реорганизовать linq в sql и воспользоваться преимуществами поздней оценки? Есть ли способ повторно использовать код инициализатора объекта?

У меня есть бизнес-объекты, которые хранятся в базе данных и обрабатываются отдельным слоем linq to sql.

Я хотел бы иметь возможность повторно использовать код из нескольких запросов, которые делают одно и то же. Часть запроса, которую я хотел бы использовать повторно, является частью создания объекта. Я также хотел бы продолжать использовать преимущества поздней оценки (получать только те столбцы, которые мне нужны, из базы данных).

Примеры, приведенные ниже, очень просты, и некоторые имена были изменены, чтобы защитить невинных.

Образец 1

void GetUserById(Guid userId)
{
    IQueryable<LinqLayer.User> x =
        from user in dataContext.Users
        where user.UserID == userId
        select user;

    IQueryable<BusinessLayer.User> y = hydrateUser(x);

    // Acutally execute the query against the database.
    BusinessLayer.User user = y.First();
}

void GetUserByName(string name)
{
    IQueryable<LinqUser> x =
        from user in dataContext.Users
        where user.FirstName == name
        select user;

    IQueryable<User> y = hydrateUser(x);

    // Acutally execute the query against the database.
    User user = y.First();
}

IQueryable<User> hydrateUser(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
        };
    return y;
}

В примере 1 происходит несколько вещей. В этом примере я могу воспользоваться поздней оценкой linq to sql. Если вы просматриваете запросы к базе данных, то выбираются только те столбцы, которые меня интересуют (перечислены в hydrateUser как ID, FirstName и т. Д.). Это хорошо, потому что я могу повторно использовать код в hydrateUser.

Образец 2:

IQueryable<User> hydrateUser(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
            ... Big long list of properties
        };
    return y;
}

IQueryable<User> hydrateUserWithPermissions(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
            ... Big long list of properties
            PermissionList = item.Permissions
        };
    return y;
}

Образец 2 начинает падать, когда я хочу использовать hydrateUser, а также гидрировать связанный объект. Например, увлажнение списка разрешений. Теперь я должен выделить целую отдельную функцию, которая выполняет дополнительную гидратацию. это менее желательно, если у меня есть гораздо больше свойств, которые я инициализирую.

Образец 3

IQueryable<User> hydratePermissions(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            PermissionList = item.Permissions
        };
    return y;
}

IQueryable<User> hydrateUser(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
            ... Big long list of properties
        };
    return y;
}

Что я хотел бы сделать, так это создать запрос с помощью кода, подобного примеру 3. Каким-то образом попробуйте воспользоваться обеими функциями. И совершить только одну поездку в базу данных. Однако это не работает.

Образец 4

User newUpUserFromLinqUser(LinqUser item)
{
    y = new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
        };
    return y;
}

Пример 4 близок к тому, что я хочу, но теряет оценку выражения, которую использует linq to sql для поздней оценки. Все поля вернутся в запросе. Хуже того, если подобный код является дочерним, для каждого дочернего элемента делается вызов в базу данных. В нашей ситуации это недопустимо.

Дополнительные примечания

Пропускная способность на премиум. Мы точно контролируем, какие данные поступают по проводам, поэтому очень важно, чтобы запросы были максимально точными.

Я посмотрел на LinqKit и, хотя кажется, что он может работать для того, что мне нужно, я бы предпочел "из коробки"

В настоящее время общая архитектура не подлежит обсуждению.

1 Ответ

0 голосов
/ 23 сентября 2009

Вы рассматривали явную загрузку объекта Permissions вашим пользователем?

using (var db = new dbContext())
{
  DataLoadOptions dlo = new DataLoadOptions();
  dlo.LoadWith<LinqUser>(lu => lu.Permissions);
  db.LoadOptions = dlo;
  //Execute code, knowing that when you retrieve users, it will also retrieve their permissions.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...