5

I have two types of entities: an employee entity and an office entity, with a one to many relationship between the two such that there are many employees for one office. For EF, a DbSet is created in the context file for each entity:

public DbSet<Office> Offices { get; set; }
public DbSet<Employee> Employees { get; set; }

An EF tutorial that I did had me do my CRUD methods for a specific entity. For example, the method below creates an office and adds it to the office DbSet (ignore the MVC stuff -- I am not doing that anymore):

public ActionResult Create([Bind(Include = "Address,BusinessName")] Office office)
    {
        try
        {

            if (ModelState.IsValid)
            {
                db.Offices.Add(office);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

        }
        catch (DataException /* dex */)
        {
            //Log the error (uncomment dex variable name and add a line here to write a log.
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
        }
        return View(office);
    }

Basically the two things I want to emphasize is that an Office object is passed into the method, and that the office is added to the Office DbSet by explicitly writing db.Offices:

db.Offices.Add(office);

However, I need to write a method in which a generic entity object can be passed in, and I can add this to its correct DbSet. The rough idea for the method I have is something like this (I have ignored all the MVC stuff):

public void Create(object entityToCreate)
{
    db.CorrespondingEntityType.Add(entityToCreate);
    db.SaveChanges();
}

So let's say I have an Employee object. I can pass this Employee into the Create method and it can see that this is an Employee, and so it would add it to the Employees DbSet. I don't know if EF supports this though. An alternative would be to make a switch statement and that way depending on the type of the entity being passed in, I could directly call which DbSet to add the entity to. But I want to avoid that because I will be working with a lot more entities than just these two. Also I will be having to do similar things for the other CRUD methods.

I saw this documentation from msdn about the ObjectSet.AddObject Method, and it seems like it should be useful, but I'm not sure how it works.

Drew
  • 1,277
  • 3
  • 21
  • 39

2 Answers2

8

You might consider a generic class like so:

 public class GenericRepository<T> where T : class
 {
    internal YourConext context;
    internal DbSet<T> dbSet;

    public GenericRepository(YourContext context)
    {
        this.context = context;
        this.dbSet = context.Set<T>();
    }

    public virtual void Insert(T entity)
    {
        dbSet.Add(entity);
        context.SaveChanges();
    }

  }
live2
  • 3,771
  • 2
  • 37
  • 46
ajliptak
  • 429
  • 3
  • 7
  • Interesting. I thought about a generic class but I'm new to using C# and I haven't used templates/generics much in the past so I wasn't sure if this was the path I wanted to go down. Thanks for the help, I'll look into generics more and try out what you're saying. – Drew Jun 05 '15 at 21:03
  • This shifts the problem to: how do I decide which typed repo should I create? Nevertheless, using `context.Set()` is the key, but it shouldn't be used in a generic type. – Gert Arnold Jun 05 '15 at 21:04
  • Gert, could you elaborate on the problem you're suggesting with your question? I'm new to databases and everything so I'm not sure what you mean. Thanks – Drew Jun 05 '15 at 21:21
  • At some point you need to specify the Type of object you want to save. There really isn't a way around that. I suppose you could use reflection to determine the type and instantiate the generic repository using Activator.CreateInstance() but that's way more overhead than a simple switch. – ajliptak Jun 05 '15 at 21:25
5

If you have an extension method like...

public static void Create<T>(this DbContext db, T entityToCreate)
    where T : class
{
    db.Set<T>().Add(entityToCreate);
    db.SaveChanges();
}

...C# will do the type inference for you. You can just call it as...

db.Create(office);

...without ever having to worry about the type. Of course you should enter a known entity type.

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291