Is it possible to create a generic method for addi

2020-07-02 19:25发布

问题:

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>();
}

回答1:

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.