0

I'm trying to create a generic function within my application, and the one thing holding me up is a lambda expression that relies on knowing the object primary key.

eg. I'm extracing a list of PrimaryKey values from a list of records. This list of records could be a variety of different types, hence the name of the Primary Key field can be different. At present, I'm using the following code where (in this case), the list of items is of type ReportCategoryEntity, however this list could be one of many different class types.

    string primaryKeyName = "ReportCategoryID";
    List<long> ids = items.Select(c => c.ReportCategoryID).ToList();

However, I would like to have something like:

    string primaryKeyName = "ReportCategoryID";
    List<long> ids = items.Select(c => c.[primaryKeyName]).ToList();

I have reviewed some other questions that suggest using Dynamic Linq (LINQ : Dynamic select), however all examples return a list of the original class object (eg. List). I'm trying to return a simple list of type long of the Ids, without the other fields of the data object.

UPDATE: I'm currently using a work-around. Not hugely elegant, but it works.

I've now got a static function that will find the value of an object's property:

public static T GetPropertyValue<T>(object obj, string propName)
{
     return (T)obj.GetType().GetProperty(propName).GetValue(obj, null);
}

I can use this within my generic table processing function to find the value where = ReportCategoryEntity

string sql = "Select * From ReportCategories Where ReportID = 1;";
string primaryKeyName = "ReportCategoryID";
var primaryIds = new List<long>();
var items = await _dbCloud.QueryAsync<T>(sql);

foreach (var i in items)
{
     var v = Helpers.GetPropValue(i, primaryKeyName);
     primaryIds.Add(long.Parse(v.ToString()));
}
DaveA
  • 187
  • 1
  • 13
  • You must be defining these primary key strings somewhere. You must also know what type your list has somewhere. I would try to refactor your code to define your lambda in the same place, instead of naming fields using strings. – Jeremy Lakeman Sep 08 '21 at 01:39
  • Thanks Jeremy. Yes, I know the primary key, however I'm trying to pull out a chunk of code into a generic function rather than having the same 40 lines repeated 20 times. The work-around I just came up with uses a loop to extract the Primary Key value. Not elegant, but works. – DaveA Sep 08 '21 at 03:27
  • Is this linq-to-entities or linq-to-obejcts? What version of EF are you using? – Dai Sep 08 '21 at 03:41
  • Also, you should never need to use `dynamic`: there's always a better (i.e. statically-typed) approach. The only time you need to use `dynamic` is when interfacing with other DLR code (e.g. IronPython). – Dai Sep 08 '21 at 03:42
  • What happens if you have an object type with a _composite key_? You can't represent those as a single `long` value. – Dai Sep 08 '21 at 03:43
  • Why not have `interface IHasSingleInt64PrimaryKey { Int64 PK { get; } }` and have your types implement it? Then cast them as the interface type. – Dai Sep 08 '21 at 03:44
  • And your generic function (or type) can take a `Func getKey` argument, allowing the caller to define the method to access the primary key. – Jeremy Lakeman Sep 08 '21 at 03:51
  • BTW, if you want to make your code reusable in Linq-to-Entities you need to use `Expression>`, not just `Func<>`, otherwise Linq can't introspect your final query to generate the right SQL. – Dai Sep 08 '21 at 03:53
  • Thanks Dai and Jeremy - I'm using Dapper as an ORM rather than EF, however the class models are just POCO objects. All the primary keys are longs in my case, so composite keys aren't an issue in this instance. Its an interesting idea to have the object types implement an interface that declares the primary key. I'll explore options! – DaveA Sep 08 '21 at 04:28
  • Hello @DavidArcher, did you also investigate this project : https://github.com/zzzprojects/System.Linq.Dynamic.Core? With this you can just call `items.Select("any_property").ToDynamicList();` – Stef Heyenrath Oct 11 '21 at 06:55

0 Answers0