Linq Select * from Table ExecuteQuery - c#

First let me start by saying that I don't have a complete understanding of Linq. I am trying to dynamically query a database, The first query uses LINQ-SQL which works fine, but the second dynamic call is what fails in run time
public void getTables()
{
foreach (var c in dc.GetTable<TableListing>())
{
List<TableData> res = tableBrowse(c.TableName);
}
}
public List<TableData> tableBrowse(string tablename)
{
string sql = "Select * from " + tablename;
var results = dc.ExecuteQuery<TableData>(sql);
return results.ToList();
}
public class TableData
{
public int Time { get; set; }
public string Value { get; set; }
}
I query the "master table" and this retrieves a list of tables to query. They all have the same structure, as defined in the class TableData. I get a runtime error about Specified cast is not valid. I'm not really looking for code as much as I am looking for what I am doing wrong and how to fix it. Thanks.

You might try decorating your class properties with ColumnAttributes, specifying the column name and type so that LINQ to SQL knows how to do the version of the column data to the properties. You may also need to set other attribute properties to make it work correctly. I would also specify the column names in the SQL instead of using *. Put the column names in the same order as your properties appear in the class as I believe that it processes the result values in the same order as the properties are defined. Not sure it this will work or not, but essentially you're recreating what the designer would do for you.
public List<TableData> tableBrowse(string tablename)
{
string sql = "Select [time], [value] from " + tablename;
var results = dc.ExecuteQuery<TableData>(sql);
return results.ToList();
}
public class TableData
{
[Column( Name="Time", DbType="DateTime NOT NULL", ... )]
public int Time { get; set; }
[Column( Name="Value", DbType="VARCHAR(255) NOT NULL", ... )]
public string Value { get; set; }
}

You aren't explicitly converting the return value from dc.ExecuteQuery<TableData>(sql) to the TableData type that you've defined. I expect that the ExecuteQuery is complaining because it doesn't know what the TableData type is.
The ExecuteQuery helper needs to return a DBML (LINQ-to-SQL generated) type as defined in your database.
But I would suggest that you don't go down this route. If you want to get records from a table, say Customers, just use content.Customers - the point of LINQ-to-SQL is that it already contains all these accessors to save you time.

Actually I found out what the problem was, I was missing a table definition. There was a third data type in one of the tables. Once I defined that table class and checked for the data type it worked fine. Sadly the compiler just didn't give that much information on just what was wrong.

Related

SQLiteConnection Query<Int> returns 0 but Query<Foo> returns correctly

First of all, I'm using Xamarin/C# with sqlite-net-pcl.
I create a table using SQLite.SQLiteConnection.CreateTable. T is one of my classes I can pass in, Here's an example:
public class Foo : IDatabaseItem
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Subject { get; set; }
public string Description { get; set; }
}
}
After inserting a record, I want to return the last key inserted. SQLiteConnection.Insert unfortunately returns the amount of rows inserted instead of the row inserted.
public int GetLastInsertedId()
{
return conn.Query<int>($"SELECT Max(Id) FROM {typeof(T).Name}").First();
}
The problem is the function above, it always returns 0. I've tried removing the .First to analyse the entire object it returns and it'll return an IEnumerable which correctly has the amount of rows in the DB within, but all of the results are 0.
Interestingly if I modify my function to return the original class it was created from and remove the "Max(Id", it works.
public Foo GetLastInsertedId()
{
return conn.Query<Foo>($"SELECT * FROM {typeof(T).Name}").First();
}
I believe I'm not referencing the column name correctly, I'd love to view the table to see what I'm working with but unfortunately the version of android I'm using doesn't appear to let you view an SQLite database (from Visual Studio).
I get that I can use Linq queries to quickly get at the data I want, but it feels like returning an entire object from the database is a bit bulky when all I want is the Id, especially as the database grows.
Any help would be appreciated, I'm sure I'm doing something daft...just can't suss out what.

Read object from c# database into classes directly

