Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity base class design in C# for repository model

I am trying to become a good programming citizen through learning more about Dependency Injection / IoC and other best-practices methods. For this I have a project where I am trying to make the right choices and design everything in the "proper" way, whatever that might mean. Ninject, Moq and ASP.NET MVC help with testability and getting the app "out the door".

However, I have a question about how to design an entity base class for the objects that my application consists of. I have a simple class library which the web app is built on top of. This library exposes a IRepository interface, and the default implementation (the one that the app uses) uses Linq-to-SQL under the covers (the DataContext etc. is not exposed to the web app) and simply contains ways to fetch these entities. The repository basically looks like this (simplified):

public interface IRepository
{
    IEnumerable<T> FindAll<T>() where T : Entity
    T Get<T>(int id) where T : Entity
}

The default implementation uses the GetTable() method on the DataContext to provide the correct data.

However, this requires that the base class "Entity" has some features. It is easy enough to get my objects to inherit from it by creating a partial class of the same name as the mapped object that Linq-to-SQL gives me, but what is the "correct" way to do this?

For instance, the interface above has a function for getting an Entity by it's id - all the different kinds of classes that derives from entity does indeed have an "id" field of type int (mapped from the primary key of their respective tables), but how can I specify this in a way that lets me implement IRepository like this?

public class ConcreteRepository : IRepository
{
    private SomeDataContext db = new SomeDataContext();

    public IEnumerable<T> FindAll<T>() where T : Entity
    {
        return db.GetTable<T>().ToList();
    }

    public T Get(int id) where T : Entity
    {
        return db.GetTable<T>().Where(ent => ent.id == id).FirstOrDefault();
    }
}

I am doing this from memory on a compiler-less PC so forgive any errors, you hopefully get my intention.

The trick here is of course that for this to compile, it has to be known for sure that Entity promises that everyone that derives from it has an id field.

And I can make an abstract field, or a normal field that is "hidden" by the id field that Linq-to-SQL sticks in the generated classes.

But this all feels kind of like a cheat, and even gives compiler warnings.

Should "Entity" really be "IEntity" (an interface instead), and I should try to make the id field be defined in a way that Linq-to-SQL will fulfill? This would also make it easy to specify other interfaces that Entity-implementors need to implement.

Or should "Entity" be an abstract base class with an abstract id field, and should it also implement needed interfaces in an abstract way for others to override?

I don't know C# well enough to see an elegant solution to this, so I would love to hear from more experienced system designers with some base class experience weigh in on this.

Thanks!

EDIT April 10th:

I see I left out something important here. My IRepository has two concrete implementations - one that is the "real" one using LINQ to SQL, the other one is a InMemoryRepository that just uses a List for now, which is used for unit testing etc.

The two solutions added will both work for one of these situations, not for the other. So if possible, I would need a way to define that everything that inherits from Entity will have the "id" property, and that this will work with the LINQ to SQL DataContext without "cheating".

like image 479
Rune Jacobsen Avatar asked Apr 09 '09 11:04

Rune Jacobsen


People also ask

What is an entity class?

Entity classes are the fundamental building blocks of systems that are developed with Cúram. They correspond to database tables. The Cúram generator supports automatic code generation for entity classes. Entity classes have a stereotype of entity. An entity class is essentially an object wrapper for a database table.

What is an entity class C#?

An “entity class” is a class most often used to represent the values from a single row of a database table. You need to create a property in C# or Visual Basic for each column defined in your table to build an entity class.

How do I create a model class in EDMX?

edmx, and click the Add button. Clicking the Add button launches the Data Model Wizard. In the Choose Model Contents step, choose the Generate from a database option and click the Next button (see Figure 2). In the Choose Your Data Connection step, select the MoviesDB.


1 Answers

If you use "Id" as a primary keys in all tables so all the generated classes would have a public property like:

public int Id {}

Then create an interface

public interface IIdentifiable {
    Id { get; }
}

Then the most tedious part :(, for all entities create a partial class and make it implement IIdentifiable.

The repository class can then look like:

public class Repository<T> : IRepository where T : IIdentifiable {
}

And the following code will work:

db.GetTable<T>().SingleOrDefault(ent => ent.Id.Equals(id));

If you do not use the generated classes and make your own, is even simpler from this point of view.

EDIT:
Instead of ent => ent.Id == id use ent => ent.Id.Equals(id). Just tested, the following is a complete working example:

public interface IIdentifiable {
    int Id { get; }
}

public class Repository<T> where T : class, IIdentifiable {
    TestDataContext dataContext = new TestDataContext();

    public T GetById(int id) {
        T t = dataContext.GetTable<T>().SingleOrDefault(elem => elem.Id.Equals(id));
        return t;
    }
}

public partial class Item : IIdentifiable {
}

class Program {
    static void Main(string[] args) {
        Repository<Item> itemRepository = new Repository<Item>();

        Item item = itemRepository.GetById(1);

        Console.WriteLine(item.Text);
    }
}
like image 152
Aleris Avatar answered Oct 21 '22 04:10

Aleris