Linq Specified cast is not valid - c#

I have checked lots of posts having this error but none had this particular problem.
(Also I am new to C sharp have been a java dev)
I am getting an exception as
System.InvalidCastException was caught
on the table2.Field("MEME_CK") line below in the code snippet.
There are about 3K rows in the table2, I couldn't find a way to avoid wrong casting for line table2.Field("MEME_CK")
Data can either be null, not present, valid or invalid. So I tried using nullable operator on the generic parameter cast. Also saw there is DBNull class that can possibly represent non existent value.
Is there a way to preprocess column data before doing "equals test" or joining in the code below ?
How can I avoid casting even after using nullable type?
Following code basically do a join on two data tables based on MemberID i.e. MEME_CK or MemeCk and creates new object with CapHeadID, MemeCk etc as fields.
var query =
(from table1 in searchResult.AsEnumerable()
join table2 in memberInfo.AsEnumerable()
on table1.Field<decimal?>("MemeCk") equals
table2.Field<decimal?>("MEME_CK")
select new
{
CapHeadID = table1.Field<decimal>("CapHeadID"),
MemeCk = table1.Field<decimal>("MemeCk"),
Suffix = table2.Field<decimal>("MEME_SFX"),
Suscriber = table2.Field<string>("SBSB_ID"),
BusinessArea = table2.Field<string>("TEAM"),
MemberName = table2.Field<string>("MemberName"),
WorkTypeName = table1.Field<string>("WrkName"),
SSN = table2.Field<string>("MEME_SSN"),
AssignedUser = table1.Field<string>("AssignedUser")
}).Distinct().OrderBy(a => (a.Suscriber.IsNotNil() ?
a.Suscriber : "")).Take(3000);

You're using AsEnumerable to convert the queries away from IQueryable... basically this means LINQ won't try to generate SQL code for the join, and the join will be done in C#.
With that in mind, you could try just get them as objects - like this:
from table1 in searchResult.AsEnumerable()
join table2 in memberInfo.AsEnumerable()
on table1.Field<object>("MemeCk") equals
table2.Field<object>("MEME_CK")
select new...
I'm not sure if that will work, but it might do

Related

How to create Regex to validate logical AND OR operators in string [duplicate]

I am looking for a query validator in C#, which allows me to parse the SQL text from a textbox and verify whether it's correct or not before sending it for execution (MS SQL or DB2 queries).
If you want to validate SQL syntax without the use of a database, the TSql100Parser class will do well for this situation.
Disclaimer, code borrowed from this post here Code to validate SQL Scripts
Pretty straightforward to use though. If it returns null, then there were no errors in parsing it.
using Microsoft.Data.Schema.ScriptDom;
using Microsoft.Data.Schema.ScriptDom.Sql;
public class SqlParser
{
public List<string> Parse(string sql)
{
TSql100Parser parser = new TSql100Parser(false);
IScriptFragment fragment;
IList<ParseError> errors;
fragment = parser.Parse(new StringReader(sql), out errors);
if (errors != null && errors.Count > 0)
{
List<string> errorList = new List<string>();
foreach (var error in errors)
{
errorList.Add(error.Message);
}
return errorList;
}
return null;
}
}
Set your query to sql with this hint:
set PARSEONLY on
It just checks your query and returns, like this:
set PARSEONLY on
select * from tablea
Returns no exception.
While
set PARSEONLY on
select * f rom tablea
returns
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'f'.
If you would like to validate/parse just a SELECT statement, regardless of how "heavy-duty" that select statement is, I found out that the best and fastest way to validate a select statement is the following:
- in your code create 2 select statements (strings) such as:
1) Your valid select statement: SELECT * FROM HUGE_TABLE JOIN MULTIPLE_TABLES WHERE <<Condition>>
2) Create a similar select statement such as SELECT TOP 1 * FROM HUGE_TABLE JOIN MULTIPLE_TABLES WHERE <<Condition>>
- Parse/Validate just the second one, regardless of how many joins you have in there, it will parse it in milliseconds, such as:
SqlCommand sqlParse = new SqlCommand(ParseSelectStatement, sqlConn);
try
{
sqlConn.Open();
sqlParse.ExecuteNonQuery()
}
Hope it helps! Cheers!
I think this is what you are looking for. http://www.codeproject.com/KB/database/sqlvalidator.aspx

