Linq to Sql and separation of concerns - am I doing this right?

171 views Asked by At

I have a project that I'm working on that I'm using LINQ to SQL for and I have set up business objects/models to use in my web app. I am looking for some feedback on how I've set all this up to see if it makes sense and if there's anything I should be doing differently.

Here's an example model:

public class User
{
    private MyDataContext _db = new MyDataContext();
    private MyLINQUserClass _user = new MyLINQUserClass();

    public string Name
    {
        get
        {
             return _user.Name;
        }
        set
        {
             _user.Name = value;
        }
    }

    public User(int UserID)
    {
        _user = _db.Where(u => u.UserID == UserID).FirstOrDefault();
        if (_user == null)
        {
            _user = new MyLINQUserClass();
        }
    }

    internal User(MyLINQUserClass user, MyDataContext db)
    {
        _db = db;
        _user = user;
    }

    public void Save()
    {
        _db.SubmitChanges();
    }

    public static User Add(string Name)
    {
        MyDataContext _db = new MyDataContext();
        MyLINQUserClass _user = new MyLINQUserClass();

        _user.Name = Name;
        _db.MyLINQUserTable.InsertOnSubmit(_user);
        _db.SubmitChanges();

        return new User(_user, _db);
    }

    public static IList<User> Get()
    {
        MyDataContext _db = new MyDataContext();
        return _db.MyLINQUserTable.Select(u => new User(u, _db)).ToList();
    }
}

For clarity, I am using this type of model already quite heavily in the project (the above is just an example I threw together for the post on the fly) and it works very well. My question is more of a "learning" question ... I know it works. I'm just not sure if there is something I should be doing differently that is better and if so, why.

Thoughts?

2

There are 2 answers

0
Pantelis Natsiavas On

I suppose there are no right answers to this kind of questions. It is a matter of design, preference and requirements. I will try to show my view...

I always liked the Repository pattern to keep the concerns seperated. I would use a repository of type T to retrieve the T entities (talking generics). These would be the entities participating on my business model. In your case, I would have a UsersRepository class, returning User entities. This Data access layer (DAL) would handle my data access concern.

My business model would use the entities to do its business. In simple CRUD applications, maybe no other objects other the entities returned by my repositories would be needed. In more complicated applications, new classes would be needed, using the repositories of the DAL to retrieve data as entities. This business layer would handle my main business functionality concern (calculations etc).

Then, for display purposes, you could need perhaps another structure. For instance, if you follow the MVC pattern (you could also see the Microsoft article) you would need to create another model to fit your display purposes. This GUI layer following the MVC pattern would handle my graphical display concern.

Hope I helped!

3
Gert Arnold On

This is the so-called Data Access Objects pattern. The User is a DAO to MyLINQUserClass which might be called the domain class.

The DAO pattern is designed for single responsibility: only the DAO "knows" the data layer while the domain class can concentrate on business logic. The domain class is persistence ignorant. So far, so good.

However, there are (at least) three great drawbacks of this pattern:

  • It tends to create lots of boilerplate code
  • It is hard to compose object graphs, because a DAO represents only one row in the database and fetching object graphs easily degenerates into one query per object or collection of child objects.
  • It is hard to work transactionally, because a DAO can't manage a transaction spanning an entire object graph. So you need some overarching layer to handle transactions.

Most ORMs however, have a different persistence-ignorance model than DAO. They have repositories and units of work. In L2S the Table is a basic repository and the context a unit of work. The "domain" classes, like MyLINQUserClass, can be considered persistence-ignorant. (Admitted, they are stuffed with boilerplate code that serves persistence and change tracking, but it is generated and it can practically be ignored). So all responsibilities for CRUD operations have been assigned, and there's no need for other objects carrying these responsibilities.

The way you implement it makes it extra hard to work with object graphs and transactions because each DAO has its own context, so you can't compose LINQ queries involving multiple DAO's in a way that the LINQ is translated into one SQL statement. And doing multiple save operations in one transaction is a challenge.

Conclusion

By using DAO in a linq-to-sql environment you're mixing CRUD responsibilities. You get all the disadvantages of the DAO pattern and can't exploit the power of the repository/UoW pattern to the full. I would strongly recommend to make a choice for one or the other, and I would choose L2S (well, actually I would choose Entity Framework).