假设我有一个 Animal
类,其中有一些后代源自 Dog
Cat
和 Mouse
public class Animal{}
public class Dog : Animal {}
public class Cat : Animal {}
public class Mouse: Animal {}
现在让我们说这些对象的实体存储在sql数据库中,并且我使用Entity Framework与该数据库进行通信 . 狗,猫和老鼠都存储在不同的表中,但是在代码中它们共享它们派生的同一个父级 .
如果我想让所有动物都满足相同的表达式,我将不得不分别查询每个DbSet,并给它相同的表达式,但参数类型不同,所以cat得到一个cat参数类型,一只狗得到一个像这样的狗参数
var cats = context.Cats.Where(p=>some expression);
var dogs= context.Dogs.Where(p=>some expression);
var mice= context.Mice.Where(p=>some expression);
var animals = new List<Animal>();
animals.AddRange(cats);
animals.AddRange(dogs);
animals.AddRange(mice);
但是,这给我带来了一个问题,因为如果我想添加另一种动物类型,例如 Bird
,我将不得不添加另一行代码来从数据库中获取数据并将其添加到结果集合中 . 这种行为是非常可管理的,我希望它循环遍历从 Animal
派生的类型,并根据提供的源表达式构造一个适当类型的表达式,该表达式作为参数传递给方法作为 Animal
类型表达式 . 像这样的东西:
public List<Animal> GetAnimals(Expression<Func<Animal, bool>> expression)
{
var animalTypes = GetTypesDerivingFrom(typeof(Animal));
List<Animal> animals = new List<Animal>();
foreach(var animalType in animalTypes)
{
var typeTranslatedExpression = GetTypeTranslatedExpression(expression); //i dont know how to do this part
var portionOfAnimals = context.Set(animalType).Where(typeTranslatedExpression).ToList();
animals.AddRange(portionOfAnimals);
}
return animals;
}
有没有办法做到这一点?我想改变表达式参数类型,但我似乎无法在代码时知道正确的参数类型 .
3 回答
我想你应该再次看看你的数据设计 . 在这里你可以解决很多问题 .
您可以使用SQL SERVER VIEW从相关表中使用UNION从不同的表中返回动物 . 添加新动物表需要在视图中添加新的UNION .
您也可以使用存储过程执行相同的操作 . 我会使用一个来获取动物,一个用于保存动物以确保更新正确的表格 .
您可以将所有动物存储在一个表中,并具有一个AnimalType字段,该字段链接到另一个具有ID和AnimalTypeName的简单表 . 然后添加新动物很简单 .
还有实体框架继承与要考虑的表https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-tpt
A可以为您提供更简单的解决方案 . 因为在代码中你有Animal作为父代,你可以对数据库做同样的事情 .
更准确地说,不是为Cats,Dogs等提供不同的表,而是有一个表Animal(因为属性应该是相同的),具有类似“AnimalType”的属性,一个枚举 .
从这里查询将非常简单 .
这不是最好的解决方案,但它是一个可行的解决方案 .
我喜欢利用数据库应用程序的强大功能,而不是假设C#代码(用于检索数据)更有效 . 我也将其视为一种关注点分离 . 在这种情况下,需要一些技巧来设置数据库表(键,其他索引等)以及视图,存储过程等 .
数据库中对象的继承并不罕见 . 你可以采取几种方式 . 哪种方法最好取决于涉及的行数和列数以及您要对数据执行的操作 . 使用您的动物层次结构作为示例: - 在继承中常见的是向上推动泛化和向下推动特化,因此我们首先创建一个“动物”表 . 这有一个整数字段“Id”,这是关键 . 我们还有一个字段“动物名称” .
现在让我们创建一个“Cat”表 . 并且使用“Id”字段但是我们有一个链接到Animal表“Id”的外键“AnimalId” . 我们添加了猫常用的其他字段 . 我们对鼠标和其他动物做同样的事情,就像你开始时一样 .
实现上述目的的另一种方法是对所有动物使用一个表 . 现在您需要更多列来获取更多动物类型 . 这有一种更高的维护方法,可能经常发生变化,但在使用较小的固定范围的对象时效果很好 . 无论类型如何,检索某些公共数据的简单方法是使用计算列,该列从每个对象类型的相关字段输出varchar .
另一种方法是拥有一个具有所有常见属性的动物表 . 第二个表存储属性名称/值对 . 每只动物现在可以拥有任意数量的不同属性,并且从前端代码维护起来很简单 . 这种数据结构具有简单,固定的设计,但仍然支持您目前所需的所有功能 . 但是,此设计对您的有用程度取决于需要对数据进行多少分析 . 在数据库中,您必须将此基于行的数据展平为列以进行某些分析处理 .