Unknown "System.Object" to "string" or XML - c#

I am using Entity Framework with
var result = db.Database.SqlQuery<object>(dynamicSQLString);
var res = result.ToList();
Where dynamicSQLString can be anything... can return a "count()", can be a select with a list of rows.... etc.... there is no way to match it with a known class type. So I thought of using "object".
I would like to know if this is the way to go, and if it is, how can I "convert" the result into a "string"...... ?
Is this even possible?
Update #1
var t1 = result.GetType(); //System.Data.Entity.Internal.InternalSqlQuery
var res = result.ToList();
var first = res.First();
var t2 = first.GetType(); // System.Object
If I do a count on "res" I get the expected number of rows, but I do NOT see a way to get the "property names" of this object/dynamic row, neither it's values.
Update #2
I've found a "similar" example, but in there the person knows exactly the parameters/types the select will return.
http://www.codeproject.com/Articles/206416/Use-dynamic-type-in-Entity-Framework-4-1-SqlQuery

you can't convert the result into string unless your SQL query
(in this case dynamicSQLString)
return premitive primitive such as
"select name from customers" that return a string result for each row in database

You could use the dynamic type instead:
http://msdn.microsoft.com/en-us/library/dd264736.aspx
However you will need to do some casting on it before you can put it into a list.

Related

C# - Cant convert var to List

This code snippet returns me an error,
public List<auto> autoSelect()
{
return autoSelect(DateTime.Today);
}
public List<auto> autoSelect(DateTime date)
{
var onderhoudAuto = (from onderhoud in db.onderhouds
where onderhoud.uitvoerdatum != DateTime.Today
select onderhoud)
.FirstOrDefault();
List<string> autos = (from auto in db.autos
where auto.autoId.Equals(onderhoudAuto)
select auto)
.FirstOrDefault();
return autos;
}
I tried convert the var to a list with .ToList(); although this doesn't work. Does anyone have any suggestions?
I tried convert the var to a list
No, you do not. var is not actually a data type - it is resolved by the compiler. A tooltip should show you the real type.
Your problem is different:
Looking at your code, we can see:
The method autoSelect signature states that the return type is List<auto>
public List<auto> autoSelect(DateTime date)
The variable autos type is List<string>
List<string> autos = [...etc...]
return autos;
You return autos, but it is not possible to return a List<string> when a List<auto> is expected.
So it has nothing to do with var - it is simply you selecting as single property and returning a list of strings, but that is not the type the method is supposed to return.
If you use FirstOrDefault() after your linq query, you are saying you want the first element (or the default -usually null- for the datatype if none matches) in the LINQ query, not a list of elements.
If you want a list of elements, use ToList() on the linq query, not try to convert a single entity to a list.
If you, for some reason, want a list of a single entity, then create a list (with new List<type>()) and then add your entity (of the same type as your list) to the list.

Expression to get LINQ with Contains to EF for SQL IN() where on entities child's property equals value

