Consider the following code:
foreach (Type formType in allFormsToLoopThrough)
{
var nonPriorityForm = _context.Query(formType);
foreach (var nonpriority in nonPriorityForm)
{
var name = nonpriority.GetType().Name;
MyWorkAssignmentDTO form = new MyWorkAssignmentDTO
{
FormName = formType.Name
Id = nonpriority.Id
};
}
}
This snippet is looping thought a list of types.
Each type is taken from the list and passed to a Query function that returns an IQueryable - basically a list of records in a given table in a database that matches the type.
Then for each of the record sets that come back, I want to loop through those and from each create a new instance of MyWorkAssignmentDTO. I am only interested in a form name (which I can get from formType) but I cannot get nonpriority.Id
I know for sure that every nonpriority will have an Id once it is resolved in the loop.
What I can't do is implement this to work at run time.
Can anyone help?
I was able to use the dynamic keyword instead of var. While I lose compile time validation, this gets me over the line when I know for sure there will be an Id.
dynamic nonPriorityForm = _context.Query(formType);
Related
in my program, I use 4 stored procedures, depending on fields that were selected in the form.
ctx = new DataClassesDataContext();
items = (from prjs in ctx.sp_Select_Stuknummers(prjnr) select prjs).ToList();
or
ctx = new DataClassesDataContext();
items = (from prjs in ctx.sp_Select_Stuknummers_Scanner(prjnr, scanner) select prjs).ToList();
and so on ...
I use LINQ to SQL, and for each of these 4 queries, I have a different result class:
sp_Select_StuknummersResult
sp_Select_Stuknummers_ScannerResult
sp_Select_Stuknummers_Scanner_WPSResult
sp_Select_Stuknummers_StuknummerResult
they all have the same fields and definitions.
Now, when I iterate the result:
foreach (sp_Select_StuknummersResult x in items)
{
WPSitems ding = new WPSitems();
ding.ID = x.ID;
ding.Naam = x.Naam;
......
}
I need to pass the type to use (in this example: sp_Select_StuknummersResult )
Is there a way to either
A. easily convert to a new type, so that one can be used every time
or
B. dynamically set the type in the foreach loop ?
maybe there is even a C that I am not aware of...
Any help is highly appreciated !
By default, L2S auto-generates a separate type for each individual stored procedure. However, you can easily change that return type in the Linq-2-Sql Designer.
In the designer, click on the stored procedure. In the Properties window, there's an entry 'Return Type': change it from 'Auto-generated type' to the type you want.
If the stored procedure returns rows from an already mapped table, select that type in the drop-down. If not, you can manually add a class to the designer and configure that type to be returned from the stored procedure.
You can do this using generics/reflection.
public static WPSitems MapObjectWithIdenticalProperties<T>(T itemOfUnknownType) where T : new()
{
var inputType = typeof(T);
var outputType = typeof(WPSitems);
var outputItem = new WPSitems();
foreach (var inputProperty in inputType.GetProperties())
{
var matchingOutputProperty = outputType.GetProperties().FirstOrDefault(x => x.Name == inputProperty.Name);
if(matchingOutputProperty != null)
matchingOutputProperty.SetValue(outputItem, inputProperty.GetValue(itemOfUnknownType));
}
return outputItem;
}
The function above can be called like this:
var items = GetYourDataThatCanBeDifferentTypes();
var mappedItems = new List<WPSitems>();
foreach(var item in items)
mappedItems.add(MapObjectWithIdenticalProperties(item));
If I understand your problem correctly this might help you out:
1.) Create an interface for the result classes (e.g.) I_SP:
sp_Select_StuknummersResult
sp_Select_Stuknummers_ScannerResult
sp_Select_Stuknummers_Scanner_WPSResult
sp_Select_Stuknummers_StuknummerResult
add common variables and methods that you need into that interface.
2.) Make sure your items is List<I_SP>
3.) Create a generic method for your foreach loop
public void MyMethod<T>(List<I_SP> items) where T:I_SP {
foreach (var x in items.OfType<T>)
{
WPSitems ding = new WPSitems();
ding.ID = x.ID;
ding.Naam = x.Naam;
......
}
}
4.) Then just call this like this:
MyMethod<*sp_Select_StuknummersResult result class*>(items);
Hope it's clear enough.
This question already has answers here:
Dynamic Object Intellisense
(3 answers)
Closed 8 years ago.
My code is like this
var eventDocs = new List<dynamic>();
foreach (var node in eventtypeNode.GetDescendantNodes())
{
string files = node.GetProperty("document").Value;
eventDocs.Add(new { Id = node.Id, Name = node.Name, CreatedOn = node.CreateDate, Path = files });
}
This works good. Now I am trying to fetch the data out of this dynamic list
foreach (var eventDoc in eventDocs)
{
eventDoc.---- //nothing comes on intellisence
}
Nothing comes on IntelliSense? Am I doing anything wrong?
You won't get anything from Intellisense precisely because you've got a List<dynamic>. You're saying, "I don't know at compile-time what this list will contain. When I access members of the elements, just bind that dynamically at execution-time."
Given that you're deferring binding to execution time, why would you be surprised that Intellisense can't tell what will be in the list?
It looks to me like you should change your code to use a LINQ query to start with - then you can have a list with a known element type, which will be an anonymous type.
var eventDocs = eventtypeNode.GetDescendantsNodes()
.Select(node => new { Id = node.Id,
Name = node.Name,
CreatedOn = node.CreateDate,
Path = node.GetProperty("document").Value })
.ToList();
You cannot access dynamic members like this, try GetDynamicMemberNames() and GetMetaObject method
Intellisense will not show suggestions, since the data is dynamic, and it doesn't know what to show.
But you know what it contains. So just code and you'll be fine.
Also, you don't need dynamic objects here. Since what you want is well-defined just define your class with necessary properties and methods and then create the list:
List<YourClass> list = new List<YourClass>();
And then Intellisense will become intelligent enough to show the suggestions ;)
Hi i am trying to get to grips with Dapper.
My situation is i want to pull two values from a query into two separate strings. Im not sure if i am going about this in the correct way, but this is what i am doing:
string sql = #"Select type, name
FROM ZipData
WHERE Zip = #zip";
using (var multi = conn.QueryMultiple(sql, new { zip = zip }))
{
string result = multi.Read<string>().SingleOrDefault();
}
And i am getting Cannot access a disposed object. Object name: 'GridReader'. when trying to read the second string.The thing is it gets the first value correctly and has both the fields in in the reader i am trying to get. Im sure im misusing the api.
What am i doing wrong here? Ive googled but can find a specific example.
You are mis-using QueryMultiple. That is defined for compound SQL statements that return multiple result sets. Something like:
SELECT Foo FROM MyTable;
SELECT Bar FROM MyOtherTable;
On the other hand, you are trying to get two different columns from a single result set, so you should just use the normal Query method:
var result = conn.Query(sql, new { zip = zip }).Single();
var type = result.type;
var name = result.name;
Query returns an enumerable (because generally a query can return multiple rows). It appears that you only want one row, however, so we invoke .Single at the end to just get that row. From there, the return type is dynamic so you can simply refer to the properies implied by the columns in your SELECT statement: type and name.
I want the ability to grab an anonymous type from my view, that was established by the corresponding controller. According to this article, such an ability becomes possible in C# 4.0 with the 'dynamic' keyword. However, when I try to find an actual example I find answers ranging from it kinda 'is possible' to it kinda 'is not possible.'
In my case, I have a controller creating this:
XElement headings = XElement.Parse(part.TagList);
var items = from heading in headings.Descendants("heading")
select new {
name = heading.Attribute("name").Value,
tags = heading.Attribute("tags").Value,
content = shapeHelper.List() //This is a dynamic object!!!
}; //can I add 'as dynamic;' here????
In short it would be nice if, without a static type, my view could simply reach into the model like this:
#{
//Currently this next line returns an error saying that
//'object' contains no method 'Count'
int foo = Model.items.Count();
//This 'foreach' works.
foreach(dynamic lineItem in Model.items){
//But this does not work. Gives another "'object' has no definition for 'name'"
<p>#lineItem.name</p> }
}
Possible?
Not sure it's exactly what you're looking for, but you could always use the ViewBag:
Controller
ViewBag.Items = from heading in headings.Descendants("heading")
select new {
name = heading.Attribute("name").Value,
tags = heading.Attribute("tags").Value,
content = shapeHelper.List()
};
View
ViewBag.Items.First().content;
I need to loop through the properties of a custom object type that I'm getting back from the database and only show the columns that contain data.
This means I cannot simply bind the list of objects to the datagrid.
I don't want to loop through each object and see if the column is empty/null and determine in the UI to display it.
What I'm thinking is in my business layer before I send the object back I would send an IEnumerable back with only those columns that should be visible. Thus I was thinking of using Linq to Object to do this, but I'm not sure that would be very pretty.
Does anyone know of a solution that I could use without a ton of IF statements that I could do to check through a large object (30 or so columns) to determine what should be shown or not.
Foreach (CustomerData customerdata in Customers)
{
if (!customerdata.address.Equals(""))
{
dgvCustomerData.Column["Address"].visible = false;
}
//Continue checking other data columns...
}
I wish to avoid all of this in the UI and all the IFs...
I'm having a brain fart on this one can anyone help me?
Thanks
You could do the following to simplify it a bit
Action<T,string> del = (value,name) => {
if ( value.Equals("") ) {
dgvCustomerData.Column[name].Visible = false;
}
};
foreach ( var data in Customers ) {
del(data.address,"Address");
del(data.name, "Name");
...
}
Take a look at the .NET Reflection Libraries. You can use reflection to get ahold of all of an object's properties, and loop through them to find out if they are null or not. Then you could return a collection of KeyValuePair objects where Key = property name, and Value = true/false. You'd then use the keyvaluepairs to set column visibility...