SQL query using ISNULL

I'm writing the following SQL query using the TableAdapter Query Configuration Wizard in Visual Studio.
SELECT COUNT(*) AS census
FROM Inventory INNER JOIN Taxonomy ON Inventory.GlobalID = Taxonomy.GlobalID
WHERE (Inventory.Institution = #institution) AND (Inventory.Year = #year) AND
(Inventory.Nending > 0)
I'm trying to add the following criteria to the WHERE clause:
(Taxonomy.Class = ISNULL(#class, Taxonomy.Class))
so that either
1) only rows that match the #class input parameter are returned or
2) all rows are returned regardless of their TaxonomyGlobal.Class value.
When I add this statement to the query my C# code that calls the query throws a System.ArgumentNullException error and states the #class value cannot be null.
Any help on how to add this criterion to the WHERE clause would be appreciated.
C# code:
namespace CollectionMetrics
{
class DatabaseQueries
{
QueryDataSetTableAdapters.InventoryTableAdapter queryAdapter =
new QueryDataSetTableAdapters.InventoryTableAdapter();
public void CensusQuery(string institution, short year, string xclass)
{
int census = 0;
string localClass = xclass;
if (xclass == "All Classes") localClass = null;
census = (int)queryAdapter.CensusBySpecies(localClass, institution, year);
censusOutput.Add(census);
}
}
}
SQL:
(#class IS NULL OR Taxonomy.Class = #class)
Since you are using TableAdapter, you will need to edit the field to allow nulls:
https://msdn.microsoft.com/en-us/library/ms233762.aspx
Setting the AllowDbNull Property
To enable a query to accept null values In the Dataset Designer,
select the TableAdapter query that needs to accept null parameter
values. Select Parameters in the Properties window and click the
ellipsis (…) button to open the Parameters Collection Editor. Select
the parameter that allows null values and set the AllowDbNull property
to true.
If you are using SqlParameters:
C#
var param = new SqlParameter("#class", (object) classVariable ?? DBNull.Value);
Replace classVariable with the name of the variable you are using in your code to set the value for the #class SqlParameter. The cast to object is required because the variable does not have the same type as DBNull.
I once tried doing what you're trying to do, thinking this was a nifty way to ignore parameters that weren't passed from the front end (and therefore were NULL).
But then I learned that using ISNULL() in the WHERE clause like this prevents indexes from being used, making your query much SLOWER than if you used:
WHERE (Taxonomy.Class = #Class OR #Class IS NULL)
Unintuitive, I admit; the way you're trying looks like it would be cleaner and therefore faster, but for SQL performance, the most important thing is using available indexes, and so it turns out the A OR B approach is actually faster than the ISNULL() approach you want to use.
As to why you're getting an error, it's got to be something the wizard is enforcing. If you tried your query purely in SQL (using SSMS), it would allow it. UNLESS your query is actually in a stored procedure and #Class is a required parameter.

The data reader is incompatible with the specified Entity Framework

I have a method that will return the bare min results from a sproc to fill a select menu. When I want the bare min results I pass bool getMin = true to the sproc, and when I want the complete record I pass bool getMin = false.
This is causing the Entity FrameWork error of "The data reader is incompatible with the specified"
The most relevant portion of the error
{"Message":"An error has occurred.","ExceptionMessage":"The data reader is incompatible with the specified 'CatalogModel.proc_GetFramingSystems_Result'. A member of the type, 'FrameType', does not have a corresponding column in the data reader with the same name.","ExceptionType":"System.Data.EntityCommandExecutionException",
Obviously the error is telling me that when the data reader attempted to set the property 'FrameType' that is was not in the query results.
Now I understand the error, what I am wanting to know is that am I goning to have t split up this sql sproc into two sprocs or is there a work around for this?
My function below
public static IEnumerable<IFramingSystem> GetFramingSystems(int brandID, string frameType, string glazeMethod, bool getMin)
{
using (CatalogEntities db = new CatalogEntities())
{
return db.proc_GetFramingSystems(brandID, frameType, glazeMethod, getMin).ToList<IFramingSystem>();
};
}
My TSQL below
ALTER proc [Catelog].[proc_GetFramingSystems]
#BrandID INT,
#FrameType VARCHAR(26),
#GlazeMethod VARCHAR(7) ='Inside',
#getMin BIT = 0
as
BEGIN
SET NOCOUNT ON;
IF #getMin =0
BEGIN
SELECT c.ID,c.Name,c.Descr,c.FrameType,c.isSubFrame,
c.GlassThickness,c.GlassPosition,c.GlazingMethod,c.SillProfile
from Catelog.Component c
WHERE c.MyType ='Frame'
AND c.FrameType = #FrameType
AND c.GlazingMethod = #GlazeMethod
AND c.ID IN(
SELECT cp.ComponentID FROM Catelog.Part p JOIN
Catelog.ComponentPart cp ON p.ID = cp.PartID
WHERE p.BrandID = #BrandID
)
ORDER BY c.Name
END
ELSE
SELECT c.ID,c.Name,c.Descr
from Catelog.Component c
WHERE c.MyType ='Frame'
AND c.FrameType = #FrameType
AND c.GlazingMethod = #GlazeMethod
AND c.ID IN(
SELECT cp.ComponentID FROM Catelog.Part p JOIN
Catelog.ComponentPart cp ON p.ID = cp.PartID
WHERE p.BrandID = #BrandID
)
ORDER BY c.Name
SET NOCOUNT OFF;
END;
To me it seems that both branches of the IF return different data, the first branch returns 9 columns where the second - only three. I believe the EF can't reflect the IFramingSystem from the latter. Specifically, the column FrameType (and 5 other columns) are obviously missing:
...
SELECT c.ID,c.Name,c.Descr <- where are the remaining columns
from Catelog.Component c
...
I understand this is an old post; but, I wanted to share what I learned tonight about this. What I found that the 'most relevant portion of the error message is stating' is this.
db.proc_GetFramingSystems(brandID, frameType, glazeMethod, getMin).ToList<IFramingSystem>();
is expecting a column to be returned from the stored procedure with the alias of 'FrameType'.
I ran into this when I created a POCO (plain old clr object) class of my table with more programmer friendly names. Instead of a strongly typed name of say 'email_address', I wanted 'EmailAddy' and so forth. I created a mapped class stating this among other mapped columns.
this.Property(t => t.EmailAddy).HasColumnName("email_address");
Although this is necessary for other parts of EF to work, the mapping class is not referenced when executing a db.SqlQuery.
So, when the code below executes
var a = new SqlParameter("#fshipno", shipno);
return _context.db.SqlQuery<EmailList>("exec spGetEmailAddy #fshipno", a).ToList();
It generated the same error except instead of 'FrameType', it mentioned 'EmailAddy'.
The fix... I had to alias the 'email_address' column in my stored procedure to 'EmailAddy' to get it to map the returned dataset to my POCO.
EDIT: I have found that this only works if your method is returning an IEnumerable:
public IEnumerable<myPOCO> GetMyPoco()
You will get the same error message if you are attempting to return a single POCO object.
public myPOCO GetMyPoco()
If you are inserting/deleting/updating (these are considered by EF as 'non-query'), and can be called by our code using
MyDbContext.Database.ExecuteSqlCommand(insert into Table (Col1,Col2) values (1,2));
But if are doing select query for a raw SQL statement, then use
MyDbContext.DbSet<Table_name>.SqlQuery(select * from table_name).ToList();
or
MyDbContext.Database.SqlQuery(select * from table_name).ToList();
()
The SqlQuery() function, in EF, for strange reasons, throw exception Insert/delete/update operation. (The exception thrown is "A member of the type, does not have a corresponding column in the data reader with the same name.") But it has actually performed operation if you open your Sql Management Studio and check for the entries.
FYI http://www.entityframeworktutorial.net/EntityFramework4.3/raw-sql-query-in-entity-framework.aspx

Oracle / ADO.NET - ORA: 00904 "Invalid Identifier" error when calling from C#

I'm trying to do a bog-standard select statement from an oracle database using ADO.NET, and getting the following:
Oracle.DataAccess.Client.OracleException : ORA-00904: : invalid identifier
The ADO code looks like this:
conn.Open();
var command = new OracleCommand(sql) {Connection = conn};
var result = command.ExecuteReader();
//do stuff with result
and the sql statement is
select pt.*
from print_table pt
left join business_table bt on bt.transaction_id = pt.transaction_id
Both columns are number(10). If I execute the same sql on the database directly, it's fine.
If I ditch the join:
select pt.*
from print_table pt
and run from ADO, it works.
Furthermore, if I change the sql to
select pt.*
from print_table pt, business_table bt
where pt.transaction_id = bt.transaction_id (+)
and run from ADO, it works. I'd rather not use this though (there's a lot more to the query in reality).
and, if I select named values, thus:
select pt.column1, pt.column2, pt.column3
from print_table pt
left join business_table bt on bt.transaction_id = pt.transaction_id
this, again, works fine.
Any suggestions very welcome.

Ambiguous Outer Join Error While Using OleDB to List all Stored Procedures and Queries

I have to document several MS Access 2007 databases, each with hundreds of macros queries, etc and I'd like to automate the process in C#. For every .mdb file, myfirst goal is to extract schema information (tables, forms, macros and query names and definitions).
I'm using the following code using OleDB to get a list of all available tables by the user:
private static List<String> getTableNames(OleDbConnection db)
{
List<String> tableList = new List<String>();
DataTable schemaTable;
try
{
object[] objArrRestrict = new object[] { null, null, null, "TABLE" };
schemaTable = db.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,objArrRestrict);
foreach(DataRow row in schemaTable.Rows) tableList.Add((String)row["TABLE_NAME"]);
}
catch(Exception e) {
Console.WriteLine(`"Table Name Querying Failed. Returning Empty List"`);
Console.WriteLine(e.Message);
}
return tableList;
}
For the columns I'm using a similar method simply feeding off the previous one like so:
object[] objArrRestrict = new object[] { null, null, tableName, null };
schemaCols = db.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, objArrRestrict);
foreach (DataRow row in schemaCols.Rows) tableList.Add((String)row["COLUMN_NAME"]);
I'm not so sure how to get the macro information (name and definition), but after some research I decided to use the following to get the query information.
object[] objArrRestrict = new object[] { null, null, null, null };
schemaCols = db.GetOleDbSchemaTable(OleDbSchemaGuid.Procedures, objArrRestrict);
However when I run the last bit of code, I get the the very vaguely worded error message:
The SQL statement could not be executed because it contains ambiguous outer joins. To force one of the joins to be performed first, create a separate query in your SQL statement.
After some more research I modified the getTableNames method to grab queries through the "VIEWS" restriction, but that only got the stored SELECT queries in the data base and I also need the stored INSERT, UPDATE and DELETE queries.
Finally, I'm now using the following code to query the MsysObjects table directly.
String cmdString;
OleDbCommand queries = new OleDbCommand(cmdString,db);
OleDbDataReader reader = queries.ExecuteReader();
Using the following two cmdStrings interchangeably:
SELECT MSysObjects.Name FROM MsysObjects WHERE (Left$([Name],1)<>"~") AND
(MSysObjects.Type)=5 ORDER BY MSysObjects.Name
or
SELECT Name FROM MSysObjects WHERE (Name Not Like ""MSys*"") AND (Type In (1,4,6)) ORDER BY Name
Again, both strings also induce the same "Ambiguous Outer Join" error.
I've read up a little bit on this type of error and I know the general recommendation is to break apart the original query into multiple queries but as I'm using library functions to get this schema data, I'm not sure how exactly to go about doing that. I've aready spent days researching this and I'm at my wit's end. If someone could help me out with this issue or point me toward some way to sidestep this roadblock I would really appreciate it.
What happens if you group it like this?
SELECT
Name
FROM
MSysObjects
WHERE
Name Not Like 'MSys*'
AND
Type In (1,4,6)
ORDER BY Name
or this one
SELECT
Name
FROM
MSysObjects
WHERE
(
(Name Not Like ""MSys*"")
AND
(Type In (1,4,6))
)
ORDER BY Name

Categories

Resources