- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经在 StackOverflow(和其他网站)中搜索了有关在 C# 中使用反射将 DataTable 转换为 List 的信息。
到目前为止,我的结果非常好:我可以在 3.5 秒内反射(reflect) 20 万行(在硬编码模式下为 0.5 秒)。
但是我的实体(代表我的数据的类,但我想你已经知道了)遵循这种模式:
我的数据库有这样的列(我实际上并没有这样做,但你会明白的):
Table: Clients
Columns:
ClientID, ClientName, ClientPhone, CityID[FK]
我正在使用 SqlConnection (MySqlConnection),因此我必须对我的实体进行硬编码并将数据库结果转换为该实体的列表。喜欢:
Select *, cit.* from Clients cli
Inner join Cities cit on (cit.CityID == cli.CityID)
Inner join Countries cou on (cou.CountryID == cit.CountID)
我不知道这个 SQL 是否正确,但我想你明白了。这应该返回一些这样的字段:
ClientID, ClientName, ClientPhone, CityID, CityName, CountryID, CountryName
结果应该是 List<Client>
.
问题是:我有 2 个内部联接,我在我的实体中表示这些数据是这样的(我喜欢“像这样”这样的表达方式):
public class Client
{
public int ClientID { get; set; }
public string ClientName { get; set; }
public string ClientPhone { get; set; }
public City ClientCity { get; set; }
}
public class City
{
public int CityID { get; set; }
public string CityName { get; set; }
public Country CityCountry { get; set; }
}
public class Country
{
public int ContryID { get; set; }
public string CountryName { get; set; }
}
所以,如果我有一个 Client
对象,我会通过表达式 client.ClientCity.CityCountry.CountryName
得到它的国家名称.我称之为 3 级属性访问器。
我想正确地反射(reflect)它。下面是将 DataTable 转换为 List 的主要方法。我的母语是葡萄牙语,但我尝试翻译我的评论以符合我上面的描述。
这段代码的想法是:我尝试在主类中找到我必须设置的列。如果找不到,我会在作为对象的属性中搜索该属性。就像 Client 中的 ClientCity 中的 CityName。这段代码一团糟。
public List<T> ToList<T>(DataTable dt) where T : new()
{
Type type= typeof(T);
ReflectionHelper h = new ReflectionHelper(type);
insertPropInfo(tipo); //a pre-reflection work, I cache some delegates, etc..
List<T> list = new List<T>();
DataTableReader dtr = dt.CreateDataReader();
while (dtr.Read())
{
T obj = new T();
for (int i = 0; i < dtr.FieldCount; i++)
{
GetObject(ref obj, tipo, dtr.GetName(i), dtr.GetValue(i));
}
list.Add(obj);
}
return lista;
}
//ref T obj: the object I create before calling this method
//Type classType: the type of the object (say, Client)
//string colName: this is the Database Column i'm trying to fill. Like ClientID or CityName or CountryName.
//colLineData: the data I want to put in the colName.
public void GetObject<T>(ref T obj, Type classType, string colName, object colLineData) where T : new()
{
//I do some caching to reflect just once, and after the first iteration, I think all the reflection I need is already done.
foreach (PropertyInfo info in _classPropInfos[classType])
{
//If the current PropertyInfo is a valuetype (like int, int64) or string, and so on
if (info.PropertyType.IsValueType || info.PropertyType == typeof(string))
{
//I think string.Equals is a little faster, but i had not much difference using "string" == "string"
if (info.Name.Equals(colName)) //did I found the property?
if (info.PropertyType != typeof(char)) //I have to convert the type if this is a Char. MySql returns char as string.
{
_delegateSetters[info](obj, colLineData); //if it isn't a char, just set it.
}
else
{
_delegateSetters[info](obj, Convert.ChangeType(colLineData, typeof(char)));
}
break;
}
else //BUT, if the property is a class, like ClientCity:
{
//I reflect the City class, if it isn't reflected yet:
if (!_classPropInfos.ContainsKey(info.PropertyType))
{
insertPropInfo(info.PropertyType);
}
//now I search for the property:
Boolean foundProperty = false;
object instance = _delegateGetters[info](obj); //Get the existing instance of ClientCity, so I can fill the CityID and CityName in the same object.
foreach (PropertyInfo subInfo in _classPropInfos[info.PropertyType])
{
if (subInfo.Name.Equals(colName))//did I found the property?
{
if (instance == null)
{
//This will happen if i'm trying to set the first property of the class, like CityID. I have to instanciate it, so in the next iteration it won't be null, and will have it's CityID filled.
instance = _initializers[info.PropertyType]();//A very fast object initializer. I'm worried about the Dictionary lookups, but i have no other idea about how to cache it.
}
_delegateSetters[subInfo](instance, colLineData);//set the data. This method is very fast. Search about lambda getters & setters using System.Linq.Expression.
foundProperty = true;
break;//I break the loops when I find the property, so it wont iterate anymore.
}
}
if (foundProperty)//if I found the property in the code above, I set the instance of ClientCity to the Client object.
{
_delegateSetters[info](obj, instance);
break;
}
}
}
}
此代码有一个问题:我可以访问 CityID 和 CityName,并填写它。但是 CountryID 和 CountryName 不会。因为这段代码可以进行 2 层反射,所以我需要一些递归方法来填充我需要的许多层。我尝试这样做,但我遇到了太多的堆栈溢出和空引用异常,我几乎放弃了。
此代码将使获取数据库行变得更加容易,您是否已经找到了一些库或任何可以满足我需要的东西?如果不是,我如何实现 n 级反射以从 DataTable 中创建适当的列表?
最佳答案
你的问题很常见,几乎所有流通的 ORM 都解决了这个问题。
当然,更改已编写的应用程序以利用 ORM 通常是不切实际的,但是有一些简单的 ORM 确实很容易添加到现有应用程序中,并让您逐步替换已编写的代码。
其中一个 ORM 是 DAPPER .它仅包含一个源文件,您可以将其直接包含在与您的 POCO 类和存储库方法相同的项目中(或者仅引用已编译的程序集)。它真的很容易学习,考虑到要执行的工作的复杂性,它的速度非常快。更不用说这个小 gem 的作者经常在这个网站上回答关于他们工作的问题。只需使用 #dapper
进行搜索即可标签
到目前为止,我发现的唯一麻烦是您的 POCO 属性和字段名称的一对一映射,以及当您的 key 未命名时 PK 和 FK 之间有时会逃避的规则 ID
.但这就是我,我仍然没有完全理解这些规则。
关于c# - 在 C# 中将 DataTable 转换为 List<T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19226203/
这个问题在这里已经有了答案: How to initialize var? (11 个答案) 关闭 8 年前。 我想给一个变量赋初值 null,并在下一个 if-else block 中赋值,但是编
我正在使用 TypeScript 3.8 编写 JS 和 TS 混合的代码。我写了以下行: export * as Easing from './easing'; 应该是 fair game在 Typ
我需要将 R 代码中的“/”更改为“\”。我有这样的事情: tmp <- paste(getwd(),"tmp.xls",sep="/") 所以我的 tmp是 c:/Study/tmp.xls 我希望
我有个问题。例如我有这个: id truth count 1 1 1 2 1 2 3 0 0 4 1 1 5 1 2 6 1
我正在尝试使用“IN”和“=”来查找一些 bean。我目前正在使用此代码: $ids = array(1,2,3,4); $user = 1; $things = R::find( 'thing'
是否可以在 Xcode 中部署到其他人的手机上?我没有 iPhone,但我想测试我在 friend 手机上制作的应用程序。在我支付 99 美元之前,我想确保这不会造成麻烦。 谢谢。 最佳答案 不会有任
我试图得到一个非常大的数字(超过 unsigned long long int )。所以我把它作为一个字符串,然后一个数字一个数字地转换成整数并使用它。 #include #include int
我在 Rust 中有 C 语言库的绑定(bind),但它们并不完整。 在 C 代码中,我定义了一个简化的宏,如下所示: #define MY_MACROS1(PTR) (((my_struct1
我正在努力解决这个问题。 http://jsfiddle.net/yhcqfy44/ 动画应该自动相对于 滚动到顶部每次出现滚动条时的高度。 我已经写了这个,但没有运气: var hheight =
我正在处理一个将数字作为字符串返回的 JSON API。例如 "12" ,但是,该字段值也可以是非数字的,例如:"-" . 我已将 JSON 数据解析为映射,我想将此字段提取为 elixir 中的整数
我正在尝试编写一个类,将.wav文件转换为.aiff文件作为项目的一部分。 我遇到了几个库Alvas.Audio(http://alvas.net/alvas.audio,overview.aspx)
我想在 Lucene 中将像“New York”这样的“复合词”索引为单个术语,而不是像“new”、“york”那样。这样,如果有人搜索“new place”,则包含“new york”的文档将不会匹
我希望这个解释能让我更好地了解使用宏的优点。 最佳答案 在函数中,所有参数在调用之前都会被评估。 这意味着 or 作为函数不能是惰性的,而宏可以将 or 重写为 if 语句,该语句仅在以下情况下计算分
我有一些看起来像这样的 XML foo ]]> (注意 > 登录 "> foo")和 XSLT 样式表 当我运行xsltproc stylesheet.xs
当我尝试将 Any 转换为 List 时,如下面的示例所示,我得到“Unchecked cast: Any!”到列表'警告。有没有解决此类问题的方法? val x: List = objectOfTy
我正在使用 Python 开发一个简单的爬虫。目的是创建一个 sitemap.xml。(你可以在这里找到真正的 alpha 版本:http://code.google.com/p/sitemappy/
我想知道在 VBScript 中是否可以在多行中中断 If 语句。喜欢: If (UCase(Trim(objSheet.Cells(i, a).Value)) = "YES") Or _ (UCas
for (String item : someList) { System.out.println(item); } 使用“do while”是否等效? 谢谢。 最佳答案 如果列表为空,f
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Split string with delimiters in C 在 C 中将“,”分隔的列表拆分为数组的最佳方法
我有一个如下所示的字符数组: [0, 10, 20, 30, 670] 如何将此字符串转换为整数数组? 这是我的数组 int i=0; size_t dim = 1; char* array = (c
我是一名优秀的程序员,十分优秀!