EntityFramework,如何决定使用哪个dbSet<TEntity>和switch/case?
EntityFramework, how to decide which dbSet<TEntity> to use with switch/case?
我是 EntityFramework 和 WCF 的初学者,所以我还不知道一切是如何工作的,所以我会尽力解释我的情况..
我有 WCF 服务,它使用 EntityFramework 的数据库,我已经设法让它正常工作,例如:
using (var entities = new databaseEntities())
{
// Check if there is 0 rows, then just add the new row.
int count = entities.Table1.Where(i => i.Name == name).Count();
if (count < 1)
{
var newEntry = new Table1
{
Name = name,
InsertDate = DateTime.Now,
CreatedBy = createdBy,
Comment = comment,
Active = true
};
entities.Table1.Add(newEntry);
entities.SaveChanges();
}
}
当我有多个 table 并且我想决定使用哪一个时,问题就来了。 tables 基本相同,因此会使用相同的操作,所以我想对所有这些使用一个函数(这样我可以避免重复代码)。但我似乎无法理解 如何 我可以在运行时更改 table 例如通过 switch/case.
例如:
// A function that gets the type of the table I want to access
void WriteToSomeTable(int type)
{
switch (type)
{
case 0:
//The table to update is Table1
break;
case 1:
//The table to update is Table2
break;
}
}
如果我想获得具有给定名称的所有条目的计数
int count = entities.Table1.Where(i => i.Name == "somename").Count();
如何在运行时确定 "entities.Table1"?
我可以制作变量:
System.Data.Entity.DbSet<Table1> firstTable = entities.Table1;
System.Data.Entity.DbSet<Table2> secondTable = entities.Table2;
所以我认为我可以用一个列表来设置一个 int 索引;使用 switch/case 设置为不同的值,然后使用
int count = list[index].Where(i => i.Name == "somename").Count();
但我无法将它们添加到列表中,因为它们是不同的类型
// entity.Table1 is
System.Data.Entity.DbSet<Table1>
// and entity.Table2 is
System.Data.Entity.DbSet<Table2>
ArrayList 也不会削减它,因为如果我尝试使用 ArrayList 中的对象,则没有“.Where”函数。
我也尝试过只使用 System.Data.Entity.Dbset,但要使用“.Where”函数,我需要使用 .Cast() 函数,但我无法将所需的 "TEntity" 存储到一个变量(或者我可以吗?)。例如:
System.Data.Entity.DbSet firstTable = entity.Table1
Type t = firstTable.GetType();
int count = firstTable.Cast<t>().Where(i => i.Name == "somename").Count();//doesn't work
//This, however works:
int count = firstTable.Cast<Table1>().Where(i => i.Name == "somename").Count();
我希望我对我的问题有所了解 :) 希望有人知道如何解决这个问题,因为我已经为此奋斗了很长时间,而我想出的唯一解决方案是在每个 switch/case 中使用完全相同的代码进行单独的函数调用,"entity.Table" 部分除外。而且必须多次编写同一组代码并不是一个很好的解决方案:(
你没有这么说,但由于你正在使用 Entity Framework,我假设你的 class databaseEntities
是包含你所有实体的 DbContext
作为 DbSet<TEntity>
属性。
你写道,你的问题是你知道实体的类型(在我的示例 TEntity 中),但你不知道如何获得相应的 DbSet。您的建议是为此使用 switch 语句。
幸运的是,这不是必需的。 DbContext.Set(Type) 为您做这件事。您提供类型,Dbcontext returns 这种类型的 DbSet。
public class SchoolContext : DbContext
{
public DbSet<Student> Students {get; set;}
public DbSet<Teacher> Teachers {get; set;}
public DbSet<ClassRoom> ClassRooms {get; set;}
...
}
如果您在编译时已经知道类型,请使用 DbContext.Set<TEntity>
,如果 TEntity 仅在运行时已知,请使用 DbContext.Set(Type entityType)`
Type entityType = ...;
DbSet mySet = DbContext.Set(entityType);
问题当然是,在编译时你不知道实体类型,因此不知道你可以调用什么函数以及你的实体类型有什么属性。
如果您确定您的实体具有某些属性,例如您的示例 属性 Name
,请考虑从一个通用接口派生所有实体。像这样:
interface ICommonSchoolProperties
{
public int Id {get;} // primary key
public string Name {get;}
}
public class Teacher : ICommonSchoolProperties {...}
public class ClassRoom : ICommonSchoolProperties {...}
etc.
现在您可以确定,每当您向 SchoolContext
询问任何类型的物品时,您可以确定您得到的物品至少有一个 Id
和一个 Name
.因此您可以执行以下操作:
Type entityType = ...
IEnumerable<ICommonSchoolProperties> schoolItems = mySchoolContext
.Set(entityType)
.Cast<ICommonSchoolProperties>)();
并且您可以调用您确定您的 SchoolProperty 具有的功能。
var nrOfItems = schoolItems
.Where(schoolItem => schoolItem.Name = ...)
.Count();
var allKnownNames = schoolItems
.Select(schoolItem => schoolItem.Name)
.Distinct();
如果您想调用教师有但课堂没有的功能,问题仍然存在。
这是一种相当罕见的情况,如果您有一个您不知道它有哪些功能的对象,您应该重新考虑您的设计并考虑创建处理这些对象的函数,而不是给出类型, 解码这个对象有什么功能然后使用它们
而不是:
private void WriteToSomeTable(Type type)
{
if type is a teacher
call teacher functions
else if type is classroom
call classroomfunctions
else
DoSomeThingcommon(...)
}
考虑:
public void WriteTeacherTable()
{
call teacher functions();
DoSomethingCommon();
}
private void WriteClassRoomtable()
{
call classroom functions;
DoSomethingCommon();
}
请注意,行数几乎没有增加。
在你的程序中的某个地方,你知道你正在与教师而不是课堂打交道。在适当的 OO 设计中,您将教师和教室混合在一起,就好像它们是相似的东西的唯一原因是,如果您知道您只想调用它们共有的功能。如果是这样,回到接口函数,你知道你可以调用哪些常用函数。
创建泛型函数...
public void MyAddFunction<T>(T newItem, databaseEntities db,
Expression<Func<T, bool>> predicate) where T : class
{
var table = db.Set<T>();
int count = table.Count(predicate);
if(count < 1)
{
table.Add(newItem);
}
db.SaveChanges();
}
并根据您的情况调用您的函数(例如您要添加 table1)
using(var entities = new databaseEntities())
{
MyAddFunction<Table1>(new Table1(), entities , x => x.Name == "name");
}
我是 EntityFramework 和 WCF 的初学者,所以我还不知道一切是如何工作的,所以我会尽力解释我的情况..
我有 WCF 服务,它使用 EntityFramework 的数据库,我已经设法让它正常工作,例如:
using (var entities = new databaseEntities())
{
// Check if there is 0 rows, then just add the new row.
int count = entities.Table1.Where(i => i.Name == name).Count();
if (count < 1)
{
var newEntry = new Table1
{
Name = name,
InsertDate = DateTime.Now,
CreatedBy = createdBy,
Comment = comment,
Active = true
};
entities.Table1.Add(newEntry);
entities.SaveChanges();
}
}
当我有多个 table 并且我想决定使用哪一个时,问题就来了。 tables 基本相同,因此会使用相同的操作,所以我想对所有这些使用一个函数(这样我可以避免重复代码)。但我似乎无法理解 如何 我可以在运行时更改 table 例如通过 switch/case.
例如:
// A function that gets the type of the table I want to access
void WriteToSomeTable(int type)
{
switch (type)
{
case 0:
//The table to update is Table1
break;
case 1:
//The table to update is Table2
break;
}
}
如果我想获得具有给定名称的所有条目的计数
int count = entities.Table1.Where(i => i.Name == "somename").Count();
如何在运行时确定 "entities.Table1"? 我可以制作变量:
System.Data.Entity.DbSet<Table1> firstTable = entities.Table1;
System.Data.Entity.DbSet<Table2> secondTable = entities.Table2;
所以我认为我可以用一个列表来设置一个 int 索引;使用 switch/case 设置为不同的值,然后使用
int count = list[index].Where(i => i.Name == "somename").Count();
但我无法将它们添加到列表中,因为它们是不同的类型
// entity.Table1 is
System.Data.Entity.DbSet<Table1>
// and entity.Table2 is
System.Data.Entity.DbSet<Table2>
ArrayList 也不会削减它,因为如果我尝试使用 ArrayList 中的对象,则没有“.Where”函数。
我也尝试过只使用 System.Data.Entity.Dbset,但要使用“.Where”函数,我需要使用 .Cast() 函数,但我无法将所需的 "TEntity" 存储到一个变量(或者我可以吗?)。例如:
System.Data.Entity.DbSet firstTable = entity.Table1
Type t = firstTable.GetType();
int count = firstTable.Cast<t>().Where(i => i.Name == "somename").Count();//doesn't work
//This, however works:
int count = firstTable.Cast<Table1>().Where(i => i.Name == "somename").Count();
我希望我对我的问题有所了解 :) 希望有人知道如何解决这个问题,因为我已经为此奋斗了很长时间,而我想出的唯一解决方案是在每个 switch/case 中使用完全相同的代码进行单独的函数调用,"entity.Table" 部分除外。而且必须多次编写同一组代码并不是一个很好的解决方案:(
你没有这么说,但由于你正在使用 Entity Framework,我假设你的 class databaseEntities
是包含你所有实体的 DbContext
作为 DbSet<TEntity>
属性。
你写道,你的问题是你知道实体的类型(在我的示例 TEntity 中),但你不知道如何获得相应的 DbSet。您的建议是为此使用 switch 语句。
幸运的是,这不是必需的。 DbContext.Set(Type) 为您做这件事。您提供类型,Dbcontext returns 这种类型的 DbSet。
public class SchoolContext : DbContext
{
public DbSet<Student> Students {get; set;}
public DbSet<Teacher> Teachers {get; set;}
public DbSet<ClassRoom> ClassRooms {get; set;}
...
}
如果您在编译时已经知道类型,请使用 DbContext.Set<TEntity>
,如果 TEntity 仅在运行时已知,请使用 DbContext.Set(Type entityType)`
Type entityType = ...;
DbSet mySet = DbContext.Set(entityType);
问题当然是,在编译时你不知道实体类型,因此不知道你可以调用什么函数以及你的实体类型有什么属性。
如果您确定您的实体具有某些属性,例如您的示例 属性 Name
,请考虑从一个通用接口派生所有实体。像这样:
interface ICommonSchoolProperties
{
public int Id {get;} // primary key
public string Name {get;}
}
public class Teacher : ICommonSchoolProperties {...}
public class ClassRoom : ICommonSchoolProperties {...}
etc.
现在您可以确定,每当您向 SchoolContext
询问任何类型的物品时,您可以确定您得到的物品至少有一个 Id
和一个 Name
.因此您可以执行以下操作:
Type entityType = ...
IEnumerable<ICommonSchoolProperties> schoolItems = mySchoolContext
.Set(entityType)
.Cast<ICommonSchoolProperties>)();
并且您可以调用您确定您的 SchoolProperty 具有的功能。
var nrOfItems = schoolItems
.Where(schoolItem => schoolItem.Name = ...)
.Count();
var allKnownNames = schoolItems
.Select(schoolItem => schoolItem.Name)
.Distinct();
如果您想调用教师有但课堂没有的功能,问题仍然存在。
这是一种相当罕见的情况,如果您有一个您不知道它有哪些功能的对象,您应该重新考虑您的设计并考虑创建处理这些对象的函数,而不是给出类型, 解码这个对象有什么功能然后使用它们
而不是:
private void WriteToSomeTable(Type type)
{
if type is a teacher
call teacher functions
else if type is classroom
call classroomfunctions
else
DoSomeThingcommon(...)
}
考虑:
public void WriteTeacherTable()
{
call teacher functions();
DoSomethingCommon();
}
private void WriteClassRoomtable()
{
call classroom functions;
DoSomethingCommon();
}
请注意,行数几乎没有增加。
在你的程序中的某个地方,你知道你正在与教师而不是课堂打交道。在适当的 OO 设计中,您将教师和教室混合在一起,就好像它们是相似的东西的唯一原因是,如果您知道您只想调用它们共有的功能。如果是这样,回到接口函数,你知道你可以调用哪些常用函数。
创建泛型函数...
public void MyAddFunction<T>(T newItem, databaseEntities db,
Expression<Func<T, bool>> predicate) where T : class
{
var table = db.Set<T>();
int count = table.Count(predicate);
if(count < 1)
{
table.Add(newItem);
}
db.SaveChanges();
}
并根据您的情况调用您的函数(例如您要添加 table1)
using(var entities = new databaseEntities())
{
MyAddFunction<Table1>(new Table1(), entities , x => x.Name == "name");
}