Cast between Oracle Table field and Entity framework fails - visual-studio-2010

Within a WCF web service I make a query on a ORACLE 11g database and I use entity framework as model. The target field is of type Numeric, while in the entity framework is Int64.
When I try to update the field I get the following exception: The specified cast from a materialized 'System.Decimal' type to the 'System.Int64' type is not valid.
The method generating the error is below, in particular for the line within the else statement: result = _context.ExecuteStoreQuery(query).FirstOrDefault();
public string GetDatabaseTimestamp(Type timestampFieldType, string query)
{
object result;
if (timestampFieldType == typeof(string))
{
result = _context.ExecuteStoreQuery<string>(query).FirstOrDefault();
}
else
{
result = _context.ExecuteStoreQuery<long>(query).FirstOrDefault();
}
return result.ToString();
}
Would it be possible to define at the EF level a converter or something similar? The option of changing the Database is not feasible, therefore I have to edit code.

In The EF I already changed the type into decimal. Problem is that the query was executed directly on the Oracle database and this was generating the exception.
I solved the issue by using attributes for the target entity and changed the method into:
public string GetDatabaseTimestamp(Type timestampFieldType, string query)
{
object result;
if (timestampFieldType == typeof(string))
{
result = _context.ExecuteStoreQuery<string>(query).FirstOrDefault();
}
else if (timestampFieldType == typeof(decimal))
{
result = _context.ExecuteStoreQuery<decimal>(query).FirstOrDefault();
}
else
{
result = _context.ExecuteStoreQuery<long>(query).FirstOrDefault();
}
return result.ToString();
}
In this way the passed timestampFieldType is of type decimal and the proper cast is selected. This issue is due to different data types used for similar fields (as example Update fields) in the Oracle DB (legacy database).

Related

Web API OData custom query issue

I am new to Web API, Entity Framework and OData. I asked a similar question in another forum but haven't gotten a relevant response.
We have a OData compliant web api service for use in Salesforce. We have a custom complex query in Oracle that we need to expose.
I am not sure how to use a custom query like we want to also allow for odata parameter filtering to occur? ($filter, $top, $skip, etc) For example, when a $filter is used i want to apply that filter to the custom query and then send it back to the database to have it return the result set. How can i do this?
The issue i seem to have is that I can see the parameters as they come in but they are not translating to the query being passed to oracle. It seems that it will fire the query returning the full result set and then apply the parameters. This is very slow as the result set is very large.
I am hoping 2 figure out 2 things
1. How can i use custom sql and apply odata parameters to the underlying query?
2. When using EF or a custom query, how can i apply odata parameters to the query so that when the query is sent to the database that the $filter parameter, for example, is included in the query? I don't want the full result returned then apply the filter.
Can anyone give me some pointers on how to make this happen?
private static ODataValidationSettings _validationSettings = new ODataValidationSettings();
//public IHttpActionResult GetName()
//{ }
// GET: odata/ShareData
[ODataRoute("Orders")]
[EnableQuery(PageSize = 50)]
public IHttpActionResult GetOrders(ODataQueryOptions<Orders> queryOptions)
{
// validate the query.
try
{
queryOptions.Validate(_validationSettings);
}
catch (ODataException ex)
{
return BadRequest(ex.Message);
}
try
{
string connectionString = ConfigurationManager.ConnectionStrings["DNATestConnectionString"].ConnectionString;
var items = GetDataItems(connectionString);
return Ok<IEnumerable<Orders>>(items);
}
catch (Exception ex)
{
return StatusCode(HttpStatusCode.InternalServerError);
}
}
#region Load Data Methods
private static List<Orders> GetDataItems(string connectionString)
{
List<Orders> items = new List<Orders>();
using (OracleConnection con = new OracleConnection(connectionString))
{
con.Open();
using (OracleCommand cmd = con.CreateCommand())
{
cmd.CommandText = "select po_header_id, segment1, vendor_id, vendor_site_id from po_headers_all where vendor_id=4993";
using (OracleDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
items.Add(ToOrders(rdr));
}
}
}
return items;
}
private static Orders ToOrders(OracleDataReader rdr)
{
Orders data = new Orders();
data.VENDOR_ID = ToInt32(rdr, "VENDOR_ID");
data.VENDOR_SITE_ID = ToInt32(rdr, "VENDOR_SITE_ID");
data.PO_HEADER_ID = ToInt32(rdr, "PO_HEADER_ID");
data.SEGMENT1 = Convert.ToString(rdr["SEGMENT1"]);
return data;
}
private static int ToInt32(OracleDataReader rdr, string name)
{
int index = rdr.GetOrdinal(name);
return rdr.IsDBNull(index) ? 0 : Convert.ToInt32(rdr[index]);
}
#endregion
I don't think this is possible.
How can i use custom sql and apply odata parameters to the underlying query?
As far as I'm aware, you can't. The whole point of the OData library is that it needs to work off an IQueryable. By using custom SQL in a string like you have in your example, you can't combine it with the OData parameters that are being passed in.
One approach would be to have your custom SQL in a SQL view, then add the SQL view to your EF model in the same way as you would add a table - it will be represented as a DbSet just like tables are.
You can then get an IQueryable to represent the dataset and then apply the OData parameters as follows:
public IHttpActionResult GetOrders(ODataQueryOptions<OrdersView> queryOptions)
{
IQueryable<OrdersView> allData = // ... get the DbSet from entity framework...
// this will apply the OData query to the data set and only pull the data you want from the database
var filteredResults = queryOptions.ApplyTo(allData) as IQueryable<OrdersView>;
return Ok<IQueryable<OrdersView>>(filteredResults);
}

