Refactoring Linq to Sql

Is there a way to reconfigure linq to sql and take advantage of late evaluation? Is there a way to reuse object initiator code?

I have business objects that are stored in a database and moistened with a separate linq to sql layer.

I would like to be able to reuse code from multiple requests that do the same. The part of the request that I would like to reuse is the part of creating the object. I would also like to continue to use late evaluation (only get the columns I want to get from the database.)

The examples below are very simple and some names have been changed to protect the innocent.

Example 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;
}

      

In Example 1, several things are happening. For this example, I can take advantage of the latest linq score for sql. If you're looking at database queries, the only columns selected are the ones I'm interested in (listed in the hydrateUser file as ID, FirstName, etc.). This is good because I can reuse the code in hydrateUser.

Example 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;
}

      

Sample 2 starts to crash when I want to use hydrateUser and also hydrate the associated object. For example, moistening the list of permissions. Now I have to push away a whole separate function that does extra hydration. this is less desirable if I have many more properties that I initialize.

Sample 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;
}

      

What I would like to do is build a query using code such as example 3. Somehow try to use both functions. And make only one trip to the database. However, this doesn't work.

Sample 4

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

      

Sample 4 is close to what I want but loses the expression evaluation that linq uses to sql for late evaluation. All fields will be returned to the request. Ever worse, if such code is a child, a call to the database is made for each child. This is unacceptable in our situation.

Additional Notes

The bandwidth is very high. We control exactly what data is sent over the wire, so it is very important that requests are as fast as possible.

I've looked at LinqKit and it looks like it might work for what I need, I'd prefer out of the box.

The general architecture is not currently being discussed.

+2


source to share


1 answer


Have you watched the explicit loading of the Permissions object with your user?



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.
}

      

0


source







All Articles