我试图找到一种方法,使用字符串sql查询将C#列表作为数据库进行查询,例如:
List<Customer> customers = new List<Customer>(){
new Customer(){Name = "joe", Age = 20},
new Customer(){Name = "john", Age = 25}
};
string query = @"Select * from customers";
List<Tuple> tuples = EntityDB.query(customers, query);
Console.Writeline(tuples[0][0]); //prints "joe"
我使用此功能需要满足几个要求,
我没有SQL服务器,我没有额外的mdf DB,只是这个客户对象列表,有没有办法做到这一点?
我的动机是能够从这个列表中提取特定信息到2D表并将其输出到excel,但行和列过滤不是预定义的,需要多行操作,用户将能够使用SQL查询指定要提取的确切信息。
答案 0 :(得分:4)
LINQ允许您对各种数据源执行类似查询的命令 - 数据库,XML文件,应用程序对象。您可以非常轻松地使用LINQ从列表中选择项目:
items.Select(c => c.Customer)
在内存对象中执行此操作时,您正在使用LINQ-to-Objects。
我更喜欢编写SQL-to-objects框架。这听起来像是一场真正的维护噩梦。
答案 1 :(得分:1)
您是否考虑过以与构建字符串相同的方式构建Linq?
像
这样的东西var customers = new List<Customer> { … };
IQueryable<Customer> results = customers.AsQueryable();
if(!string.IsNullOrEmpty(CustomerName))
results = results.Where(x => x.Name = CustomerName);
if(CustomerMaxAge != 0)
results = results.Where(x => x.Age <= CustomerMaxAge);
//etc....
return results.ToList();
使用IQueryable
,您可以推迟内存中的内容,直到您完成添加条件。
答案 2 :(得分:1)
您是否考虑使用轻量级数据库来解决问题,而不是尝试在代码中模拟数据库?想到像SQLite这样的东西。通常它会将文件写入磁盘,但实际上也支持在内存中加载。
根据文档,内存中的SQLite数据库不需要将文件写入磁盘,并且在打开连接时存在于内存中。一旦连接关闭,它就不复存在了。
http://www.sqlite.org/inmemorydb.html
打开连接后,您可以像使用常规SQL字符串的任何其他数据库一样查询数据,或者如果您愿意,可以使用LINQ和NHibernate或其他一些支持的ORM查询数据。
SQLite特别适用于需要SQL强大但没有设置完整数据库服务器的开销的时候。事实上,如果您使用Firefox作为浏览器,那么您现在正在使用SQLite;)
答案 3 :(得分:0)
也许这就是你想要的?
List<Tuple<string,int>> tuples = customers.Select(x => Tuple.Create(x.Name,x.Age)).ToList();
答案 4 :(得分:0)
P.S。:请参阅my other answer,它更好,可能更接近您所寻找的内容。
为了完整起见,这里是一个非常动态解决方案 - 尽管我发布这样糟糕的代码几乎感到羞耻:
// using System.Reflection;
// converts an object's public properties into an `object` sequence:
static IEnumerable<object> Terribelize<T>(this T obj)
{
foreach (PropertyInfo property in obj.GetType().GetProperties())
{
yield return property.GetValue(obj, null); // works if readable & non-indexed
}
}
// does the above to all objects in a sequence:
static IEnumerable<IEnumerable<object>> TerribelizeAll<T>(this IEnumerable<T> objs)
{
foreach (T obj in objs)
{
yield return obj.Terribelize();
}
}
然后你可以这样做:
var customers = new List<Customer> { … };
var abominations = customers.TerribelizeAll();
Console.Writeline(abominations.First().First());
为什么你会希望代码 无类型和非结构化超出我的范围。
答案 5 :(得分:0)
似乎基于ADO.NET DataTable
s的解决方案可能正是您所寻找的。 DataTable
和DataSet
基本上用于表示内存中的关系数据库对象。你可以,例如使用本答案末尾定义的扩展方法执行以下操作:
List<Customers> customers = …;
DataTable table = customers.CopyToDataTable(); // see implementation below
// non-LINQ select:
DataRow[] preferredCustomers = table.Select("Age > 15 AND Age < 50");
// LINQ select (requires project reference to System.Data.DatasetExtensions.dll):
IEnumerable<int> agesOfJCustomers = from row in table.AsEnumerable()
where row.Field<string>("Name").StartsWith("J")
select row.Field<int>("Age");
以下是将任何对象集合转换为数据表的方法:
// using System.Reflection;
// using System.Data;
public static DataTable CopyToDataTable<T>(this IEnumerable<T> objs)
{
var table = new DataTable();
// create the column definitions, based on the public properties of type T:
foreach (var property in typeof(T).GetProperties())
{
table.Columns.Add(property.Name, property.PropertyType);
}
// add one row per object in the given object collection:
foreach (T obj in objs)
{
var row = table.NewRow();
foreach (var column in table.Columns.Cast<DataColumn>())
{
var property = typeof(T).GetProperty(column.ColumnName);
var propertyValue = property.GetValue(obj, null);
row[column] = propertyValue;
}
table.Rows.Add(row);
}
return table;
}
此代码当然可以改进:查看MSDN文章"How to: Implement CopyToDataTable Where the Generic Type T
Is Not a DataRow
"。