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