Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to create a generic method for adding items to a entity framework dbset?

I have not worked with Entity Framework or generics before and am having some difficulty reducing my code.

I am parsing a text file to load 10 lookup tables with data that could possibly change nightly. The text files have a heading for the "type" followed by a list of key/value sets. I have this working perfectly, but I would like to refactor the code to clean it up and would like to use generic methods to accomplish this so I can reduce the duplicated code.

I have gotten the parsing down to a generic method, but I have not been able to figure out how to get the entities added to the context in a generic way. I have to loop over a list of the entities for each type and add them to the context:

void Main()
{
    switch (line.ToUpper())
    {
        case "AREA":
        {
            List<Area> areaList = this.GetItems<Area>(file);

            foreach (var element in areaList)
            {
                if (context.Area.Find(element.Id) == null)
                {
                    context.Area.Add(element);
                }
            }

            break;
        }
        case "CATEGORY":
        {
            List<Category> categoryList = this.GetItems<Category>(file);

            foreach (var element in categoryList)
            {
                if (context.Category.Find(element.Id) == null)
                {
                    context.Category.Add(element);
                }
            }

            break;
        }
    }
}

private List<T> GetItems<T>(StreamReader reader) where T : ILookupData, new()
{
    string line;
    List<T> list = new List<T>();            

    while (reader.Peek() == ' ')
    {
        line = reader.ReadLine().TrimStart();
        string[] tokens = line.Split(new string[] { " - " }, 2, StringSplitOptions.None);

        T item = new T();
        item.Id = Convert.ToInt32(tokens[0]);
        item.Description = (string)tokens[1];

        list.Add(item);
    }

    return list;
}

Update: The above works fine, but cannot seem to get the context added.

I have tried a few different things, but seem to keep getting this error when I try to generic up the context:

The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type of method.

The last thing I tried was to add a generic GetDbSet to the context:

public DbSet<T> GetDbSet<T>() where T : class
{
    return this.Set<T>();
}

But I get the same error in my controller adding this code to the GetItems method:

using (MyContext context = new MyContext())
{
    var dbSet = context.GetDbSet<T>();
}
like image 951
AnyKey Avatar asked Jun 05 '13 15:06

AnyKey


People also ask

What is the use of DbSet in Entity Framework?

A DbSet represents the collection of all entities in the context, or that can be queried from the database, of a given type. DbSet objects are created from a DbContext using the DbContext. Set method.

What is meant by DbContext and DbSet?

Intuitively, a DbContext corresponds to your database (or a collection of tables and views in your database) whereas a DbSet corresponds to a table or view in your database. So it makes perfect sense that you will get a combination of both!

How do I get a DbSet?

You can get DbSet from DbContext by Type using the method DbContext. Set(Type entityType) . So if you have the model class name as string you should do some mapping to actual clr type.


1 Answers

I have a generic repository in my current project. This is its add method:

public void Add<T>(T newItem) where T : class
{
    db.Set<T>().Add(newItem);
}

where db is the DbContext object itself. The where T : class fixes that error about reference types. Without it, you could pass any type in as T, including bool or struct, or any value type, which DbSet.Add() can't handle. The where specifies that T must be a class, which is a reference type, and therefore allowed.

like image 51
anaximander Avatar answered Oct 29 '22 06:10

anaximander