Question

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.

Was it helpful?

Solution

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!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top