Наконец-то у меня появился шанс сделать некоторые TableValuedParameters, и они отлично работают, поэтому я собираюсь вставить целый лот-код, который показывает, как я их использую, с примером из моего текущего кода: (примечание: мы используем ADO .СЕТЬ)
Также обратите внимание: я пишу некоторый код для службы, и у меня есть много предопределенных битов кода в другом классе, но я пишу это как консольное приложение, чтобы я мог отлаживать его, поэтому я скопировал все это из консольное приложение. Извините, мой стиль кодирования (например, жестко закодированные строки подключения), так как он был своего рода "создать один, чтобы выбросить". Я хотел показать, как я использую, List<customObject>
и легко помещать его в базу данных в виде таблицы, которую я могу использовать в хранимой процедуре. C # и код TSQL ниже:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using a;
namespace a.EventAMI {
class Db {
private static SqlCommand SqlCommandFactory(string sprocName, SqlConnection con) { return new SqlCommand { CommandType = CommandType.StoredProcedure, CommandText = sprocName, CommandTimeout = 0, Connection = con }; }
public static void Update(List<Current> currents) {
const string CONSTR = @"just a hardwired connection string while I'm debugging";
SqlConnection con = new SqlConnection( CONSTR );
SqlCommand cmd = SqlCommandFactory( "sprocname", con );
cmd.Parameters.Add( "@CurrentTVP", SqlDbType.Structured ).Value = Converter.GetDataTableFromIEnumerable( currents, typeof( Current ) ); //my custom converter class
try {
using ( con ) {
con.Open();
cmd.ExecuteNonQuery();
}
} catch ( Exception ex ) {
ErrHandler.WriteXML( ex );
throw;
}
}
}
class Current {
public string Identifier { get; set; }
public string OffTime { get; set; }
public DateTime Off() {
return Convert.ToDateTime( OffTime );
}
private static SqlCommand SqlCommandFactory(string sprocName, SqlConnection con) { return new SqlCommand { CommandType = CommandType.StoredProcedure, CommandText = sprocName, CommandTimeout = 0, Connection = con }; }
public static List<Current> GetAll() {
List<Current> l = new List<Current>();
const string CONSTR = @"just a hardcoded connection string while I'm debugging";
SqlConnection con = new SqlConnection( CONSTR );
SqlCommand cmd = SqlCommandFactory( "sprocname", con );
try {
using ( con ) {
con.Open();
using ( SqlDataReader reader = cmd.ExecuteReader() ) {
while ( reader.Read() ) {
l.Add(
new Current {
Identifier = reader[0].ToString(),
OffTime = reader[1].ToString()
} );
}
}
}
} catch ( Exception ex ) {
ErrHandler.WriteXML( ex );
throw;
}
return l;
}
}
}
-------------------
the converter class
-------------------
using System;
using System.Collections;
using System.Data;
using System.Reflection;
namespace a {
public static class Converter {
public static DataTable GetDataTableFromIEnumerable(IEnumerable aIEnumerable) {
return GetDataTableFromIEnumerable( aIEnumerable, null );
}
public static DataTable GetDataTableFromIEnumerable(IEnumerable aIEnumerable, Type baseType) {
DataTable returnTable = new DataTable();
if ( aIEnumerable != null ) {
//Creates the table structure looping in the in the first element of the list
object baseObj = null;
Type objectType;
if ( baseType == null ) {
foreach ( object obj in aIEnumerable ) {
baseObj = obj;
break;
}
objectType = baseObj.GetType();
} else {
objectType = baseType;
}
PropertyInfo[] properties = objectType.GetProperties();
DataColumn col;
foreach ( PropertyInfo property in properties ) {
col = new DataColumn { ColumnName = property.Name };
if ( property.PropertyType == typeof( DateTime? ) ) {
col.DataType = typeof( DateTime );
} else if ( property.PropertyType == typeof( Int32? ) ) {
col.DataType = typeof( Int32 );
} else {
col.DataType = property.PropertyType;
}
returnTable.Columns.Add( col );
}
//Adds the rows to the table
foreach ( object objItem in aIEnumerable ) {
DataRow row = returnTable.NewRow();
foreach ( PropertyInfo property in properties ) {
Object value = property.GetValue( objItem, null );
if ( value != null )
row[property.Name] = value;
else
row[property.Name] = "";
}
returnTable.Rows.Add( row );
}
}
return returnTable;
}
}
}
USE [Database]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[Event_Update]
@EventCurrentTVP Event_CurrentTVP READONLY
AS
/****************************************************************
author cbrand
date
descrip I'll ask you to forgive me the anonymization I've made here, but hope this helps
caller such and thus application
****************************************************************/
BEGIN TRAN Event_Update
DECLARE @DEBUG INT
SET @DEBUG = 0 /* test using @DEBUG <> 0 */
/*
Replace the list of outstanding entries that are still currently disconnected with the list from the file
This means remove all existing entries (faster to truncate and insert than to delete on a join and insert, yes?)
*/
TRUNCATE TABLE [database].[dbo].[Event_Current]
INSERT INTO [database].[dbo].[Event_Current]
([Identifier]
,[OffTime])
SELECT [Identifier]
,[OffTime]
FROM @EventCurrentTVP
IF (@@ERROR <> 0 OR @DEBUG <> 0)
BEGIN
ROLLBACK TRAN Event_Update
END
ELSE
BEGIN
COMMIT TRAN Event_Update
END
USE [Database]
GO
CREATE TYPE [dbo].[Event_CurrentTVP] AS TABLE(
[Identifier] [varchar](20) NULL,
[OffTime] [datetime] NULL
)
GO
Кроме того, я буду конструктивно критиковать мой стиль кодирования, если у вас есть что предложить (всем читателям, которые сталкиваются с этим вопросом), но, пожалуйста, оставьте его конструктивным;) ... Если вы действительно хотите меня, найдите меня в чате здесь , Надеюсь, с помощью этого фрагмента кода можно увидеть, как они могут использовать, List<Current>
как я определил, таблицу в БД и А List<T>
в своем приложении.