1

I'm coming from a stored procedure and creating the data access layer manually approach. I am trying to understand where I should fit Linq To SQL or entity frameworks into my normal planning. I normally seperate out the business layer from the DAL layer and use a repository inbetween.

It seems that people will either use the generated classes from linq to sql, extend them by using the partial class or do a full seperation and map the generated linq classes to seperate business entities. I am partial to the seperate Business entities. However, this seems to be counterintuitive.

One of my last projects used DDD and the entity framework. When needing to udpate an object it moved the business entity to the repistory layer which when going to the DAL layer would create a context and than requery the object. It would than update the values and resbumit.

I didn't see the large point as the data context wasn't saved and required an extra query to grab the object before updating. Normally I would just do the update(If concurrency wasn't an issue)

So my questions come down to:

  1. Does it make sense to seperate linq to sql generated classes into Business entities?
  2. Should the data context be saved or is that impractical?

Thanks for your time, trying to make sure I understand. I normally like to seperate out as it makes it cleaner to understand even in some smaller porjects.

Aur
  • 191
  • 9

1 Answers1

3

I currently hand roll my own Dto classes and Datacontext instead of using auto-generated code files from Linq to Sql. To give some background of my solution architecture/modeling, I have a "Contract" project, and a "Dal" project. (Also a "Model" project, but I'll try to stay focused here on Dal only). Hand-rolling my own Dtos and Datacontext, makes everything a lot smaller and simpler, I'll give a few examples of how I do that here.

I never return out a Dto object outside of the Dal, in fact I make sure to declare them as internal. The way I return them out is I cast them as an interface (interfaces are located in my "Contract" layer). We'll make a simple "PersonRepository" that implements an "IPersonRetriever and IPersonSaver" interfaces.

Contracts:

public interface IPersonRetriever
{
     IPerson GetPersonById(Guid personId);
}

public interface IPersonSaver
{
     void SavePerson(IPerson person);
}

Dal:

    public class PersonRepository : IPersonSaver, IPersonRetriever
    {
        private string _connectionString;

        public PersonRepository(string connectionString)
        {
            _connectionString = connectionString;
        }

        IPerson IPersonRetriever.GetPersonById(Guid id)
        {
            using (var dc = new PersonDataContext(_connectionString))
            {
                return dc.PersonDtos.FirstOrDefault(p => p.PersonId == id);
            }
        }

        void IPersonSaver.SavePerson(IPerson person)
        {
            using (var dc = new PersonDataContext(_connectionString))
            {
                var personDto = new PersonDto
                {
                    Id = person.Id,
                    FirstName = person.FirstName,
                    Age = person.Age
                };

                dc.PersonDtos.InsertOnSubmit(personDto);
                dc.SubmitChanges();
            }
        }
    }

PersonDataContext:

    internal class PersonDataContext : System.Data.Linq.DataContext
    {
        static MappingSource _mappingSource = new AttributeMappingSource(); // necessary for pre-compiled linq queries in .Net 4.0+

        internal PersonDataContext(string connectionString) : base(connectionString, _mappingSource) { }

        internal Table<PersonDto> PersonDtos { get { return GetTable<PersonDto>(); } }
    }

    [Table(Name = "dbo.Persons")]
    internal class PersonDto : IPerson
    {
        [Column(Name = "PersonIdentityId", IsPrimaryKey = true, IsDbGenerated = false)]
        internal Guid Id { get; set; }

        [Column]
        internal string FirstName { get; set; }

        [Column]
        internal int Age { get; set; }

        #region IPerson implementation

        Guid IPerson.Id { get { return this.Id; } }
        string IPerson.FirstName { get { return this.FirstName; } }
        int IPerson.Age { get { return this.Age; } }

        #endregion
    }

You will need to add the "Column" attribute to all of your Dto properties, but if you notice, if there is a one-to-one correlation between what you want the field to be exposed as on the interface, and the name of the actual table column, you won't need to add any of the Named Parameters. In this example my PersonId in the database is stored as "PersonIdentityId", yet I only want my interface to make the field say "Id".

That's how I do my Dal layer, I believe this layer should be dumb, real dumb. Dumb in the sense that it is only there for CRUD (Create, Retrieve, Update and Delete) operations. All of the business logic would go into my "Model" project, which would consume and utilize the IPersonSaver and IPersonRetriever interfaces.

Hope this helps!

Justin Williams
  • 697
  • 3
  • 12
  • This makes much more sense. The question I have though, how does this utilize the feature of auto generating the classes? It seems that if you want to have a good seperation there is still a good amount of plumbing to do. – Aur Mar 30 '11 at 04:15
  • There really is a lot you'll have to do if you go that route, and that's why I don't use the auto-generated classes myself. Hand-rolling them like this makes things easier to read in my opinion, less code, less bulk, easier to debug, better separation, etc. – Justin Williams Mar 30 '11 at 14:09
  • So primarily use linq to help with abstracting away from stored procedures and making basic crud operations easier. Okay that makes a lot of sense. I've been looking at generics to try and figure out if that can be used to help reduce code repition. – Aur Mar 30 '11 at 23:39
  • Sometimes it is best to have stored procedures handle complicated business rules in the database, and linq has a pretty cool way of caching stored procs, to reduce the over heard. I can post on "compiled linq queries" if that will help you as well. – Justin Williams Apr 01 '11 at 12:50
  • Also, refer here for a good post on Generic Repositories - http://stackoverflow.com/questions/2587965/using-a-generic-repository-pattern-with-fluent-nhibernate – Justin Williams Apr 01 '11 at 12:51