I am getting following error while executing simple select statement in my custom code.
Could not find specified column in results
Here is my code-
string queryBuilder="select BASKET_DESCRIPTION from MARKET_BASKET_REQUESTS order by BASKET_DESCRIPTION limit 1";
public T SelectSingle<T>(string queryBuilder) where T : new()//made new
{
T result = new T();
TableScheme dbTable = GetTableSchemeFromType(typeof(T));
IDataReader reader = ExecuteReader(queryBuilder);
result = ParseDataReaderToEntityListtttt<T>(reader,dbTable);
reader.Close();
return result;
}
private T ParseDataReaderToEntityListtttt<T>(IDataReader reader, TableScheme dbTable) where T : new()
{
Type type = typeof(T);
T result = new T();
while (reader.Read())
{
T t = new T();
foreach (var column in dbTable.Columns)
{
type.GetProperty(column.AssociatedPropertyName).SetValue(t, reader[column.ColumnName], null);
}
result = t;
}
return result;
}
Your SELECT statement only selects the BASKET_DESCRIPTION column, while your TableScheme (which is generated by the not shown method GetTableSchemeFromType(), but I guess it uses Type.GetProperties() to get all properties) is requesting other columns by name which aren't present in the result set, which is what the error is trying to tell you.
So either SELECT * (or at least all relevant columns), or stop building your own ORM and use an existing one.
Related
i have my classes as the following:
class SalesInvlice
{
int id {get;set;}
string number {get;set;}
List<InvoiceItems> {get;set}
}
class InvoiceItems
{
id {get;set}
string item_name {get;set}
int price {get;set;}
}
my application is an agent that can connect to any database specified in the config file, and to execute a certain query. in my case it will execute a query on one client DB as the following select id, number, items.id as items_id, item_name, price from transaction left join transaction_details on transactions.id = transaction_details.transaction_id
let say i got the data using SQLDataReader, but i am open in another solutions as well.
what i am looking for here, is to map the results from SQLDataReader to list of SalesInvoice Object.
the issue i am facing that if the transaction has list of transaction_details, this means the datareader will get them to me in different rows.
You have a choice to make you can return the data in one dataset or two. The first will return the transaction data duplicated see bellow. You will need to manage the dr duplicate transactions.
select id,
number,
items.id as items_id,
item_name, price
from transaction
left join transaction_details
on transactions.id = transaction_details.transaction_id
Or return the data in two sets of data ( transaction and transaction detail). I am assuming that you are interested in data for a particular transaction not many different transactions. Ado.net will allow for multiple groups of data to be returned. You would need to cast each data set to is object type. dimly a case of newing up a transaction and assigning properties.
to solve this issue, i have made my simi general mapper.
I have mapper that do the following:
private List<T> mappingFun<T>( IEnumerable<Dictionary<string, object>> args, object propListObj = null) where T: Entity
{
List<T> listObject = new List<T>();
foreach(var arg in args)
{
T returnedObject = Activator.CreateInstance<T>();
PropertyInfo[] modelProperties = returnedObject.GetType().GetProperties();
var addedobject = listObject.FirstOrDefault(x => x.name == arg[returnedObject.GetType().Name + "_name"].ToString());
if (addedobject != null)
{
returnedObject = addedobject;
}
foreach(var prop in modelProperties)
{
var a = prop.PropertyType;
if (prop.PropertyType == typeof(String))
{
prop.SetValue(returnedObject, arg[returnedObject.GetType().Name + "_" + prop.Name].ToString());
}
else
{
var propModuleObj = GetType().GetMethod("mappingFun", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(IEnumerable<Dictionary<string, object>>), typeof(object) }, null).MakeGenericMethod(prop.PropertyType.GetGenericArguments().Single()).Invoke(this, new object[] { new List<Dictionary<string, object>>() { arg }, prop.GetValue(returnedObject) });
prop.SetValue(returnedObject, propModuleObj);
}
}
listObject.AddIfNotExist(returnedObject);
if(propListObj != null)
listObject.AddRange((List<T>)propListObj);
}
return listObject;
}
This helps 100%
I am trying to enumerate the registry to fetch a list of installed applications and return them via Linq to a DataTable in C#.
I have tried various things including sanitizing it as XML (which worked), however it seemed rather inefficient as ultimately, i require this as DataTable object.
Here is where i am at currently:
//Warning
public static DataRow DataRowInstalledApplication (this RegistryKey rgkey, string keyName)
{
RegistryKey key = rgkey.OpenSubKey(keyName, false);
try
{
//Application Name is mandetory for a given key.
if (key == null|| key.RegToString("DisplayName", false) == null )return null;
//Build a sanitised data row
var rowBuilder = new DataTable().NewRow();
rowBuilder["DisplayName"] = key.RegToString("DisplayName");
rowBuilder["UninstallString"] = key.RegToString("UninstallString");
rowBuilder["InstallLocation"] = key.RegToString("InstallLocation");
rowBuilder["Publisher"] = key.RegToString("Publisher");
rowBuilder["DisplayIcon"] = key.RegToString("DisplayIcon");
return rowBuilder;
}
finally
{
if (key != null) key.Close();
}
}
Here is the method that contains the Linq:
public DataTable GetRegistryApplicationDataTable(RegistryKey registryKey, string tableName)
{
if (registryKey != null)
{
try
{
//change to throw non critical error
var installedListXml = new DataTable(tableName, from name in registryKey.GetSubKeyNames()
let app = registryKey.DataRowInstalledApplication(name)
select app);
return installedListXml;
}
catch
{
return new DataTable(tableName);
}
finally
{
registryKey.Close();
}
}
return null;
}
The main problem i have is that i do not really understand Linq very well. Mainly how individual values are used during the iteration to call other things similar to
foreach (string value in collection)
{
Somefunction(value);
}
, in the case of the registry values i am trying to retrieve, i do not understand how to make a Linq query pass each key name to function, which will generate a row and the Linq Query return as a data table.
I would be grateful of any pointers! thanks
ps i call the above with
private static readonly RegistryKey HKLMUninstallKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
GetRegistryApplicationDataTable(HKLMUninstallKey, "Computer")
and expect back a data table called computer.
Your first problem is your linq statement. You are trying to pass an IEnumerable into a constructor that is expecting either a (string) or a (string, string). If you modify your logic to this:
var query = from name in registryKey.GetSubKeyNames()
let app = registryKey.DataRowInstalledApplication(name)
select app;
foreach(var result in query)
{
var installedListXml = new DataTable(tableName, result);
}
That would work IF result was actually a string, but it's a DataRow, which is not a valid parameter for a DataTable constructor. Instead, there is an extension method you can call on the resulting query to copy to a data table, like so:
var query = from name in registryKey.GetSubKeyNames()
let app = registryKey.DataRowInstalledApplication(name)
select app;
var installedListXml = query.CopyToDataTable();
When you write a LINQ query statement, it is not executed until you try to enumerate over the results. CopyToDataTable does this, so if you were to step through your code you will notice that your function DataRowInstalledApplication will not be called until you call CopyToDataTable and not when you first assign query. The result you receive is an Enumerator that you can treat just like any other, whether that's using in a foreach loop or calling ToList or so forth. Inside the linq query itself, you are actually iterating over other values, in this case GetSubKeyNames. It would be functionally equivalent if you were to do this instead:
var dataRows = new List<DataRow>();
foreach(var name in registryKey.GetSubKeyNames())
{
dataRows.Add(registryKey.DataRowInstalledApplication(name));
}
return dataRows.CopyToDataTable();
I'm new to using Dynamic Objects in C#. I am reading a CSV file very similarly to the code found here: http://my.safaribooksonline.com/book/programming/csharp/9780321637208/csharp-4dot0-features/ch08lev1sec3
I can reference the data I need with a static name, however I can not find the correct syntax to reference using a dynamic name at run time.
For example I have:
var records = from r in myDynamicClass.Records select r;
foreach(dynamic rec in records)
{
Console.WriteLine(rec.SomeColumn);
}
And this works fine if you know the "SomeColumn" name. I would prefer to have a column name a a string and be able to make the same type refrence at run time.
Since one has to create the class which inherits from DynamicObject, simply add an indexer to the class to achieve one's result via strings.
The following example uses the same properties found in the book example, the properties which holds the individual line data that has the column names. Below is the indexer on that class to achieve the result:
public class myDynamicClassDataLine : System.Dynamic.DynamicObject
{
string[] _lineContent; // Actual line data
List<string> _headers; // Associated headers (properties)
public string this[string indexer]
{
get
{
string result = string.Empty;
int index = _headers.IndexOf(indexer);
if (index >= 0 && index < _lineContent.Length)
result = _lineContent[index];
return result;
}
}
}
Then access the data such as
var csv =
#",,SomeColumn,,,
ab,cd,ef,,,"; // Ef is the "SomeColumn"
var data = new myDynamicClass(csv); // This holds multiple myDynamicClassDataLine items
Console.WriteLine (data.OfType<dynamic>().First()["SomeColumn"]); // "ef" is the output.
You will need to use reflection. To get the names you would use:
List<string> columnNames = new List<string>(records.GetType().GetProperties().Select(i => i.Name));
You can then loop through your results and output the values for each column like so:
foreach(dynamic rec in records)
{
foreach (string prop in columnNames)
Console.Write(rec.GetType().GetProperty (prop).GetValue (rec, null));
}
Try this
string column = "SomeColumn";
var result = rec.GetType().GetProperty (column).GetValue (rec, null);
I think I understand returning records of an anonymous type from But in this I want to create NEW CatalogEntries, and set them from the values selected. (context is a Devart LinqConnect database context, which lets me grab a view).
My solution works, but it seems clumsy. I want to do this in one from statement.
var query = from it in context.Viewbostons
select it;
foreach (GPLContext.Viewboston item in query)
{
CatalogEntry card = new CatalogEntry();
card.idx = item.Idx;
card.product = item.Product;
card.size = (long)item.SizeBytes;
card.date = item.Date.ToString();
card.type = item.Type;
card.classification = item.Classification;
card.distributor = item.Distributor;
card.egplDate = item.EgplDate.ToString();
card.classificationVal = (int)item.ClassificationInt;
card.handling = item.Handling;
card.creator = item.Creator;
card.datum = item.Datum;
card.elevation = (int)item.ElevationFt;
card.description = item.Description;
card.dirLocation = item.DoLocation;
card.bbox = item.Bbox;
card.uniqID = item.UniqId;
values.Add(card);
}
CatalogResults response = new CatalogResults();
I just tried this:
var query2 = from item in context.Viewbostons
select new CatalogResults
{ item.Idx,
item.Product,
(long)item.SizeBytes,
item.Date.ToString(),
item.Type,
item.Classification,
item.Distributor,
item.EgplDate.ToString(),
(int)item.ClassificationInt,
item.Handling,
item.Creator,
item.Datum,
(int)item.ElevationFt,
item.Description,
item.DoLocation,
item.Bbox,
item.UniqId
};
But I get the following error:
Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a
collection initializer because it does not implement
'System.Collections.IEnumerable' C:\Users\ysg4206\Documents\Visual
Studio
2010\Projects\CatalogService\CatalogService\CatalogService.svc.cs 91 25 CatalogService
I should tell you what the definition of the CatalogResults is that I want to return:
[DataContract]
public class CatalogResults
{
CatalogEntry[] _results;
[DataMember]
public CatalogEntry[] results
{
get { return _results; }
set { _results = value; }
}
}
My mind is dull today, apologies to all. You are being helpful. The end result is going to be serialized by WCF to a JSON structure, I need the array wrapped in a object with some information about size, etc.
Since .NET 3.0 you can use object initializer like shown below:
var catalogResults = new CatalogResults
{
results = context.Viewbostons
.Select(it => new CatalogEntry
{
idx = it.Idx,
product = it.Product,
...
})
.ToArray()
};
So if this is only one place where you are using CatalogEntry property setters - make all properties read-only so CatalogEntry will be immutable.
MSDN, Object initializer:
Object initializers let you assign values to any accessible fields or properties of an
object at creation time without having to explicitly invoke a constructor.
The trick here is to create a IQueryable, and then take the FirstOrDefault() value as your response (if you want a single response) or ToArray() (if you want an array). The error you are getting (Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a collection initializer because it does not implement 'System.Collections.IEnumerable') is because you're trying to create an IEnumerable within the CatalogEntry object (by referencing the item variable).
var response = (from item in context.Viewbostons
select new CatalogEntry()
{
idx = item.Idx,
product = item.Product,
size = (long)item.SizeBytes,
...
}).ToArray();
You don't have to create anonymous types in a Linq select. You can specify your real type.
var query = context.Viewbostons.Select( it =>
new CatalogEntry
{
idx = it.idx,
... etc
});
This should work:
var query = from it in context.Viewbostons
select new CatalogEntry()
{
// ...
};
My Db column in a string (varchar) and i need to assign it to a int value.
I am using linq to query.Though the code compiles am getting an error at the run time .
Thanks in advance.
PFB my query :
var vlauesCap = from plan in entities.PA_RTM_CAP_Group
select new Business.PartnerProfile.LookUp
{
Id =Convert.ToInt32(plan.cap_group_code),
//(Int32)plan.cap_group_code,
Value = plan.cap_group_name
};
return vlauesCap.ToList();
The EF provider does not know how to translate Convert.ToInt() into SQL it can run against the database. Instead of doing the conversion on the server, you can pull the results back and do the conversion using linq to objects:
// the ToList() here causes the query to be executed on the server and
// the results are returned in a list of anonymous objects
var results = (from plan in entities.PA_RTM_CAP_Group
select new
{
Code = plan.cap_group_code,
Name = plan.cap_group_name
}).ToList();
// the conversion can now be done here using Linq to Objects
var vlauesCap = from r in results
select new Business.PartnerProfile.LookUp
{
Id = Convert.ToInt32(r.Code),
Value = r.Name
};
return vlauesCap.ToList();
You can't do this directly, what you can do is declare a private variable to handle your "mapped" value, and expose the unmapped property...
[Column(Name = "cap_group_code", Storage = "m_cap_group_code")]
private string m_cap_group_code;
public int cap_group_code {
get
{
return Int32.Parse(m_cap_group_code);
}
set
{
m_cap_group_code = value.ToString();
}
}
Try this:
var vlauesCap = from plan in entities.PA_RTM_CAP_Group
select new Business.PartnerProfile.LookUp
{
Id =Convert.ToInt32(plan.cap_group_code),
Convert.ToInt32(plan.cap_group_code),
Value = plan.cap_group_name
};
return vlauesCap.ToList();
Why aren't you using casting for such a purpose, which is a more effective way of achieving this.
Just replace Convert.ToInt32(plan.cap_group_code) with (int)plan.cap_group_code
Do remember, there should be a value in the string and is int, else it will show Exception. If you are not sure about it, then you can further expand the casting to use null coalesciting operator