views:

1597

answers:

7

Hi everyone.

Clearly separation of concerns is a desirable trait in our code and the first obvious step most people take is to separate data access from presentation. In my situation, LINQ To SQL is being used within data access objects for the data access.

My question is, where should the use of the entity object stop? To clarify, I could pass the entity objects up to the domain layer but I feel as though an entity object is more than just a data object - it's like passing a bit of the DAL up to the next layer too.

Let's say I have a UserDAL class, should it expose an entity User object to the domain when a method GetByID() is called, or should it spit out a plain data object purely for storing the data and nothing more? (seems like wasteful duplication in this case)

What have you guys done in this same situation? Is there an alternative method to this?

Hope that wasn't too vague.

Thanks a lot,

Martin.

+4  A: 

I return IQueryable of POCOs from my DAL (which uses LINQ2SQL), so no Linq entity object ever leaves the DAL. These POCOs are returned to the service and UI layers, and are also used to pass data back into the DAL for processing. Linq handles this very well:

 IQueryable<MyObjects.Product> products = from p in linqDataContext.Products 
                                          select new MyObjects.Product //POCO
                                          {
                                              ProductID = p.ProductID
                                          };
 return products;
Codewerks
+1  A: 

I personally don't like my entities to spread accross the layers. My DAL return POCO's (of course, it often means extra work, but I found this much cleaner - maybe that this will be simpler in the next .NET version ;-)).

The question is not so simple and there are lots of different thinking of the subject (I keep on asking myself the same question that you are).

Maybe you could take a look at the MVC Storefront sample app : I like the essence of the concept (the mapping that occurs in the data layer especially).

Hope this helps.

cik
+1  A: 

There is a similar post here, however, I see your question is more about what you should do, rather than how you should do it.

In small applications I find a second POCO implementation to be wasteful, in larger applications (particularly those that implement web services) the POCO object (usually a Data Transfer Object) is useful.

If your app falls into the later case, you may want to look at ADO.Net Data Services.

Hope that helps!

Zachary Yates
+3  A: 

For most projects, we use LINQ to SQL entities as our business objects.

The LINQ to SQL designer allows you to control the accessibility of the classes and properties that it generates, so you can restrict access to anything that would allow the consumer to violate the business rules and provide suitable public alternatives (that respect the business rules) in partial classes.

There's even an article on implementing your business logic this way on the MSDN.

This saves you from writing a lot of tedious boilerplate code and you can even make your entities serialisable if you want to return them from a web service.

Whether or not you create a separate layer for the business logic really depends on the size of your project (with larger projects typically having greater variation between the business logic and data access layers).

I believe LINQ to Entities attempts to provide a one-stop solution to this conundrum by maintaining two separate models (a conceptual schema for your business logic and a storage schema for your data access).

Richard Poole
A: 

I have actually struggled with this, as well. Using plain vanilla LINQ to SQL, I quickly abandoned the DBML tooling, because it bound the entities to tightly to the DAL. I was striving for a higher level of persistence ignorance, although Microsoft didn't make it very easy.

What I ended up doing was hand-writing the persistence ignorance layer, by having the DAL inherit from my POCOs. The inherited objects exposed the same properties of the POCO it is inheriting from, so while inside the persistence ignorance layer, I could use attributes to map to the objects. The called then could cast the inherited object back to its base type, or have the DAL do that for them. I preferred the latter case, because it lessened the amount of casting that needed to be done. Granted, this was a primarily read-only implementation, so I would have to revisit it for more complex update scenarios.

The amount of manual coding for this is rather large, because I also have to manually maintain (after coding, to begin with) the context and provider for each data source, on top of the object inheritance and mappings. If this project was being deprecated, I would definitely move to a more robust solution.

Looking forward to the Entity Framework, persistence ignorance is a commonly requested feature according to the design blogs for the EF team. In the meantime, if you decide to go the EF route, you could always look at a pre-rolled persistence ignorance tool, like the EFPocoAdapter project on MSDN, to help.

joseph.ferris
A: 

I use a custom LinqToSQL generator, built upon one I found in the Internet, in place of the default MSLinqToSQLGenerator. To make my upper layers independent of such Linq objects, I create interfaces to represent each one of them and then use such interfaces in these layers. Example:


public interface IConcept {
    long Code { get; set; }
    string Name { get; set; }
    bool IsDefault { get; set; }
}

public partial class Concept : IConcept { }

[Table(Name="dbo.Concepts")]
public partial class Concept
{
    private long _Code;
    private string _Name;
    private bool _IsDefault;
    partial void OnCreated();
    public Concept() { OnCreated(); }
    [Column(Storage="_Code", DbType="BigInt NOT NULL IDENTITY", IsPrimaryKey=true)]
    public long Code
    {
             //***
    }
    [Column(Storage="_Name", DbType="VarChar(50) NOT NULL")]
    public string Name
    {
             //***
    }
    [Column(Storage="_IsDefault", DbType="Bit NOT NULL")]
    public bool IsDefault
    {
             //***
    }
}

Of course there is much more than this, but that's the idea.

Rafael Romão
A: 

Please keep in mind that Linq to SQL is not a forward looking technology. It was released, it's fun to play with, but Microsoft is not taking it anywhere. I have a feeling it won't be supported forever either. Take a look at the Entity Framework (EF) by Microsoft which incorporates some of the Linq to SQL goodness.

Nick