use linq to query dynamic object - c#

I dynamically set the type of an object
Then I want to query that object
int id = 123;
dynamic b =
Convert.ChangeType(dataToCompareTo, Type.GetType(tableName));
var values = (from item in (b)
where item.Id == id
select item).FirstOrDefault();
Linq will not allow me to do this ("query expressions with source type of dynamic [..] are not allowed"). I do not know the object type before runtime.

dynamic is the wrong thing to use here. ChangeType has a return type of object. It is not possible for the compiler to know at compile time what the type will be. If you define b as var the compiler will consider b to be an object and know nothing more about it.
Your LINQ expression seems to be expecting a particular type that implements IEnumerable and perhaps even an IEnumerable<SomeType>. In which case you would have to cast it to those types:
int id = 123;
var b =
Convert.ChangeType(dataToCompareTo, Type.GetType(tableName));
IEnumerable<SomeType> c = b as IEnumerable<SomeType>;
if (c == null)
{
///this is where you handle the objects that aren't what you need them to be for the linq expression below
}
else
{
var values = (from item in (c)
where item.Id == id
select item).FirstOrDefault();
}

If you want to use dynamic - you can do it here. Suppose you know that your b variable is list of some type which has Id property but you don't know which, and for whatever reason cannot use interface:
public class SomethingWithId {
public int Id { get; set; }
}
// you have no idea what that is at runtime
object something = new List<SomethingWithId>() {new SomethingWithId() {Id = id}};
Then you can use dynamic like this:
object something = new List<SomethingWithId>() {new SomethingWithId() {Id = id}};
// cast to `IEnumerable<dynamic>`, this will always compile
// but of course might fail at runtime, as always with dynamic
// in your case that is (IEnumerable<dynamic>) Convert.ChangeType(dataToCompareTo, Type.GetType(tableName));
var b = (IEnumerable<dynamic>) something;
// run your query
var values = (from item in b
where item.Id == id
select item).FirstOrDefault();
That said - don't get used to do such things in C# - it's strongly typed languge and you should not ignore benefits provided by that.

Related

Is it possible to remove columns in select query