What I am trying to do is read a database, row by row, and use the data from each row to initialize an object of the type that data represents. In this case I am reading rows of the Device table and trying to create Device objects with that data. I saw this SO link:
and I tried this snippet:
using(var dc = new DataContext(connectionString))
{
List<Person> people = dc.ExecuteQuery(#"
SELECT Id, Name Address
FROM [People]
WHERE [Name] = {0}", name).ToList(); // some LINQ too
}
But it is telling me
The type arguments for this usage cannot be inferred from the usage
Is this in principal correct or should I be using the BondIO serializer/deserializer? as mentioned here
Also the order of the members in the object may not be the same as the order of the columns in the database, is this relevant?
Later that same day....
I now have a DBContext with all my database objects defined like this:
public class MyContext : DBContext
{
public dbSet<Device>{ get; set;}
etc...
}
And I now try to get object using this snippet:
using (var db = new MyContext(ConnectionString))
{
var res = db.Device.Find(ID);
}
However this gives an exception message
Could not load type 'System.Data.Entity.ModelConfiguration.Conventions.AttributeToColumnAnnotationConvention`2
I have checked the database and it should return 1 value based on the PrimaryKey ID that I am passing. Anybody have any hints what I'm still doing wrong.
You cannot, because ExecuteQuery is for executing statements, not for querying database. You should use SqlQuery instead
What you can do is, to create a new class with the properties you want to set in your query, means a simplified version of your query. In your case
public class Device
{
public int Id {get;set}
public string Name {get;set}
public string Address {get;set}
}
then use it as
var people = dc.ExecuteQuery<Device>(#"
SELECT Id, Name Address
FROM [People]
WHERE [Name] = {0}", name).ToList();

How to create dynamic Linq Select Expression with anonymous objects

Am using Entity Framework to run a query on a table. However, i need to get select columns only.
class MyEvent
{
public string Name { get; set; }
public int Id { get; set; }
virtual Stage EventStage { get; set; }
..... more columns .....
}
class Stage
{
public string Name { get; set; }
public string Location { get; set; }
..... more columns .....
}
I can write an IQueryable to return these as
dbContext.MyEvents
.Select(s =>
new {
Name = s.Name,
Id = s.Id,
EventStage = new
{
Name = s.EventStage.Name,
Id = s.EventStage.Id
}
}
)
.ToList();
This works as expected, giving me just those columns am interested in.
Now, I need to construct that 'Select' call dynamically using Expression tree, something like here.
How can I achieve that? Is it feasible to construct an anynomous object, like above, via expressions?
EDIT:
The use case for me is that I have a generic dB context class which takes a list of columns as strings to be fetched. In the past, we were returning all columns, ignoring that input list. So, now I need to dynamically generate the select statement to return only the required subset of columns, which can either be done via anonymous object or a dynamically created DTO.
Thanks
Maybe you can use something like the ToDynamic method from here:
https://gist.github.com/volak/20f453de023ff75edeb8
A possible usecase for this problem:
Let the user select the columns to display and query only those selected columns, so you don't query always the whole entity from the database.
Define a strongly typed object and return that. I would avoid using a dynamic object.
Note: you can't return an anonymous object.

Entity Framework: Executing a stored procedure that returns different columns and column data types

I am trying to execute a stored procedure this way:
var filterValues= context.Database.SqlQuery<FilterProcedureDTO>(
"[dbo].[sp_GetFilterValues] #FieldID", new SqlParameter("FieldID", filterID))
.ToList();
the issue is the filter values that come up have diffrent column name with each call as the user changes the filter on the view,though all come up as objects with an int column and string column,it seems they are bound to the specified model ie FilterProcedureDTO..which looks like
public class FilterProcedureDTO
{
public FilterProcedureDTO() {
//empty constructor
}
public int production_lineID { get; set; }
public string production_line_desc { get; set; }
}
so if the call produces taskID and task_desc this wont work anymore.
Another thing is some IDs are int32 and some are int16 so the code is not executing perfectly because of periodic exceptions
How can I get the stored procedure to return generic objects,just recognising the datatypes and not variable names too?
The SQLQuery method always attempts the column-to-property matching based on property name.
So you need to change your stored procedure so that it always returns the same name and datatype. You should be able to do that using aliases and casting in the sql.
Reference:
https://stackoverflow.com/a/9987939/150342

Why is my DbModelBuilder configuration ignored when mapping Entity from DbSet<T>.SqlQuery?

I have a DbModel configuration like so:
modelBuilder.Entity<WishlistLine>()
.HasKey(w => w.PersistenceKey)
.Property(w => w.PersistenceKey)
.HasColumnName("WishlistLineId");
I have a query run via the following two methods:
public IEnumerable<WishlistLine> FetchWishlistLinesUsingLogonName(string logonName)
{
return GetFromRawSql(#"
SELECT wl.* FROM WishlistLines wl
INNER JOIN Accounts a ON wl.AccountId = a.AccountId
LEFT JOIN Users u ON u.AccountId = a.AccountId
WHERE u.LogonName = #p0", logonName);
}
protected IEnumerable<TEntity> GetFromRawSql(string sqlQuery, params object[] parameters)
{
return _dbSet.SqlQuery(sqlQuery, parameters).ToList();
}
I can "save" WishlistLines into the database through EF without any problems. When I run this query though I get this error:
The data reader is incompatible with the specified 'DataAccessLayer.DatabaseContext.WishlistLine'. A member of the type, 'PersistenceKey', does not have a corresponding column in the data reader with the same name.
I understood that using DbSet<T>.SqlQuery() would map the returned data to the entities but it seems to be ignoring the DbModel configurations. Judging (guessing) from the error message the wrong data reader is being used.
so:
A) am I doing anything wrong?
B) is there a way to make use of EF's DbModel-aware entity mapper?
Indeed the column name mapping is ignored when you execute a raw SQL query. Here are two references: This pretty dissatisfying thread only for fun, but the following one with a serious answer from the EF team:
Quote from http://entityframework.codeplex.com/workitem/233:
The SqlQuery method is designed not to take any mapping into account,
including mapping that is applied using attributes. It simply matches
the column names from the results with property names in the object.
If the column names don't match you will need to use a column alias
(AS keyword in SQL Server) to rename the column in the results.
We agree that it would be useful to have the option to make SqlQuery
honor Column attributes so we're keeping this issue open and putting
it on our backlog for future consideration.
So, the only workaround seems to be an explicit AS alias instead of a * in your SQL query that specifies your property name as a column alias:
return GetFromRawSql(#"
SELECT wl.WishlistLineId AS PersistenceKey,
wl.SomeOtherColumn AS SomeOtherProperty,
...
..."
// ...
I found another solution that is quite clean. In my model, I have public properties with the nice names I want to use, and private properties with the exact same name as in the database, and return the private value in the getter of the public ones, like this:
public class KeywordsStatistic
{
public string Keyword { get { return lib_motcle; } }
public int NumActions { get { return nbrActions; } }
private string lib_motcle { get; set; }
private int nbrActions { get; set; }
}
Of course, this would need to be modified if the values need to be updated, but the principles are the same...
HTH

Categories

Resources