views:

725

answers:

7

I like LINQ to SQL, but it seems like the classes it generates are tightly coupled to the database they are stored in, which seems like a Bad Thing.

For example, using ye olde Northwind database, if I create the dbml with the Products table, a Product class is generated. I can use this class in any other tier, which is all well and good, but if I decide I'd rather use plain old ADO.NET (or switch databases), I'll have to recreate the Product class, along with every other "model."

Is there a way around this? Or to create your object models separately, and then have the tables mapped to them? I've played around with the various mapping classes provided, but haven't found a satisfactory answer yet.

+1  A: 

Scott Hanselman did a screen talking about asp.net DynamicData where he used Linq To Sql classes. Although he wasn't addressing the particular issue I think the general concept would still work. His approach was to create a separate partial class that had the same name as the class, Product in your case, that was generated by the dbml. Then you should always have a Product class that exists outside of what LINQ generates and just "extends" what it does.

Marcus King
+3  A: 

My team fought with this issue recently. I really wanted to maintain "persistence ignorance", meaning that domain objects could be created as plain old C# objects, without being forced to inherit from a certain base class or clutter up the class with a bunch of attributes. Like you said, we wanted to be able to modify the persistence layer independently of the business model.

In the end, we decided that LINQ isn't the way to go if you want persistence ignorance. We end up writing way too much mapping code to convert between the LINQ layer and our business layer. When we started writing a bunch of reflection-based code to try and do these mappings automatically we realized we were sliding down the rabbit hole, with little to show for it.

If persistence ignorance is important to you, you might be better served with a full-fledged ORM like NHIbernate.

Seth Petry-Johnson
Nuts. I'm not the biggest fan of NHibernate. Thanks though.
swilliams
+2  A: 

Linq to SQL (or EF) is not about persistence-ignorance. It is about an object view of data.

NHibernate is the persistence-ignorance ORM you may be looking for.

Justice
A: 

Just copy the generated code into your own classes and switch off the code generation. The magic is in the attributes not anything else.

Alternatively you can write your own plain CLR objects without the attributes and use an external XML mapping file to describe the relationship between the objects and the database. More information can be found in the LINQ to SQL documentation on MSDN.

DamienG
Can you be any more specific? Like I said, I've spent hours and hours digging through MSDN to be able to do this.
swilliams
+2  A: 

I've recently achieved this by creating the POCOs myself and manually creating a XML mapping file for the database. It requires a bit of manual work but it gives the desired effect.

Here's a blog post I found useful to get you started.

Garry Shutler
Can you provide anything along the lines of documentation or a blog post or something?
swilliams
Thanks Garry, I'll look into it.
swilliams
+6  A: 

All these answers and no links! Maybe I can help:

The attributes thing that damieng mentioned

The partial class thing that Marcus King mentioned

I have languished through this difficulty a couple of times, what I ended up doing on my last project was using interfaces as the contract that's shared between all of the different projects in the solution, and having the partial classes implement it.

[Table(Name="Products")]
public partial class Product: IProduct { }

And yes, unfortunately it took some reflection magic to make it work for the POCO implementation.

In the end, if you are truly concerned about it, I'd go with NHibernate (I don't really like it either), which does exactly what Garry Shulter seems to be describing.

Hope that helps!

Zachary Yates
Links?! Whoa. Thank you very much! I think I'll probably end up sticking with NHibernate, or maybe SubSonic though. Oh well.
swilliams
+2  A: 

Oh hey, I think I found a solution to this while watching Rob Conery's screencasts on ASP.NET MVC. The trick is to select into an object in your LINQ to SQL query.

public IQueryable<LinqExample.Core.Person> GetAll() {
    var people = from pe in this.db.Persons
                 select new Person {
                     Id = pe.id,
                     FirstName = pe.fname,
                     LastName = pe.lname,
                     Reports = this.GetReports(pe.id)
                 };
    return people;
}

This let's you define a Person class elsewhere in your code. I blogged about it more in depth.

swilliams