开发者

Creating a generic retrieval method to return 1 record

开发者 https://www.devze.com 2023-03-11 14:59 出处:网络
I am working through a code sample, and I just want to hear some opinions on the way that they have done things.They use plain old ADO.NET.They have a generic function called Read that brings back 1 r

I am working through a code sample, and I just want to hear some opinions on the way that they have done things. They use plain old ADO.NET. They have a generic function called Read that brings back 1 record. Here is the code:

public static T Read<T>(string storedProcedure, Func<IDataReader, T> make, object[] parms = null)
{
   using (SqlConnection connection = new SqlConnection())
   {
      connection.ConnectionString = connectionString;

      using (SqlCommand command = new SqlCommand())
      {
         command.Connection = connection;
         command.CommandType = CommandType.StoredProcedure;
         command.CommandText = storedProcedure;
         command.SetParameters(parms);

         connection.Open();

         T t = default(T);
         var reader = command.ExecuteReader();
         if (reader.Read())
            t = make(reader);

         return t;
      }
   }
}

I don't know why:

  • They use Func<IDataReader, T> make as part of the method signature? Is it efficient to do it like this? Is there a better way/best practice to do this?
  • I don't understand T t = default(T);? Is it efficient to do it like this? Is there a better way/best practice to do this?
  • What does t = make(reader); do? Is it efficient to do it like this? Is there a better way/best practice to do this?

The calling function would look something like this:

public Customer GetCustomer(int customerId)
{
   // Other code here
   string storedProcedure = "MyStoredProcedure";
   object[] parameters = { "@CustomerId", customerId };
   return Db.Read(storedProcedure, Make, parameters);
}

private static Func<IDataReader, Customer> Make = reader =>
new Customer
{
   CustomerId = reader["CustomerId"].AsId(),
   Company = re开发者_运维知识库ader["CompanyName"].AsString(),
   City = reader["City"].AsString
};

I don't understand the Func Make part? Can someone please explain to me what is happening here and if this is good practices. Any changes would be appreciated, but please provide detailed sample code :)


The delegate for the make (materialization) is pretty versatile and flexible, but IMO makes for a bit of unnecessary work in the vast majority of cases. In terms of what it does - they use the delegate as a callback to get the caller to specify how to read the record.

Note, since they don't expect the consumer to change record, they should probably be exposing IDataRecord, not IDataReader (any reader also implements record).

Note that if there are any error messages in the TDS stream after the first record, the approach shown won't see them - but that is an edge case. If you wanted to mitigate against that, you could read to the end of the TDS stream:

while(reader.NextResult()) {}

Personally, though, I'd just use dapper-dot-net here - avoids having to write that per-type code manually:

var cust = connection.Query<Customer>("MyStoredProcedure",
     new { CustomerId = customerId },
     commandType: CommandType.StoredProcedure).Single();

this executes MyStoredProcedure as a sproc, passing in @CustomerId with the value from customerId, then applies a direct column<===>property/field match to create Customer records, then asserts that there is exactly one result - and returns it.


They use Func make as part of the method signature? Is it efficient to do it like this? Is there a better way/best practice to do this?

Due to the generic nature of the method T is unknown so they don't know how to map the reader back to T properties. So they leave this responsibility to the caller of the method. Actually this is efficient enough and it's good practice.

I don't understand T t = default(T);? Is it efficient to do it like this? Is there a better way/best practice to do this?

Because T could be either value or reference type you cannot assign it to null. default(T) returns the default value for this type.In case of reference type this will be null. In case of a value type, for example integer, it will be 0.

What does t = make(reader); do? Is it efficient to do it like this? Is there a better way/best practice to do this?

It invokes the delegate that is passed and assigns the result to t.

0

精彩评论

暂无评论...
验证码 换一张
取 消