我的存储过程正在返回动态数据透视表列。我使用的是SQLMapper和COlumnTypeAttribute,但在结果中我只能看到第一列及其值,但动态数据透视表列及其值是空的。
示例数据可能看起来像
第一列是固定的,其余列是枢轴列。
TSBNumber SystemXY SystemBB SystemTT
asdas 1/1/2013
1231 1/1/2014
12312 1/1/2013
ASAWS 1/1/2013
awsdS 1/1/2013
存储过程
DECLARE @PivotColumnHeaders NVARCHAR(MAX)
SELECT @PivotColumnHeaders =
COALESCE(
@PivotColumnHeaders + ',[' + cast(SystemFullName as Nvarchar) + ']',
'[' + cast(SystemFullName as varchar)+ ']'
)
FROM System
WHERE (@SelectedSystemIDs IS NULL OR System.ID IN(select * from dbo.SplitInts_RBAR_1(@SelectedSystemIDs, ',')))
AND ((@PlatformID IS NULL) OR (System.PlatformID = @PlatformID) OR (@PlatformID = 12 AND System.PlatformID <= 2))
DECLARE @PivotTableSQL NVARCHAR(MAX)
SET @PivotTableSQL = N'
SELECT *
FROM (
SELECT
TSBNumber [TSBNumber],
SystemFullName,
ClosedDate
FROM ServiceEntry
INNER JOIN System
ON ServiceEntry.SystemID = System.ID
where
(ServiceEntry.TSBNumber IS NOT NULL)
AND
(ServiceEntry.ClosedDate IS NOT NULL)
AND
(
(''' + @SelectedTsbIDs + ''' = '''+ '0' + ''') OR
(ServiceEntry.TSBNumber in (select * from dbo.SplitStrings_Moden(''' + @SelectedTsbIDs + ''', ''' + ',' + ''')))
)
) AS PivotData
PIVOT (
MAX(ClosedDate)
FOR SystemFullName IN (
' + @PivotColumnHeaders + '
)
) AS PivotTable
'
EXECUTE (@PivotTableSQL)
ColumnAttributeTypeManager
namespace RunLog.Domain.Exports
{
/// <summary>
/// Uses the Name value of the ColumnAttribute specified, otherwise maps as usual.
/// </summary>
/// <typeparam name="T">The type of the object that this mapper applies to.</typeparam>
public class ColumnAttributeTypeMapper<T> : FallbackTypeMapper
{
public static readonly string ColumnAttributeName = "ColumnAttribute";
public ColumnAttributeTypeMapper()
: base(new SqlMapper.ITypeMap[]
{
new CustomPropertyTypeMap(
typeof(T),
(type, columnName) =>
type.GetProperties().FirstOrDefault(prop =>
prop.GetCustomAttributes(false)
.OfType<ColumnAttribute>()
.Any(attr => attr.Name == columnName)
)
),
new DefaultTypeMap(typeof(T))
})
{
}
//public ColumnAttributeTypeMapper()
// : base(new SqlMapper.ITypeMap[]
// {
// new CustomPropertyTypeMap(typeof (T), SelectProperty),
// new DefaultTypeMap(typeof (T))
// })
//{
//}
//private static PropertyInfo SelectProperty(Type type, string columnName)
//{
// return
// type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).
// FirstOrDefault(
// prop =>
// prop.GetCustomAttributes(false)
// // Search properties to find the one ColumnAttribute applied with Name property set as columnName to be Mapped
// .Any(attr => attr.GetType().Name == ColumnAttributeName
// &&
// attr.GetType().GetProperties(BindingFlags.Public |
// BindingFlags.NonPublic |
// BindingFlags.Instance)
// .Any(
// f =>
// f.Name == "Name" &&
// f.GetValue(attr).ToString().ToLower() == columnName.ToLower()))
// && // Also ensure the property is not read-only
// (prop.DeclaringType == type
// ? prop.GetSetMethod(true)
// : prop.DeclaringType.GetProperty(prop.Name,
// BindingFlags.Public | BindingFlags.NonPublic |
// BindingFlags.Instance).GetSetMethod(true)) != null
// );
//}
}
public class MyModel
{
[Column("TSBNumber")]
public string TSBNumber { get; set; }
[Column(Name = "FileKey")]
public string MyProperty2 { get; set; }
//public string MyProperty2 { get; set; } // Uses Default Mapping
// ...
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class ColumnAttribute : Attribute
{
public string Name { get; set; }
public ColumnAttribute() { }
public ColumnAttribute(string Name) { this.Name = Name; }
}
public class FallbackTypeMapper : SqlMapper.ITypeMap
{
private readonly IEnumerable<SqlMapper.ITypeMap> _mappers;
public FallbackTypeMapper(IEnumerable<SqlMapper.ITypeMap> mappers)
{
_mappers = mappers;
}
public ConstructorInfo FindConstructor(string[] names, Type[] types)
{
foreach (var mapper in _mappers)
{
try
{
ConstructorInfo result = mapper.FindConstructor(names, types);
if (result != null)
{
return result;
}
}
catch (NotImplementedException)
{
}
}
return null;
}
public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
{
foreach (var mapper in _mappers)
{
try
{
var result = mapper.GetConstructorParameter(constructor, columnName);
if (result != null)
{
return result;
}
}
catch (NotImplementedException)
{
}
}
return null;
}
public SqlMapper.IMemberMap GetMember(string columnName)
{
foreach (var mapper in _mappers)
{
try
{
var result = mapper.GetMember(columnName);
if (result != null)
{
return result;
}
}
catch (NotImplementedException)
{
}
}
return null;
}
}
}
执行存储过程
public static string ServiceTsbExport(DateTime StartDate, DateTime EndDate, int UserRoleID,
string SelectedSystemIDs,
string SelectedTsbIDs)
{
EFDbContext db = new EFDbContext();
Dapper.SqlMapper.SetTypeMap(typeof(MyModel), new ColumnAttributeTypeMapper<MyModel>());
return db.Database.SqlQuery<MyModel>("[dbo].[spExportServiceTSB] @parm1, @parm2, @parm3, @parm4, @parm5",
new SqlParameter("parm1", StartDate),
new SqlParameter("parm2", EndDate),
new SqlParameter("parm3", SelectedSystemIDs),
new SqlParameter("parm4", SelectedTsbIDs),
new SqlParameter("parm5", UserRoleID)
).ToList().ToHTMLTable();
}
答案 0 :(得分:4)
我认为你很难做到这一点很简单。我曾经做过几乎完全相同的事情。这是它的匿名版本:
using Dapper;
...
using (var cnn = new SqlConnection(@"Data Source=... etc."))
{
cnn.Open();
var p = new DynamicParameters();
p.Add("@params", "Id=21");
var obs = cnn.Query(sql:"GetPivotData", param: p,
commandType:CommandType.StoredProcedure);
var dt = ToDataTable(obs);
}
此ToDataTable
方法可能与您的ToHTMLTable
方法类似。这是:
public DataTable ToDataTable(IEnumerable<dynamic> items)
{
if (items == null) return null;
var data = items.ToArray();
if (data.Length == 0) return null;
var dt = new DataTable();
foreach(var pair in ((IDictionary<string, object>)data[0]))
{
dt.Columns.Add(pair.Key, (pair.Value ?? string.Empty).GetType());
}
foreach (var d in data)
{
dt.Rows.Add(((IDictionary<string, object>)d).Values.ToArray());
}
return dt;
}
逻辑的核心是,Dapper的dynamic
扩展方法返回的Query()
可以转换为IDictionary<string, object>
。