Adrian Grigore

Updated: Generic base class for LINQ2SQL data layers

In LINQ on February 26, 2009 at 16:23

Hi,

It’s been a while since I posted the first version of my generic base class for LINQ2SQL data layers. The idea behind this class was to provide a quick and simple way to implement a repository with LINQ2SQL and therefore also a solid foundation for implementing your n-tier architecture data layer. If you missed the article, you can read more about the base class here.

The version I previously posted has worked fine for me, but it was still lacking a way to retrieve the ID and version attributes of saved entities. Due to a typo, it also did not work with entities that have more than one unique identity column. Thanks to Mike and Fabrizio for pointing out these limitations!

Version 0.2 available here fixes both of these issues:

Download RepositoryBase Demo Website

Download RepositoryBase Source Code Only

Advertisements
  1. Holy smack, you got it. Nice.

  2. I from kunshan of china.Thanks for your greate job. how a graceful solution for n-tier architecture data layer by LINQ2SQL .Certainly it is. I don’t think I’ve ever seen a better design.

  3. Hi,
    I have just got hold of your code and I have had to fiddle around with it as we do not have int ID fields for our tables but have Guids (please don’t ask, I didn’t design it and no we don’t need keys that are unique across the database…). I have only flicked thorugh it but wondered if you could quickly tell me if this is likely to cause problems. Especially with saving recursively and the is new method.
    Hope that makes sense.
    Thanks for the great artcile
    Rob

  4. Hi Rob,

    Thanks for your interest in my article.

    I must admit I have never used GUIDs, so I can only guess. I think you should be able to alter RepositoryBase to fit your needs. A few points that come to my mind:

    * As you correctly observed, the Save() / SaveRecursively() methods use the ID attribute to find out whether the business entity is new to the database. Basically you should be able to do this in a similar manner with a GUID, as long as newly constructed entities always have one well-defined GUID that never occurs in entities that have been loaded from the database.

    * Repositorybase finds the ID property of each business entity automatically (even if it is not called “ID”) by reflecting on the respective table ( see lines 196, 331 and 385 of RepositoryBase). You’ll need to use an alternate mechanism for finding the GUID property instead. The simplest option would be to call your GUID properties “GUID” or something similar in all business entity types and to hardcode that property name in RepositoryBase. This will also remove a bit of reflection.

    * You will also have to alter the Load() and Delete methods in RepositoryBase as well as GetIDSelector() from the business entities to use GUIDs, but that should be trivial.

    Please let me know if it worked. And if you have a blog, a pingback is always appreciated 😉

    Good luck,

    Adrian

  5. Hi Adrian,
    Thanks for a a quick a thorough response!

    Looks like I may have more problems as there are quite a lot of many to many relationships which have multiple value keys that vary. I will try and come up with a nice solution using a repository, though looks like I may have to try and do it in my own time and use a dirty solution for the deadline I am on :-(. If I come up with anything I’ll try and document it somewhere and let you know.

    Thanks again
    Rob

  6. Does this work with composite primary keys? I talking about a link table like OrderDetails that might have the OrderID and ProductID as the primary key.

    Thanks
    Gaz

  7. Gary,

    This does not work out of the box with composite primary keys. However, it should be quite easy to adapt it accordingly.

    The Load(int ID) and Delete(int ID) and DeleteRecursively(int ID) functions will have to be changed to accept two parameters, but that’s trivial since Load is just filtering the respective table and the real work in Delete is done in Internal functions that take in an entity (not an ID) anyway. The rest might work with composite primary keys without further changes, although I have not tried it yet.

  8. Adrian,

    Where in the updated BaseRepository are the child IDs set for the SaveRecursively functionality?

    Thanks,
    Chris

  9. @Chris: This should be done automatically by the LINQ2SQL data context. Setting the ID and version attributes explicitly is only necessary for the root entity, because this is the only entity that is being detached from any previous context by serializing it. For some obscure reason explicitly detaching the child entities does not seem to be necessary, so the RepositoryBase does not do it.

  10. FYI, when I try to run the out-of-the-box sample, I get the following RTE on start “ObjectDataSource ‘BillsListObjectDataSource’ could not find a non-generic method ‘LoadAll’ that has parameters: ID”. This is, if I recall correctly, an issue with the ObjectDataSource in DotNet, I think and it is fixable BUT I thought you should know anyway. Thank you regardless because the code is quite underneath, IMHO. Thank you. — Mark Kamoski

  11. FYI, I tweaked your sample’s UI a bit to get it working. (The backend code seems fine.) I had to remove the selectparameters for bills BillsListObjectDataSource and BillingItemsDataSource and change both to selectmethod=”LoadAll” because they underlying objects did not seem to have “select where some_id = some_selected_id” (or at least I could not get it to work). If you want the tweaked sample, then please just send a request to mkamoski@yahoo.com because I do not see a way to email it to you directly. Anyway, this seems fine so far. I appreciate the help. Thank you. — Mark Kamoski

  12. @Mark: See the e-mails I have sent you regarding this.

  13. Hi Adrian,

    Attempting to save an item after edit gives this error

    “An entity can only be attached as modified without original state if it declares a version member or does not have an update check policy.”

    How can one get around this, given that the detaching and serialising would have gotten rid of the original state.

    Thanks.

  14. @Gboyega S : Sounds like your table does not have a version column. See the demo website for an example of a table with version information.

  15. Hi, I’m working on a new project and using LINQ. New to it. Why do I need to use a base class? as I have it now, I have a DBML. I drag my tables and my stored procs to it and call the stored procs or use tables (entities). Not sure if this is a correct design…

  16. Hi Adrian,
    I am trying to implement your repositorybase in an asp.net mvc project.
    My database table (sql2005, not express) has a version column. I created the table using a sql script and used rowversion instead of timestamp as datatype.
    Still the output window in visual studio keeps telling me that there is no version on the linq entity.
    Inserting a new row is possible, updating an existing row not.

    What is going wrong here?
    Many thanks in advance.
    roger

  17. Oops, forgot to include mailaddress.

  18. Roger,

    Where does the error message come from? Is it Linq or my RepositoryBase class?

  19. Hi Adrian,

    I just send you an email with a detailed explanation.
    In short the error is:
    Warning: “StaticText” entity type does not have a version property. You might want to add a version column to speed up Saving and Deleting of “StaticText” entities.

    The column is in the table.

  20. Hi Adrian,

    I would like to implement your repositorybase in a multithreaded Desktop application.
    Do you think it is possible to implement it ?

    Is there any seggestions ?

    Thanks

  21. @Kayralla: It’s certainly possible. The repository’s implementation does not depend on the UI plattform you are using. You can use it with ASP.NET just as well as with a desktop UI.

  22. thanks for the fast replay.

    One of the tables in my database contain 4 primary keys. (Guid, int, int, int)
    How can I implement that in :
    protected abstract Expression<Func> GetIDSelector(TIDType ID);

    thanks again

  23. Hi Adrian

    It is done.
    thanks for this nice article

    Khayralla

  24. I can’t get the demo to work. I load the website and receive the below error.

    ObjectDataSource ‘BillsListObjectDataSource’ could not find a non-generic method ‘LoadAll’ that has parameters: ID.

  25. Hey,

    I’ve tried implementing your repository with an manually mapped class, well actually multiple classes.
    The Load and the Save function seem to work fine, no problem at all.

    Only the update function is giving me problems. It is giving me errors on the attach function. I know this is not related to the repository but to the datacontext but have you ever seen this before with an other user?
    I must say i have removed the HasVersion(Property) function.

    TIA

  26. Hi NoiK,

    Sorry, but I have not been using disconnected linq for about 1 year now (thanks to coding in ASP.NET MVC), so am not fully accustomed with the code anymore. Without knowing any more details, I’m afraid I can’t you help here…

  27. You mean you’re missing details from my side? Or because you were not in L2S for a while?

    Thanks anyway 🙂

  28. Both. I would at least need to know the specific error message. But even with that, I am not sure if I could point you in the right direction without debugging your (and my) code. As I said, nowadays I am not using disconnected Linq anymore.

Comments are closed.

%d bloggers like this: