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>();
}
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.
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!
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With