Note that there are some explanatory texts on larger screens.

plurals
  1. POC# LINQ to SQL: Refactoring this Generic GetByID method
    primarykey
    data
    text
    <p>I wrote the following method.</p> <pre><code>public T GetByID(int id) { var dbcontext = DB; var table = dbcontext.GetTable&lt;T&gt;(); return table.ToList().SingleOrDefault(e =&gt; Convert.ToInt16(e.GetType().GetProperties().First().GetValue(e, null)) == id); } </code></pre> <p>Basically it's a method in a Generic class where <code>T</code> is a class in a DataContext.</p> <p>The method gets the table from the type of T (<code>GetTable</code>) and checks for the first property (always being the ID) to the inputted parameter.</p> <p>The problem with this is I had to convert the table of elements to a list first to execute a <code>GetType</code> on the property, but this is not very convenient because all the elements of the table have to be enumerated and converted to a <code>List</code>.</p> <p>How can I refactor this method to avoid a <code>ToList</code> on the whole table?</p> <p><strong>[Update]</strong></p> <p>The reason I can't execute the <code>Where</code> directly on the table is because I receive this exception:</p> <blockquote> <p>Method 'System.Reflection.PropertyInfo[] GetProperties()' has no supported translation to SQL.</p> </blockquote> <p>Because <code>GetProperties</code> can't be translated to SQL.</p> <p><strong>[Update]</strong></p> <p>Some people have suggested using an interface for <em>T</em>, but the problem is that the <code>T</code> parameter will be a class that is auto generated in <em>[DataContextName].designer.cs</em>, and thus I cannot make it implement an interface (and it's not feasible implementing the interfaces for all these "database classes" of LINQ; and also, the file will be regenerated once I add new tables to the DataContext, thus loosing all the written data).</p> <p>So, there has to be a better way to do this...</p> <p><strong>[Update]</strong></p> <p>I have now implemented my code like <a href="https://stackoverflow.com/questions/735140/c-linq-to-sql-refectoring-this-generic-getbyid-method/735209#735209">Neil Williams</a>' suggestion, but I'm still having problems. Here are excerpts of the code:</p> <p><em>Interface:</em></p> <pre><code>public interface IHasID { int ID { get; set; } } </code></pre> <p><em>DataContext [View Code]:</em></p> <pre><code>namespace MusicRepo_DataContext { partial class Artist : IHasID { public int ID { get { return ArtistID; } set { throw new System.NotImplementedException(); } } } } </code></pre> <p><em>Generic Method:</em></p> <pre><code>public class DBAccess&lt;T&gt; where T : class, IHasID,new() { public T GetByID(int id) { var dbcontext = DB; var table = dbcontext.GetTable&lt;T&gt;(); return table.SingleOrDefault(e =&gt; e.ID.Equals(id)); } } </code></pre> <p>The exception is being thrown on this line: <code>return table.SingleOrDefault(e =&gt; e.ID.Equals(id));</code> and the exception is:</p> <blockquote> <p><code>System.NotSupportedException: The member 'MusicRepo_DataContext.IHasID.ID' has no supported translation to SQL.</code></p> </blockquote> <p><strong>[Update] Solution:</strong></p> <p>With the help of <a href="https://stackoverflow.com/questions/735140/c-linq-to-sql-refectoring-this-generic-getbyid-method/735888#735888">Denis Troller</a>'s posted answer and the link to the post at the <a href="http://mikehadlow.blogspot.com/2008/03/using-irepository-pattern-with-linq-to.html" rel="nofollow noreferrer">Code Rant blog</a>, I finally managed to find a solution:</p> <pre><code>public static PropertyInfo GetPrimaryKey(this Type entityType) { foreach (PropertyInfo property in entityType.GetProperties()) { ColumnAttribute[] attributes = (ColumnAttribute[])property.GetCustomAttributes(typeof(ColumnAttribute), true); if (attributes.Length == 1) { ColumnAttribute columnAttribute = attributes[0]; if (columnAttribute.IsPrimaryKey) { if (property.PropertyType != typeof(int)) { throw new ApplicationException(string.Format("Primary key, '{0}', of type '{1}' is not int", property.Name, entityType)); } return property; } } } throw new ApplicationException(string.Format("No primary key defined for type {0}", entityType.Name)); } public T GetByID(int id) { var dbcontext = DB; var itemParameter = Expression.Parameter(typeof (T), "item"); var whereExpression = Expression.Lambda&lt;Func&lt;T, bool&gt;&gt; ( Expression.Equal( Expression.Property( itemParameter, typeof (T).GetPrimaryKey().Name ), Expression.Constant(id) ), new[] {itemParameter} ); return dbcontext.GetTable&lt;T&gt;().Where(whereExpression).Single(); } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload