ASP.NET MVC4应用程序使用修改的WebMatrix Dynamicrecord从ADO.NET获取动态数据并将其显示在WebGrid中。如何在while循环中从ADO.NET获取动态数据
运行的应用程序将导致奇怪例外
尝试无效时没有数据在方法本
读取
private object GetNonNullValue(int i)
在线路
var value = Record[i];
正如https://github.com/npgsql/npgsql/issues/295中讨论的那样,使用注释中所示的foreach在Mono中不起作用。所以应用程序使用虽然但在Windows中也不起作用。
如何在while循环中获取动态数据?
所有解决方案可在http://wikisend.com/download/360760/invalidattemptoreadwhennodataispresent.zip
控制器:
using Eeva.Business;
using Eeva.Erp.ViewModels;
using Npgsql;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Web.Mvc;
namespace Eeva.Erp.Controllers
{
public class ReportController : Controller
{
public ActionResult Test()
{
var data = TestData();
return View("ReportData", new ReportDataViewModel(data, ""));
}
IEnumerable<dynamic> TestData()
{
using (var connection = new NpgsqlConnection(ConnectionString()))
{
connection.Open();
DbCommand command = (DbCommand)connection.CreateCommand();
command.CommandText = "select 'A' union select 'B'";
using (command)
{
using (DbDataReader reader = command.ExecuteReader())
{
IEnumerable<string> columnNames = null;
while (reader.Read())
{
if (columnNames == null)
columnNames = GetColumnNames(reader);
yield return new EevaDynamicRecord(columnNames, reader);
}
//foreach (DbDataRecord record in reader)
//{
// if (columnNames == null)
// columnNames = GetColumnNames(record);
// yield return new EevaDynamicRecord(columnNames, record);
//}
}
}
}
}
static IEnumerable<string> GetColumnNames(IDataRecord record)
{
// Get all of the column names for this query
for (int i = 0; i < record.FieldCount; i++)
yield return record.GetName(i);
}
static string ConnectionString()
{
return new NpgsqlConnectionStringBuilder()
{
Host = "localhost",
UserName = "postgres",
}.ConnectionString;
}
}
}
视图模型:
using System.Collections.Generic;
using System.Web.Mvc;
using Eeva.Business;
namespace Eeva.Erp.ViewModels
{
public class ReportDataViewModel
{
public IEnumerable<dynamic> Rows { get; set; }
public string Source;
public ReportDataViewModel(IEnumerable<dynamic> rows, string source)
{
Rows = rows;
Source = source;
}
}
}
检视:
@model Eeva.Erp.ViewModels.ReportDataViewModel
@using System.Web.Helpers
@{ Layout = null;
var gd = new WebGrid(source: Model.Rows);
}
<!DOCTYPE html>
<html>
<head></head>
<body>
@gd.GetHtml()
</body>
</html>
Dynamicrecord使用FR OM MVC4源代码的修改:
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Dynamic;
using System.Globalization;
using System.Linq;
using System.Text;
using WebMatrix.Data.Resources;
namespace Eeva.Business
{
public sealed class EevaDynamicRecord : DynamicObject, ICustomTypeDescriptor
{
public EevaDynamicRecord(IEnumerable<string> columnNames, IDataRecord record)
{
Debug.Assert(record != null, "record should not be null");
Debug.Assert(columnNames != null, "columnNames should not be null");
Columns = columnNames.ToList();
Record = record;
}
public IList<string> Columns { get; private set; }
private IDataRecord Record { get; set; }
public object this[string name]
{
get
{
for (int i = 0; i < Record.FieldCount; i++)
{
string normname = Record.GetName(i);
if (normname.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return GetNonNullValue(i);
}
throw new InvalidOperationException("No column " + name);
}
}
public object this[int index]
{
get
{
return GetNonNullValue(index); // GetValue(Record[index]);
}
}
public string Field(int fldNo)
{
return Record.GetName(fldNo).ToUpperInvariant();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this[binder.Name];
return true;
}
private object GetNonNullValue(int i)
{
var value = Record[i];
if (DBNull.Value == value || value == null)
{
var tt = Record.GetFieldType(i).Name;
switch (tt)
{
case "Decimal":
case "Int32":
case "Double":
return 0;
case "String":
return "";
case "DateTime":
return null;
case "Boolean":
// kui seda pole, siis demos lao kartoteek kartoteegi kaart annab vea:
return false;
}
return null;
}
if (value is decimal? || value is decimal)
return Convert.ChangeType(value, typeof(double));
if (value is string)
return value.ToString().TrimEnd();
return value;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return Columns;
}
private void VerifyColumn(string name)
{
// REVIEW: Perf
if (!Columns.Contains(name, StringComparer.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentCulture,
"Invalid Column Name " + name));
}
}
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return AttributeCollection.Empty;
}
string ICustomTypeDescriptor.GetClassName()
{
return null;
}
string ICustomTypeDescriptor.GetComponentName()
{
return null;
}
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return null;
}
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return null;
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return null;
}
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return null;
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return EventDescriptorCollection.Empty;
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return EventDescriptorCollection.Empty;
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
return ((ICustomTypeDescriptor)this).GetProperties();
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
// Get the name and type for each column name
var properties = from columnName in Columns
let columnIndex = Record.GetOrdinal(columnName)
let type = Record.GetFieldType(columnIndex)
select new DynamicPropertyDescriptor(columnName, type);
return new PropertyDescriptorCollection(properties.ToArray(), readOnly: true);
}
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
private class DynamicPropertyDescriptor : PropertyDescriptor
{
private static readonly Attribute[] _empty = new Attribute[0];
private readonly Type _type;
public DynamicPropertyDescriptor(string name, Type type)
: base(name, _empty)
{
_type = type;
}
public override Type ComponentType
{
get { return typeof(EevaDynamicRecord); }
}
public override bool IsReadOnly
{
get { return true; }
}
public override Type PropertyType
{
get { return _type; }
}
public override bool CanResetValue(object component)
{
return false;
}
public override object GetValue(object component)
{
EevaDynamicRecord record = component as EevaDynamicRecord;
// REVIEW: Should we throw if the wrong object was passed in?
if (record != null)
{
return record[Name];
}
return null;
}
public override void ResetValue(object component)
{
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentCulture,
"DataResources.RecordIsReadOnly", Name));
}
public override void SetValue(object component, object value)
{
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentCulture,
"DataResources.RecordIsReadOnly", Name));
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
}
}
}
我http://forums.asp.net/p/2013821/5795169.aspx
更新发布,这也
Problably创造每dynamicrecord的副本解决了这一问题:
Dictionary<string, object> Clonedict;
public EevaDynamicRecord Clone()
{
var res = new EevaDynamicRecord(Columns, Record);
res.Clonedict = new Dictionary<string, object>();
for (int i = 0; i < Record.FieldCount; i++)
res.Clonedict[Record.GetName(i)] = Record[i]);
return res;
// this also does not work:
// return (EevaDynamicRecord)this.MemberwiseClone();
}
是有更好的解决办法
我注意到,你没有验证该'我'是'GetNonNullValue'或'this [int index]'中的有效列索引。也许你最终会使用超出范围的列号? – 2014-10-18 14:23:40
调试器显示我的值为0。这是完美的价值,结果包含单列。 – Andrus 2014-10-18 14:33:29
我已经看到了问题,而不是这种模式,但与其他人,其中'DbCommand'和'DbDataReader'被包裹在一个'using'子句和'DbDataReader'返回那是'DbCommand'后采取行动和'DbDataReader'超出了范围。它截断了数据。也许类似这样的事情发生在'yield':'IEnumerable'被枚举时,'DbDataReader'从源数据中分离出来。因此,您的IDataRecord在访问时无效。 –
2014-10-18 22:28:39