I have a simple need to filter all parents out of the returned collection where there is no match on a field, that is called by name from a string, doesn't match a value presented. What I am after is if parent object has child object, and that child objects property "foo"(called by string) doesn't or does equal a value bar, the parent object is filtered from the collection appropriately.
Here is my linq ef call
var field = "bar";
var values = new List<string>{"foo","fuYu"};
var dataPage = _aim_context.ae_s_bld_c.AsNoTracking();
var result = dataPage.Where(x =>
DbHelper.byPropertyContains(x.udfs, field, values)
);
// NOTE `udfs` is a ONE-to-ONE with `ae_s_bld_c`
What I am looking to see is something like the SQL of
SELECT [m].[id],[m.udfs].[bar],
FROM [dbo].[ae_s_bld_c] AS [m]
INNER JOIN [dbo].[ae_s_bld_c_udf] AS [m.udfs]
ON ([m].[multitenant_id] = [m.udfs].[multitenant_id])
WHERE ([m].[multitenant_id] = 1.0)
AND ([m.udfs].[bar] IN ('foo','fuYu')) --< Goal line
The way I have approached this was to get an expression set up to take the List<string> and make the SQL. I have read near 50 articles and SO posts, but have not figured out exactly why I am not getting this just yet as everyone seems to have different ideas, and most are not in line with dotnet core 2.1+ it seems.
Here is what I am sitting at currently after many many iterations. NOTE: it is a little different from what I am after as I am giving my current trail.
My current context linq try
//...
dataPage = dataPage.Where(DbHelper.byPropertyContains<ae_s_bld_c>("udfs", field, values));
//...
I think it would be better if it was like the first example I put up, but that was what I have landed on since I have had a time lining it up with x=>x.udfs, both as x=> funName(x.udfs) and x=> x.udfs.funName()
My static method to build the expression
public static class DbHelper
{
public static Expression<Func<T, bool>> byPropertyContains<T>(string node, string field, List<string> value) {
//trying to take parent item and get it's property by string name because
// doing the function in linq like x=>x.udfs was not working right
// but that is the prefered I think
var property_parameter = Expression.Parameter(typeof(T), "x");
var property = Expression.PropertyOrField(property_parameter, node);
var selector_parameter = Expression.Parameter(property.Type, "y");
var selector = Expression.PropertyOrField(selector_parameter, field);
var methodInfo = typeof(List<string>).GetMethod("Contains", new Type[] {
typeof(string)
});
var list = Expression.Constant(value, typeof(List<string>));
var body = Expression.Call(methodInfo, list, selector);
return Expression.Lambda<Func<T, bool>>(body, selector_parameter);
}
}
Update
Per the request of #NetMage I have tried to work backwards with LINQpad. I think I am close but it is hard to tell with teh output. I am putting it up here for reference. To be clear, the property name of the child will be a string of the name. The best outcome is I could have a name like udfs.foo where I can test on any level if the values contain by string name, but really ok with it starting here,
var result = dataPage.Where(x =>
DbHelper.byPropertyContains(x.udfs, field, values)
);
Let start from here. You need an equivalent of something like this
var result = dataPage.Where(x => values.Contains(x.udfs.{field}));
where field is a string returning property dynamically specified by name.
In EF Core you don't even need to deal with building expresions by hand, because EF Core provides a special SQL translatable function for accessing simple properties by name called EF.Property.
With that method the solution is simple as that:
var result = dataPage
.Where(x => values.Contains(EF.Property<string>(x.udfs, field)));

Linq converting implicitly to type

Hi I have following method with linq statement in it.
public prO Getproject(int id)
{
var tt = (from c in db.pdi
where c.id==id
select new prO
{
name = c.p.name,
pr_id = c.p.pr_id,
re = c.p.re
});
return tt;
}
The above method returns one value of tt. However I keep getting intelicense error
(local variable) IQueryable<prO>tt
Error:
cannot implicitly convert system.linq.iqueryable to prO
Please let me know how to this error. Thanks
You are returning a collection with your query.
Since you want only one item change your query to:
public prO Getproject(int id)
{
var tt = (from c in db.pdi
where c.id==id
select new prO
{
name = c.p.name,
pr_id = c.p.pr_id,
re = c.p.re
//change here
}).FirstOrDefault();
return tt;
}
The error tells you the following: Your method has a return type of prO, but your query doe not return this type. You are nowhere defining, that you are returning excatly one item of prO. As far as the compiler is concerned, there could be 1000 items with a matching Id.
EDIT:
Based on Rawlings comments, it would be preferrable to use SingleOrDefault() instead. Both solutions are per se working, the difference however is that FirstOrDefault returns any amount of results, but takes only the first one, whereas Single or SingleOrDefault lets the query itself return exactly a single item.
Note, that if your query returns more than 1 result, FirstOrDefault displays the first result. SingleOrDefault will throw an exception.
Use return tt.FirstOrDefault();

Cannot convert type 'System.Linq.IQueryable<double?>' to 'float'