Cannot map raw SQL query to DataRow

I am trying to get IEnumerable from linq query below. What am I doing wrong?
IEnumerable<DataRow> results =
context.Database.SqlQuery<DataRow>("SELECT * FROM Customer").AsEnumerable();
DataRow class does not have default (parameterless) constructor, so you can't use it as query parameter type. There is no generic constraints on type parameter, and nothing mentioned on MSDN(!), but column map factory will throw exception if parameter type does not have default constructor:
The result type 'System.Data.DataRow' may not be abstract and must
include a default constructor.
Here is a code which throws this exception:
internal static CollectionColumnMap CreateColumnMapFromReaderAndClrType(
DbDataReader reader, Type type, MetadataWorkspace workspace)
{
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
ConstructorInfo constructor = type.GetConstructor(flags, (Binder) null, Type.EmptyTypes, (ParameterModifier[]) null);
if (type.IsAbstract || (ConstructorInfo) null == constructor && !type.IsValueType)
throw EntityUtil.InvalidOperation(InvalidTypeForStoreQuery((object) type));
// ...
}
BTW Mapping to DataRow makes no sense, even if it would have default public constructor. Because it is not simple primitive type and it does not have properties which match the names of columns returned from the query (yes, mapping uses properties only).
Correct usage of Linq will be
IEnumerable<Customer> results = context.Customers;
That will generate SELECT * FROM Customer query, and map query results to customer entities. If you really want to use raw SQL:
IEnumerable<Customer> results =
context.Database.SqlQuery<Customer>("SELECT * FROM Customers");
I think we were trying to solve the same problem (Google led me here, anyway). I am executing a raw SQL command through SqlQuery<TElement>(string sql, params object[] parameters and wanted to assert individual properties of the results returned from the query in a unit test.
I called the method:
var result = (db.SqlQuery<Customer>("select * from customers").First();
and verified the data it returned:
Assert.AreEqual("John", result.FirstName);
I defined a private class Customer inside my test class (unfortunately, I'm not using Entity Framework):
private class Customer
{
public string FirstName { get; set; }
}
The properties of Customer must match the column names returned in the SQL query, and they must be properties (not just variables of the Customer class. You don't have to create properties for all of the columns returned from the query.

How do I store a comma-separated list in Orchard CMS?

Using Orchard CMS, I am dealing with a record and a part proxy, but cannot figure out how to save it into the DB. In fact, I confess I don't even know how to get the items I'm trying to save into this paradigm. I was originally using enum's for choices:
MyEmum.cs:
public enum Choices { Choice1, Choice2, Choice3, Choice4 }
MyRecord.cs:
public virtual string MyProperty { get; set; }
MyPart.cs:
public IEnumerable<string> MyProperty
{
get
{
if (String.IsNullOrWhiteSpace(Record.MyProperty)) return new string[] { };
return Record
.MyProperty
.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)
.Select(r => r.Trim())
.Where(r => !String.IsNullOrEmpty(r));
}
set { Record.MyProperty = value == null ? null : String.Join(",", value); }
}
Now, in my service class, I tried something like:
public MyPart Create(MyPartRecord record)
{
MyPart part = Services.ContentManager.Create<MyPart>("My");
...
part.MyProperty = record.MyProperty; //getting error here
...
return part;
}
However, I am getting the following error: Cannot implicitly convert 'string' to System.Collections.Generic.IEnumerable<string>'
Essentially, I am trying to save choices from a checkboxlist (one or more selections) as a comma-separated list in the DB.
And this doesn't even get me over the problem of how do I use the enum. Any thoughts?
For some background:
I understand that the appropriate way to handle this relationship would be to create a separate table and use IList<MyEnum>. However, this is a simple list that I do not intend to manipulate with edits (in fact, no driver is used in this scenario as I handle this on the front-end with a controller and routes). I am just capturing data and redisplaying it in the Admin view for statistical/historical purposes. I may even consider getting rid of the Part (considering the following post: Bertrand's Blog Post.
It should be:
part.MyProperty = new[] {"foo", "bar"};
for example. The part's setter will store the value on the record's property as a comma-separated string, which will get persisted into the DB.
If you want to use enum values, you should use the Parse and ToString APIs that .NET provide on Enum.

Guid values in Oracle with fluentnhibernate

I've only been using fluent nhibernate a few days and its been going fine until trying to deal with guid values and Oracle. I have read a good few posts on the subject but none that help me solve the problem I am seeing.
I am using Oracle 10g express edition.
I have a simple test table in oracle
CREATE TABLE test (Field RAW(16));
I have a simple class and interface for mapping to the table
public class Test : ITest
{
public virtual Guid Field { get; set; }
}
public interface ITest
{
Guid Field { get; set; }
}
Class map is simple
public class TestMap : ClassMap<Test>
{
public TestMap()
{
Id(x => x.Field);
}
}
I start trying to insert a simple easily recognised guid value
00112233445566778899AABBCCDDEEFF
Heres the code
var test = new Test {Field = new Guid("00112233445566778899AABBCCDDEEFF")};
// test.Field == 00112233445566778899AABBCCDDEEFF here.
session.Save(test);
// after save guid is changed, test.Field == 09a3f4eefebc4cdb8c239f5300edfd82
// this value is different for each run so I pressume nhibernate is assigning
// a value internally.
transaction.Commit();
IQuery query = session.CreateQuery("from Test");
// or
// IQuery query = session.CreateSQLQuery("select * from Test").AddEntity(typeof(Test));
var t in query.List<Test>().Single();
// t.Field == 8ef8a3b10e704e4dae5d9f5300e77098
// this value never changes between runs.
The value actually stored in the database differs each time also, for the run above it was
EEF4A309BCFEDB4C8C239F5300EDFD82
Truly confused....
Any help much appreciated.
EDIT: I always delete data from the table before each test run. Also using ADO directly works no problem.
EDIT: OK, my first problem was that even though I thought I was dropping the data from the table via SQL command line for oracle when I viewed the table via oracle UI it still had data and the first guid was as I should have expected 8ef8a3b10e704e4dae5d9f5300e77098.
Fnhibernate still appears to be altering the guid value on save. it alters it to the value it stores in the database but I'm still not sure why it is doing this or how\if I can control it.
If you intend on assigning the id yourself you will need to use a different id generator than the default which is Guid.comb. You should be using assigned instead. So your mapping would look something like this:
Id(x => x.Field).GeneratedBy.Assigned();
You can read more about id generators in the nhibernate documentation here:
http://www.nhforge.org/doc/nh/en/index.html#mapping-declaration-id-generator

How to access data into IQueryable?

I have IQueryable object and I need to take the data inside the IQueryable to put it into Textboxs controls. Is this possible?
I try something like:
public void setdata (IQueryable mydata)
{
textbox1.text = mydata.????
}
Update:
I'm doing this:
public IQueryable getData(String tableName, Hashtable myparams)
{
decimal id = 0;
if (myparams.ContainsKey("id") == true)
id = (decimal)myparams["id"];
Type myType= Type.GetType("ORM_Linq." + tableName + ", ORM_Linq");
return this.GetTable(tableName , "select * from Articu where id_tipo_p = '" + id + "'");
}
public IQueryable<T> GetTable<T>(System.Linq.Expressions.Expression<Func<T, bool>> predicate) where T : class
{
return _datacontext.GetTable<T>().Where(predicate);
}
This returns a {System.Data.Linq.SqlClient.SqlProvider+OneTimeEnumerable1[ORM_Linq.Articu]}`
I don't see any method like you tell me. I see Cast<>, Expression, ToString...
EDIT: Updated based on additional info from your other posts...
Your getData method is returning IQueryable instead of a strongly typed result, which is why you end up casting it. Try changing it to:
public IQueryable<ORM_Linq.Articu> getData(...)
Are you trying to query for "Articu" from different tables?
With the above change in place, your code can be rewritten as follows:
ORM_Linq.Articu result = mydata.SingleOrDefault();
if (result != null)
{
TextBoxCode.Text = result.id.ToString();
TextBoxName.Text = result.descrip;
}
If you have a single result use SingleOrDefault which will return a default value if no results are returned:
var result = mydata.SingleOrDefault();
if (result != null)
{
textbox1.text = result.ProductName; // use the column name
}
else
{
// do something
}
If you have multiple results then loop over them:
foreach (var item in mydata)
{
string name = item.ProductName;
int id = item.ProductId;
// etc..
}
First, you should be using a strongly-typed version of IQueryable. Say that your objects are of type MyObject and that MyObject has a property called Name of type string. Then, first change the parameter mydata to be of type IQueryable<MyObject>:
public void setdata (IQueryable<MyObject> mydata)
Then we can write a body like so to actually get some data out of. Let's say that we just want the first result from the query:
public void setdata (IQueryable<MyObject> mydata) {
MyObject first = mydata.FirstOrDefault();
if(first != null) {
textbox1.Text = first.Name;
}
}
Or, if you want to concatenate all the names:
public void setdata(IQueryable<MyObject> mydata) {
string text = String.Join(", ", mydata.Select(x => x.Name).ToArray());
textbo1.Text = text;
}
Well, as the name suggests, an object implementing IQueryable is... Queryable! You'll need to write a linq query to get at the internal details of your IQueryable object. In your linq query you'll be able to pull out its data and assign bits of it where ever you'd like - like your text box.
Here's a great starting place for learning Linq.
I think you find the same mental struggle when coming from FoxPro and from DataSet. Really nice, powerful string-based capabilities(sql for query, access to tables and columns name) in these worlds are not available, but replaced with a compiled, strongly-typed set of capabilities.
This is very nice if you are statically defining the UI for search and results display against a data source known at compile time. Not so nice if you are trying to build a system which attaches to existing data sources known only at runtime and defined by configuration data.
If you expect only one value just call FirstOrDefault() method.
public void setdata (IQueryable mydata)
{
textbox1.text = mydata.FirstOrDefault().PropertyName;
}

Resources