HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Extension method to do Linq Lookups

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
linqlookupsmethodextension

Problem

Does this extension method contain unnecessary work? - Thanks for reviewing

Scenario - A series of tables are Key-Value pairs (Int "Id" / nvarChar "Title"). This extension method "dots-off" any integer ("Id") and provide the corresponding string value ("Title") given a target "type"

Used in aspx-code-behind. An extension method was chosen for readable one-liners. There are many panels with similar controls to be set conditionally.

// aspx.cs
txtParentGender.Text=parent.GenderId.RhGet(typeof(Gender));  //male, female
txtParentEthnicity.Text=parent.EthnicityId.RhGet(typeof(Ethnicity)); //Caucasian, etc. 
txtParentMaritalStatus.Text=parent.MaritalStatusId.RhGet(typeof(MaritalStatus)); // married, divorced etc.
txtChildGender.Text=child.GenderId.RhGet(typeof(Gender));
txtChildEthnicity.Text=child.EthnicityId.RhGet(typeof(Ethnicity));
txtChildRelation.Text=child.RelationId.RhGet(typeof(Relation)); //son, daughter etc.

// class.cs
using System.Linq.Dynamic; // nuget package

public static string RhGet(this int id, Type type )
{

   string returnValue = string.Empty;

   // set up data context
   using (MyDataContext dc = new MyDataContext())
   {
       // get table corresponding to this type
       var table = dc.GetTable(type);

       // match and select record using "id"
       var matchingRecord = ((IQueryable)table).Where(string.Format("Id.Equals({0})", id))
                                               .Select("new(Title)").Cast().FirstOrDefault();

       // do a lot of contorting to finally get the string value
       returnValue = matchingRecord.GetType().GetProperty("Title").GetValue(matchingRecord,null).ToString();
    }

    return returnValue;
}

Solution

I would not write this extension method for int at all since it assumes everything of type int in your project is referring to the ID of a table.

Also, as a rule of thumb, if you're using strings that contain structural metadata about your objects, it's generally a sign you might want to rethink your approach.

Instead, I would find a way to apply an interface to your tables that have this structure, so you could then make an extension method for that interface, or a method that takes in an instance that implements that interface. That way you don't have to rely on strings at all.

If you are really committed to having a method that finds a value based on an int and type inputs, I would change the method to be a static, non-extension method, passing in the int and type.

I also came up with this alternative solution. Although it doesn't behave the same as your original example, you might benefit by using a type parameter so you get a strongly-typed entity returned by your method, which your code will know has a "Title" property:

public static TEntity GetEntityById(int id)
{

   TEntity entity = null;

   //a using is a try finally. you have stuff you want to execute in a finally so I simplified.
   try
   {
        MyDataContext dc = new MyDataContext();

       // match and select record using "id"
       entity = dc.GetTable().Where(string.Format("Id.Equals({0})", id)).Cast().FirstOrDefault(); //not sure if Cast is redundant or not
    }
    finally 
    {
        return entity;
    }
}

//consuming code
string myTitle = GetEntityById(222).Title;


I also noticed you are instantiating a datacontext in this method--you might want to either pass it in or make this an extension method on your datacontext for testability.

Code Snippets

public static TEntity GetEntityById<TEntity>(int id)
{

   TEntity entity = null;

   //a using is a try finally. you have stuff you want to execute in a finally so I simplified.
   try
   {
        MyDataContext dc = new MyDataContext();

       // match and select record using "id"
       entity = dc.GetTable<TEntity>().Where(string.Format("Id.Equals({0})", id)).Cast<TEntity>().FirstOrDefault(); //not sure if Cast<TEntity> is redundant or not
    }
    finally 
    {
        return entity;
    }
}

//consuming code
string myTitle = GetEntityById<MyEntity>(222).Title;

Context

StackExchange Code Review Q#86797, answer score: 3

Revisions (0)

No revisions yet.