As the question suggests I want to remove the columns from a select query where in that column are empty.
var query = from a in ...
select new
{
A =(decimal?)null,
B =(decimal?)null,
C = a.Amount1
};
var query2 = from b in ...
select new
{
A = b.Amount2,
B = b.Amount3,
C = (decimal?)null
};
var query3 = query.Concat(query2);
Output:
query3=[0]{A=null, B=null, C=100.00}
[1]{A=100.00, B=50.25, C=null}
Expected Result:
query3=[0]{C=100.00}
[1]{A=100.00, B=50.25}
You can't do this. The result set has to contain items of the same type and even if fields are null they still have to be there.
You could not show them in your UI, but exactly how you do that will depend on the UI.
You can't. A class has a predefined set of fields (not to speak about ExpandoObject which has some compiler tricks going on). This is the same for anonymous type, which you use.
You can't just hide or remove fields which are not filled. What if you iterate over the instances and try to retrieve item.C, which was null and thus removed? That would normally give you a compiler error. How would .NET resolve that?
The only other thing you can do is put in two different types in your list (a list of objects, so untyped), a very bad idea in my opinion. Keep it like this. You could add an indicator which type the row is, to be able to test it easily.
So:
select new
{
Type = "A", // or "B"
A =(decimal?)null,
B =(decimal?)null,
C = a.Amount1
};
A LINQ query typically outputs objects of a common type, so each object has to have the same base type (and the columns associated. The only way to concatenate objects of different types is to cast them to object:
var query = from a in ...
select new
{
C = a.Amount1
};
var query2 = from b in ...
select new
{
A = b.Amount2,
B = b.Amount3,
};
var query3 = query.Cast<object>().Concat(query2.Cast<object>());
but since they're anonymous you'll have to use dynamic to access them since you won;t be able to cast back to the original type, so you'll end up with something like this:
Console.WriteLine(((dynamic)(query3[0])).C);
Console.WriteLine(((dynamic)(query3[1])).A);
or at best:
dynamic list = query3.ToList();
Console.WriteLine(list[0].C);
Console.WriteLine(list[1].A);
but in any case you'll lose compile-time type safety.

How to get the Id of the selectedvalue?

I have DropDownList with the following values:
ddl.SelectedValue = { Id = 234, Name = "ABC Name" }
How can I get the value of the Id?
I use WinForms and RadDropDownList
Try this one:
public int GetId(object obj)
{
var anon = new { Id = 0, Name = string.Empty };
var obj2 = MakeSameType(obj, anon);
return obj2.Id;
}
public static T MakeSameType<T>(object obj, T anonymous)
{
return (T)obj;
}
use it like:
int id = GetId(ddl.SelectedValue);
If it works, it is thanks to how the equivalent anonymous types are "condensed" in single types by the C# compiler.
Note that this solution is as brittle as you can have
If you add/remove/rename a property of the anonymous type, the GetId will break (you'll have to keep the var anon = new {...} perfectly aligned). If you move the method that creates the collection of anonymous types to another assembly it will break too (because only anonymous types inside the same assembly are "unified" by the compiler).
In general you shouldn't have anonymous types that "escape" a method. An anonymous type should remain in the method that it is defined. Assigning it directly as the DataSource of a control is asking for problems.
If you feel lazy and don't want to create a type for a key-value, use the Tuple:
var tuple = Tuple.Create(something, somethingelse, somethingstillelse);
var value1 = tuple.Item1;
var value2 = tuple.Item2;
var value3 = tuple.Item3;
and so on.
As your are using anonymous types, it gets little complicated. But, you can cast SelectedValue to dynamic, and exstract 'Id' from there:
dynamic selectedValue = ddl.SelectedValue;
int id = selectedValue.Id;
But i would recommend to declare your own class or struct for such cases.
I have changed the LINQ query
from:
var query = (from q in tableq where ...
select new {Id = q.Id, Name = q.Name});
to:
var query = (from q in tableq where ...
select q);
... and then change it to:
table1.Id = (ddl.SelectedValue as tableq).Id == null ? table1.Id : (ddl.SelectedValue as tableq).Id;

linq to sql select new keyword and assign column alias name

i wants to assign column alias to another column in linq to sql select new keyword my code is
var query=from d in db.tblAttributeDatas
select new
{
a=d.strValue,
b=a
};
but compiler give me error.
can not resolved symbol a
.
You cannot use alias that way.
You have to do it using let this way:
var query=from d in db.tblAttributeDatas
let str = d.strValue // hold value here
select new
{
a=str, // now assign here
b=str
};
Basically, you can't do this because of the nature of object initializers (which is: initializing objects using the object literal notation { ... }).
This simple line of code...
var x = new { a = 1, b = 2 };
...is executed in IL code as...
<>f__AnonymousType0<System.Int32,System.Int32>..ctor
So you see that the anonymous type is created having a two-parameter constructor. Suppose this constructor would be visible as...
class X
{
public X(int a, int b) { }
}
It's obvious you can't call this constructor by
var x = new X(1, a);
You must supply two values. One constructor argument can't "borrow" the value of the other argument.
assign the same value to b .. there is no harm..
var query = from d in db.tblAttributeDatas
select new
{
a = d.strValue,
b = d.strValue
};

How do I create a list object that contains a list of another object type using from within a query using linq and c#

I am trying to return a list of an object that contains another object list as a databmember using linq. I've tried the examples shown but I keep getting ad different error with each attempt. One of which is as follows: LINQ to Entities does not recognize the method 'System.Collections.Generic.List1[SunGard.Tools.Notifications.LinkVariable] ToList[LinkVariable](System.Collections.Generic.IEnumerable1[SunGard.Tools.Notifications.LinkVariable])' method, and this method cannot be translated into a store expression.
I have an object (AlertMessageReturn) that contains some string datamembers as well as a list aof another object (List). I have a class that defines the LinkVarible and a table that contains the values. My query looks like this:
AlertMessagesQuery = from alertMessage in this.context.AlertMessages
where alertMessage.UserId=UserId
select new AlertMessageReturn()
{ PAM_ShortMessage = alertMessage.PAM_ShortMessage,
PAM_LongMessage = alertMessage.PAM_LongMessage,
PAM_LongMessageRemote = alertMessage.PAM_LongMessageRemote,
LinkVariables = (from linkVariable in this.context.AlertMessageLinks
from user in this.context.AlertMessageUsers
where user.PAMU_PAM_ID == linkVariable.PAML_PAM_ID && user.PAMU_UserId == UserId
select new LinkVariable()
{
Name = linkVariable.PAML_SessionVariableName,
Value = linkVariable.PAML_SessionVariableValue
})
};
The error is related to the type returned for linkvariables.
Please help.
I changed the code as follows:
LinkDataQuery = from linkData in this.context.AlertMessageLinks
from user1 in this.context.AlertMessageUsers
where user1.PAMU_PAM_ID == linkData.PAML_PAM_ID && user1.PAMU_UserId == UserId
select new LinkData
{
Name = linkData.PAML_SessionVariableName,
Value = linkData.PAML_SessionVariableValue
};
var links = LinkDataQuery.ToList();
AlertMessagesQuery = from alertMessage in this.context.AlertMessages
where alertMessage.UserId=UserId
select new AlertMessageReturn()
{ PAM_ShortMessage = alertMessage.PAM_ShortMessage,
PAM_LongMessage = alertMessage.PAM_LongMessage,
PAM_LongMessageRemote = alertMessage.PAM_LongMessageRemote,
LinkVariables = links
};
var AlertMessages = AlertMessagesQuery.ToList(); // this is where the error point to
if (AlertMessages.Any())
{
return AlertMessages;
}
The error I now get is:System.NotSupportedException: Unable to create a constant value of type 'SunGard.Tools.Notifications.LinkData'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
The LINQ to SQL engine cannot turn your sub-query to generate the LinkVariables into SQL. More importantly, SQL cannot return nested data sets like that.
Any time you get a message of type 'cannot be translated into a store expression' it is an indicator that you are doing something with your linq that is attempting to be translated into other statements (usually SQL). For example, if you say
....select new MyObject
{
Id = Guid.Parse( passedIdentity ),
....
}
while this is a totally valid C# statement you will get an error that Guid.Parse cannot be handled by linq. If it is possible to move the variables into external variables that are used inside the query then it would work. So you would do...
string name = linkVariable.PAML_SessionVariableName;
string nValue = ....
....
select New LinkVariable
{
Name=name,
Value=nValue
};
Also ... you do not need the closing parens on the Select New statement.
While LINQ to SQL can bring back object heirarchies, it can't project into types that aren't part of the model. Instead of projecting into the AlertMessageReturn type, try projecting into an anonymous type in the IQueryable portion of the code. Once you're done structuring your database query, force the results to come back (using AsEnumerable) and then project that into your AlertMessageReturn type. It's more overhead, but does work. Alternatively, you can use something like AutoMapper to translate your anonymous type into the result types.
AlertMessagesQuery =
from alertMessage in this.context.AlertMessages
where alertMessage.UserId=UserId
select new
{
alertMessage.PAM_ShortMessage,
alertMessage.PAM_LongMessage,
alertMessage.PAM_LongMessageRemote,
LinkVariables = from linkVariable in this.context.AlertMessageLinks
from user in this.context.AlertMessageUsers
where user.PAMU_PAM_ID == linkVariable.PAML_PAM_ID && user.PAMU_UserId == UserId
select new
{
Name = linkVariable.PAML_SessionVariableName,
Value = linkVariable.PAML_SessionVariableValue
})
};
var alertMessageResults =
from message in AlertMessagesQuery.AsEnumerable()
select new AlertMessageResult
{
PAM_ShortMessage = mesage.PAM_ShortMessage,
PAM_LongMessage = message.PAM_LongMessage,
PAM_LongMessageRemote = message.PAM_LongMessageRemote,
LinkVariables = (from variable in message.LinkVariables
select new LinkVariable { Name=variable.Name, Value = variable.Value})
.ToList()
};
return alertMessageResults.ToList();

How to return Generic.List<Anonymoustype> from a function in C#

ASP.NET 3.5 C#
I am joining two tables using Linq.
Table names are MapAssets and ExitPoint.
In Database they are related with 'has a relationship'
I am writing a function in my BLL to return the joined table
public List<ExitPoints> GetExitPointDetailsByProjectID(int iProjectID)
{
ctx = new CoreDBDataContext();
var exitPointDetails = from ma in ctx.MapAssets
join ep in ctx.ExitPoints
on ma.MapAssetID equals ep.MapAssetID
where ma.ProjectID == iProjectID
select new
{
//would like to have data from both tables here
ctx.MapAssets,
ctx.ExitPoints
};
return exitPointDetails.ToList();
}
This obviuosly doesn't work. And I dont know what to return at all.
All constraint I have for the return is to be able to be bound to a gridview.
is this the correct way? Or else whats the correct way?
You can't, or better, the only way is to return them boxed in a List of object, but this hugely complicates things, because you can't cast them to any type (of course it's anonymous) and you can only access their properties through reflection....
In cases like that, I'd highly suggest you to create a custom class.
EDIT:
On a side note...
If you were using .net 4, things would be easier because you could returns dynamic Type instead of object (look at this link to see dynamic's simplifications), but I'd prefer to create a custom class anyway.
Have a look at how to return anonymous types from Method.
http://forums.asp.net/t/1387455.aspx.
Copying the code from the link.
object ReturnAnonymous()
{
return new { Name="Faisal", City="Chakwal" };
}
// Application entry-point
void Main()
{
object o = ReturnAnonymous();
// This call to 'Cast' method converts first parameter (object) to the
// same type as the type of second parameter - which is in this case
// anonymous type with 'Name' and 'City' properties
var typed = Cast(o, new { Name="", City="" });
Console.WriteLine("Name={0}, City={1}", typed.Name, typed.City);
}
// Cast method - thanks to type inference when calling methods it
// is possible to cast object to type without knowing the type name
T Cast<T>(object obj, T type)
{
return (T)obj;
}
You can use the method mentioned below to return List and
List<object> lstAnonymousTypes = GetExitPointDetailsByProjectID(1);
foreach(object o in lstAnonymousTypes)
{
//Change it accordingly
var typed = Cast(o, new { new MapAssets() , new ExitPoints() });
}
Hope this helps not tried.
You can't return an anonymous type, you can only use an anonymous type in the scope of the method it's in. You could need to create a new class with MapAssets/ExitPoints properties and select a new instance of that class.
You are trying to return List ExitPoints and List of MapAssets which is not possible because you are getting the output from both tables ie ExitPoints and MapAssets. And it is also not possible to return an anonymous type. So in order to retrun the query create a class name ExMapClass with properties that you need as output of the queries. Now after executing the linq query which you have written iterate it ie
create list of newly created class
list newclass = new list ();
foreach( var result in ctx )
{
instantiate the created class
obj.Property1 = var.MapAssets;
obj.Property2 = var.ExitPoints;
newclass.add(obj);
}
now retrun the list of newlycreated class.
hope you got it.
Do you have to bind to this object after you've created it? If not then you can create an "persistent AnonymousType" class that stores the values in a dictionary and returns the property values with a method like:
string lastName AnonType.GetValue<string>("LastName");
int age AnonType.GetValue<int>("Age");
Here is a link to an excellent example. The author also has an example where he creates the "AnonymousType" from a datatable.
I have worked on a variation of this where I provide the ability to query a list of "AnonymousType" with the following syntax:
// Here's the query
var dept13 = anonAgents.AsQueryable()
.Where(x => x.Has("Department", Compare.Equal, 13);
// Here is how the List is constructed
private static AnonymousType ProvisionAgent(string name, int department)
{
return AnonymousType.Create(new
{
Name = name,
Department = department
});
}
private List<AnonymousType> CreateAnonAgentList()
{
var anonAgents = new List<AnonymousType>();
// Dave and Cal are in Department 13
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Dan Jacobs", 13, 44)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Calvin Jones", 13, 60)));
// Leasing = Dept 45
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Stanley Schmidt", 45, 36)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Jeff Piper", 45, 32)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Stewart Blum", 45, 41)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Stuart Green", 45, 38)));
// HR = Dept 21
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Brian Perth", 21, 25)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Katherine McDonnel", 21, 23)));
return anonAgents;
}
Just use and ArrayList
public static ArrayList GetMembersItems(string ProjectGuid)
{
ArrayList items = new ArrayList();
items.AddRange(yourVariable
.Where(p => p.yourProperty == something)
.ToList());
return items;
}
wont this work ?
ctx = new CoreDBDataContext();
var exitPointDetails = from ma in ctx.MapAssets
join ep in ctx.ExitPoints
on ma.MapAssetID equals ep.MapAssetID
where ma.ProjectID == iProjectID
select Tuple.Create(ma, ep);
return exitPointDetails.ToList();

Categories

Resources