【问题标题】:EntityFramework, how to decide which dbSet<TEntity> to use with switch/case?EntityFramework,如何决定哪个 dbSet<TEntity> 与 switch/case 一起使用?
【发布时间】:2017-04-25 11:09:44
【问题描述】:

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

当我有不止一张桌子并且我想决定使用哪一张时,问题就来了。这些表基本相同,因此将使用相同的操作,所以我想为所有表使用一个函数(这样我可以避免重复代码)。但我似乎无法理解如何我可以在运行时更改表格,例如通过开关/案例。

例如:

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

我希望我对我的问题有所了解 :) 希望有人有一个想法,如何解决这个问题,因为我已经与这个问题斗争了很长时间,而我想出的唯一解决方案就是拥有除了“entity.Table”部分之外,在每个开关/案例中使用完全相同的代码进行单独的函数调用。而且必须多次编写同一组代码并不是一个很好的解决方案:(

【问题讨论】:

    标签: c# entity-framework wcf dbset


    【解决方案1】:

    制作泛型函数...

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

    【讨论】:

    • 太棒了!这很简单,而且效果非常好!我对泛型函数不太熟悉,所以我什至没有想到这一点 :) 非常感谢!
    • 很高兴为您提供帮助 :)
    • 我会使用Any 而不是Count
    • 你完全正确@Gert Arnold。我没想到性能问题...
    【解决方案2】:

    您没有这么说,但由于您使用的是实体框架,我假设您的类 databaseEntities 是包含您所有实体的 DbContext DbSet&lt;TEntity&gt; 属性。

    您写道,您的问题是您知道实体的类型(在我的示例 TEntity 中),但您不知道如何获取相应的 DbSet。您的建议是为此使用 switch 语句。

    幸运的是,这不是必需的。 DbContext.Set(Type) 为你做这件事。你提供Type,Dbcontext返回这个类型的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&lt;TEntity&gt;,如果仅在运行时知道 TEntity,请使用 DbContext.Set(Type entityType)`

    Type entityType = ...;
    DbSet mySet = DbContext.Set(entityType);
    

    问题当然是,在编译时你不知道 entityType,因此不知道你可以调用什么函数以及你的 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();
    

    如果你想调用 Teachers 有但 ClassRooms 没有的函数,问题仍然存在。

    这是一种相当罕见的情况,如果您有一个不知道它有什么功能的对象,您应该重新考虑您的设计并考虑创建处理这些对象的函数,而不是给出类型、解码这个对象有什么功能,然后使用它们

    代替:

    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 设计中,您将教师和教室混合在一起的唯一原因,就好像它们是相似的一样,如果您知道您只想调用它们共同的功能。如果是这样的话,回到你知道可以调用哪些常用函数的接口函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-17
      • 2011-10-31
      • 1970-01-01
      • 2021-12-17
      • 1970-01-01
      • 2013-09-16
      • 2019-02-16
      相关资源
      最近更新 更多