I have a table named InventoryItem which consists of columns ItemDescription and Item BalanceQty.I want to fetch the BalanceQty of the ItemName selected in a comboBox.For this,I created a method in my Data Access Layer And passed the string parameter representing the string value of ItemDescription to this method.This has been implemented using Entity Framework.This is how my code looks:
public float GetAvailableQty(string itemName)
{
float availableQty =(from table in context.InventoryItem
where table.ItemDescription == itemName
select table.BalanceQuantity);
return availableQty;
}
But it is giving me the following error-
Cannot convert type 'System.Linq.IQueryable' to 'float'
Where am I going wrong?
Probably you need this:
double availableQty =(from table in context.InventoryItem
where table.ItemDescription == itemName
select table.BalanceQuantity).Sum();
IQueriable returns an expression tree. The result of query like this is a rows set, and it can be materialized to IEnumerate by using of ToList() or implicitly by assigning to IEnumerable. But anyway it will be rows set, not a single value. If you sure the query returns the single one then use .Single() or SingleOrDefault. See other extension methods for IQueriable.
Otherwise, if you need an array then assign result to some IEnumerable variable.
Because your Linq returns an Iqueryable ...
Lets assume you have 3 rows with with an item with 3 different quatities (silly, i know, but think about other things that can have multiple values per item, like colors for a paint). Your linq will return the three quantities, and you're assuming it's a number
You could use First or FirstOrDefault to fetch the first item, or the default value for that object.
In your case, it shouldn't matter, but you should realize how Linq works and what it returns ...
Another example:
let's assume : List numbers = {1,2,3,4,5,6} (let's assume they are ints).
and you do : var small_numbers = numbers.Where(x => x<4)
What you get is something you can then query like: foreach (var small in small_numbers) {...}). The result is not an int.
You could take the first, last, and indeed, that would be an int. But what you get is a collection. so, even if you do: var one_result = numbers.Where(x => x<2), one_result is not an int.

Database.Query return type should be IEnumerable<dynamic>

I need help to understand this thing. Why in the following code the variables "ejes" and "habilidades" are resolved as "dynamic" and the third as IEnumerable<dynamic>. This is affecting the code that runs next, an exception appears when I try to invoke the extension method "Count()" because "ejes" and "habilidades" are not IEnumerable. They are the result of the same method "Database.Query".
Here is the snippet:
var db = Database.Open("froned");
db.Execute("begin transaction");
try
{
var asignacion = db.QuerySingle("select * from asignacion_avanza where id_asignacion = #0", id_asignacion);
var ejes = db.Query(String.Format(#"
select id_eje
from asignatura_eje_nivel
where id_nivel = {0}
and id_asignatura = {1}",
asignacion.id_nivel,
asignacion.id_asignatura));
var habilidades = db.Query(String.Format(#"
select id_habilidad
from asignatura_habilidad_nivel
where id_nivel = {0}
and id_asignatura = {1}",
asignacion.id_nivel,
asignacion.id_asignatura));
var dificultades = db.Query("select id_dificultad from dificultad");
var c_dif = dificultades.Count();
var c_eje = ejes.Count();
var c_habilidades = habilidades.Count();
I put an Image of the debugger to show the runtime type of the variables.
asignacion.id_nivel and asignacion.id_asignatura are dynamic types.
When you pass a dynamic type into any method as an argument, the return type of the method becomes dynamic instead of whatever MSDN says it is. You cannot use extension methods on dynamic types. Count() is an extension method on Enumerable. That's why you get the exception.
There are two ways to solve the problem and revert the return type to Enumerable. The first is to define it explicitly:
IEnumerable<dynamic> data = db.Query(someSQL, parameterValue);
and the other is to cast the parameter to a non-dynamic type:
var data = db.Query(someSQL, (string)parameterValue);
And as Knox points out, you must use parameters rather than string.Format.
The difference is debugger is due to dificultades has already evaluated
(var c_dif = dificultades.Count();).
Other two variables is not evaluated yet (linq deferred).
So debugger knows more about dificultades.
Are you sure that habilidades and the other one have data? I think it might be that db.Query is returning a null, meaning no rows returned, and then habilidades.Count can't execute because null doesn't have an object to execute against. One way to test this outside the debugger is to do a db.QueryValue( "Select Count(*) from ...") and see if you're getting zero rows returned.
By the way, the database functions in C# build in the variable handling in a slightly shorter way than you have. You can write
var ejes = db.Query( #"
Select *
From asign
Where id_nivel = #0",
asignacion.id_nivel );
This technique is called parameterized SQL. I'm only showing one parameter, but you will need more. The #0, #1, #2, and so forth get replaced just like in a String.Format.

Categories