First
I cannot use Entity Framework for this because this is a Desktop application in which all database calls are first routed through a Web API End Point. A requirement of this application is that all traffic is HTTP traffic.
Setup
Lets say I have an IEnumerable<BaseItem> where the BaseItem is a base model class that all models inherit from.
We also dynamically instantiate and populate our collection with a dynamic class and dynamic properties that match the column names and appropriate data types of the System.DataTable that is returned from the query.
These dynamic classes also inherit from BaseItem which exposes two functions:
void SetValue(string PropertyName, object Value)
object GetValue(string PropertyName).
Issue
I need to be able to write a linq query that 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.
I know the solution is probably to use an Expression Tree, but all the examples I find use actual property references, and in this case, the property can only be accessed and set through the GetValue, and SetValue functions. I'm having a hard time wrapping my head around how to achieve this. Below is an example of the linq query i want, if I KNEW the fields I wanted to return.
var Result = DefaultCollection.Select(x => new { BUSINESS_UNIT = x.GetValue("BUSINESS_UNIT"), FISCAL_YEAR = x.GetValue("FISCAL_YEAR") }).Distinct();
Again, I can't write this because I don't know which fields i need to include in the select list until runtime when I can reference the UniqueConstraint List.
How can I achieve this dynamically with Linq Expression?
Start To Finish Example
You've populated an IEnumerable<BaseItem> from a System.Data.DataTable and lets say the query that you ran was SELECT FIRST_NAME, LAST_NAME, EMAIL ADDRESS FROM TABLEA.
The IEnumerable is populated from automation in which a dynamic class is generated to represent a row in the table and dynamic properties are added to the class to represent each column in the table.
Accessing the properties is via methods in BaseItem string result = item.GetValue("FIRST_NAME") and item.SetValue("EMAIL_ADDRESS", "[email protected]');
You also queried INFORMATION_SCHEMA to get unique constraints on TABLEA and you store it in a public class ConstraintModel object that has a public List<string> Columns representing the columns that make up the unique constraint. In this case, only one column "EMAIL_ADDRESS" is in the constraint.
If the user makes changes to the IEnumerable<BaseItem> and more than one item has the same EMAIL_ADDRESS, we know that the UPDATE statement back to SQL will fail. We want to check that the unique constraint hasn't been violated.
At the point the user saves, we want to run a "Validation Check" on the in memory IEnumerable object. Ideally we would write a linq query that essentailly did a SELECT SUM(1), EMAIL_ADDRESS GROUP BY EMAIL_ADDRESS, and if any of the results had more than 1 value, we know a duplicate exists. Obviously the above syntax is SQL not Linq, but you get the idea. I can't know at compile time what fields on the BaseItem i need to select and group by, so I need to leverage the Constraint.Columns object and use it to write a dynamic linq expression. Additionally, the properties on the Dynamic Class are only exposed through the methods that they inherit from BaseItem ... GetValue(string PropertyName) and SetValue(string PropertyName, object Value);
dynamically selects properties from the collection based on the unique constraint columns from the table that the query referencedandI have that in a separate List, where the string values match the dynamic property names on the dynamic class(specifically, show us the API that allows you to 'dynamically select properties based on constraint columns' and 'the list with string values')