【发布时间】:2020-09-15 14:17:33
【问题描述】:
第一
我不能为此使用实体框架,因为这是一个桌面应用程序,其中所有数据库调用首先通过 Web API 端点进行路由。此应用程序的要求是所有流量都是 HTTP 流量。
设置
假设我有一个IEnumerable<BaseItem>,其中BaseItem 是所有模型都继承自的基本模型类。
我们还使用与查询返回的 System.DataTable 的列名和适当数据类型相匹配的动态类和动态属性动态地实例化和填充我们的集合。
这些动态类也继承自 BaseItem,它公开了两个函数:void SetValue(string PropertyName, object Value)object GetValue(string PropertyName)。
问题
我需要能够编写一个 linq 查询,该查询根据查询引用的表中的唯一约束列从集合中动态选择属性。我在一个单独的列表中拥有它,其中字符串值与动态类上的动态属性名称匹配。
我知道解决方案可能是使用表达式树,但我发现的所有示例都使用实际的属性引用,在这种情况下,只能通过 GetValue 和 SetValue 函数访问和设置属性。我很难弄清楚如何实现这一目标。如果我知道要返回的字段,下面是我想要的 linq 查询示例。
var Result = DefaultCollection.Select(x => new { BUSINESS_UNIT = x.GetValue("BUSINESS_UNIT"), FISCAL_YEAR = x.GetValue("FISCAL_YEAR") }).Distinct();
同样,我不能写这个,因为我不知道我需要在选择列表中包含哪些字段,直到运行时我可以引用 UniqueConstraint 列表。
如何使用 Linq 表达式动态实现这一点?
从头到尾的例子
您从System.Data.DataTable 填充了IEnumerable<BaseItem>,假设您运行的查询是SELECT FIRST_NAME, LAST_NAME, EMAIL ADDRESS FROM TABLEA。
IEnumerable 由自动化填充,其中生成一个动态类来表示表中的一行,并将动态属性添加到该类中以表示表中的每一列。
通过 BaseItem string result = item.GetValue("FIRST_NAME") 和 item.SetValue("EMAIL_ADDRESS", "MyEmail@Email.com'); 中的方法访问属性
您还查询了INFORMATION_SCHEMA 以获取对TABLEA 的唯一约束,并将其存储在public class ConstraintModel 对象中,该对象具有代表构成唯一约束的列的public List<string> Columns。在这种情况下,约束中只有一列“EMAIL_ADDRESS”。
如果用户对IEnumerable<BaseItem> 进行更改并且多个项目具有相同的EMAIL_ADDRESS,我们知道返回SQL 的UPDATE 语句将失败。我们要检查是否违反了唯一性约束。
在用户保存时,我们要对内存中的 IEnumerable 对象运行“验证检查”。理想情况下,我们会编写一个 LINQ 查询,该查询本质上是执行 SELECT SUM(1), EMAIL_ADDRESS GROUP BY EMAIL_ADDRESS,如果任何结果的值超过 1 个,我们就知道存在重复。显然上面的语法是 SQL 而不是 Linq,但你明白了。我无法在编译时知道 BaseItem 上需要选择和分组的字段,因此我需要利用 Constraint.Columns 对象并使用它来编写动态 linq 表达式。此外,Dynamic Class 上的属性仅通过它们从 BaseItem 继承的方法公开...GetValue(string PropertyName) 和SetValue(string PropertyName, object Value);
【问题讨论】:
-
您能否举一个
dynamically selects properties from the collection based on the unique constraint columns from the table that the query referenced和I have that in a separate List, where the string values match the dynamic property names on the dynamic class的示例(具体来说,向我们展示允许您“基于约束列动态选择属性”和“带有字符串值的列表”的API) -
到底是什么
-
听起来您应该分两步执行此操作。首先,获取您的动态查询结果,然后创建一个新的动态对象,其中仅包含调用者需要的列。或者将结果集转换为 List
> 或其他内容,并从每个字典中删除调用者未要求的项目。 -
@zaitsman - 我添加了一个从头到尾的例子,希望能澄清。
-
通过 http API 调用访问数据是很多人所做的。这不能成为有人认为这种架构是最佳选择的唯一原因。我只是想知道是什么阻止了您的应用程序(不是您现在可以更改它)使用更标准的方法来检索和更改数据(甚至不使用实体框架)。也许有一个特殊的用例迫使你在运行时发现一切,我只是好奇。
标签: c# linq lambda expression