Using LINQ to SQL with Managed ODP.NET (Oracle) - oracle

I'm using the newly released Managed ODP.NET driver from Oracle to connect to my database (see here). Connection setup is fine. I now try to use a very simple LINQ to SQL example. The problem is that I get the an ArgumentOutOfRangeException. It appears on the foreach-Statement.
My very simple object:
[Table(Name = "my_mgr.ADDRESS")]
public class Address
{
[Column(Name = "NAME")]
public string Surname;
[Column(Name = "VNAME")]
public string Forename;
[Column(Name = "ANZ")]
public int Anz;
}
The part of testing the query:
DataContext db = new DataContext(inst.Connection);
Table<Address> addressTable = db.GetTable<Address>();
if (addressTable != null)
{
//"SELECT * from my_mgr.ADDRESS WHERE anz > 0";
var query = from p in addressTable where p.Anz > 0 select p;
foreach (var p in query)
{
MessageBox.Show(
"Forename: " + p.Forename + "\n" +
"Surname: " + p.Surname
);
}
}
Whereas my original SQL query was (which is actually working):
SELECT * from my_mgr.ADDRESS WHERE anz > 0
I actually searched a lot for this but I cannot find valid results since the driver is very new and it seems nobody had the problem before. I am very sure that the driver supports LINQ to SQL, as stated on this website. Sadly I'm not able to use neither the Entity Framework nor auto-generation tools provided by Visual Studio.

Linq to SQL does not support Oracle. If you want to use ODP.NET and Linq just like linq to sql, I suggest you use ALinq. http://www.alinq.org

Related

Is there a way to view LINQ Generated query expressions in CRM Dynamics?

Considering the fact LINQ queries in CRM Dynamics are translated into query expressions (source):
[...] The OrganizationServiceContext class contains an underlying LINQ
query provider that translates LINQ queries from Microsoft Visual C#
or Microsoft Visual Basic .NET syntax into the query API used by
Microsoft Dynamics CRM. [...]
Is there a way to see the generated query expressions (As it's possible to see the generated SQL query in Linq-to-Sql or Linq-to-Entities)?
You can use reflection to get the query object and then convert that to a FetchXML query to get a printable query. This will work with both early-bound and late-bound queries.
From: https://pogo69.wordpress.com/2012/04/05/crm-linq-provider-converting-expressions-to-queryexpression-andor-fetchxml/
var connectionString = #"SET YOUR CONNECTION STRING";
var service = new CrmServiceClient(connectionString);
using (var xrm = service.OrganizationServiceProxy)
{
OrganizationServiceContext orgContext =
new OrganizationServiceContext(xrm);
var query = from c in orgContext.CreateQuery("contact")
join a in orgContext.CreateQuery("account")
on c["contactid"] equals a["primarycontactid"]
where (String)c["lastname"] == "Wilcox" ||
(String)c["lastname"] == "Andrews"
where ((String)a["address1_telephone1"]).Contains("(206)")
|| ((String)a["address1_telephone1"]).Contains("(425)")
select new
{
Contact = new
{
FirstName = c["firstname"],
LastName = c["lastname"]
},
Account = new
{
Address1_Telephone1 = a["address1_telephone1"]
}
};
IQueryProvider queryProvider = query.Provider;
MethodInfo translateMethodInfo = queryProvider.GetType().GetMethod("Translate");
QueryExpression queryEx = (QueryExpression)translateMethodInfo.Invoke(queryProvider, new object[] { query.Expression });
QueryExpressionToFetchXmlRequest reqConvertToFetchXml = new QueryExpressionToFetchXmlRequest { Query = queryEx };
QueryExpressionToFetchXmlResponse respConvertToFetchXml = (QueryExpressionToFetchXmlResponse)xrm.Execute(reqConvertToFetchXml);
Console.WriteLine("To FetchXML:" + Environment.NewLine + Environment.NewLine);
Console.WriteLine(respConvertToFetchXml.FetchXml);
Alternatively you could use Fiddler to capture the actual query text sent in the SOAP message. I've done this before and haven't found it any more valuable than the FetchXml.

GroupBy and Distinct in EntityFramework Core

EF Core dose not support GroupBy, and i think for Distinct i have same problem.
so, how can i fix it?
i just get 100 first elements and then i call Distinct() on result List
have a better solution?
is it possible to add groupby as a extension method to EFCore?
.Net Core is not a good idea for a reporting System :/
it is trap :(
query = query.Where(e => e.Goodscode.Contains(filter) || e.GoodsName.Contains(filter));
return query.Select(e => new GoodsDTO
{
Name = e.GoodsName,
Code = e.Goodscode,
T3Code = e.T3Code,
StockId = e.StockId
}).Take(100).ToList().Distinct(new GoodsDTOComparer()).Take(20);
//why we do like up: because EF7 dosent support Distinct and GroupBy yet (12-03-2017)
//microsoft, please don't be OpenSource, because you dont care for your opensource products
You can use Dapper library for queries that not supported in ef core
example
using (IDbConnection dbConnection = new SqlConnection(niniSiteConnectionString))
{
var sql = #"SELECT Name, Count(*) AS Total FROM Users
GROUP BY u.Name
HAVING COUNT(*) > 1";
var result = dbConnection.Query<UserDto>(sql).ToList();
}
public class UserDto
{
public string Name{get; set;}
public int Total{get; set;}
}

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);
}

How to do a Full-Text search within a Linq query when using LLBLGen

[Using LLBLGen Pro 3.1 with Entity Framework 4, .NET 4 and SQLServer 2005]
I've got a linq query that includes .Contain(keyword);
IEnumerable<Product> products = null;
using (var context = new ModelDataContext())
{
products = (from product in context.Products where product.Title.Contains(keyword)
select product);
}
I was looking into the performance of the query and discovered that when the SQL is generated it's actually a "like '%keyword%'" that is being generated not a contains.
After doing a bit of research I came across some info in the LLBLGen Pro documentation regarding FunctionMapping:
http://www.llblgen.com/documentation/2.6/Using%20the%20generated%20code/Linq/gencode_linq_functionmappings.htm
I've created a table-valued function on my sql database, and also the classes required within my project:
public class CustomDatabaseFunctions
{
public static bool FullTextSearch(string fieldToSearch, string toFind)
{
// empty body, as it's just here to make the query compile. The call is converted to a SQL function.
return true;
}
}
public class CustomDatabaseFunctionMappings : FunctionMappingStore
{
public CustomDatabaseFunctionMappings() : base()
{
this.Add(new FunctionMapping(typeof(CustomDatabaseFunctions),"FullTextSearch",1,"Product_FullTextSearch({0})","ProductDatabase","Resources"));
}
}
The next part of the documentation states that you need to pass the custom FunctionMappingStore to the LinqMetaData. In the example this is done as follows:
metaData.CustomFunctionMappings = new NorthwindFunctionMappings();
var q = from o in metaData.Order where o.CustomerId == "CHOPS"
select new { o.OrderId, OrderTotal = NorthwindFunctions.CalculateOrderTotal(o.OrderId, true) };
The problem I have is that I'm doing my linq query using the DataContext and I've no idea where the variable metaData comes from or how to use it!
I'll keep looking to see if I can find out but any help very welcome!
the documentation you're linking to is for our framework, yet you're saying you're using EFv4. So you should use the function mapping feature of EF, not our own framework ;). That is, if you're using EF, but the code suggests you don't. So I'm very confused.
It's also better to post questions about LLBLGen Pro on our own support forums as we don't monitor SO.

NHibernate LINQ 3.0 Oracle Expression type 10005 is not supported by this SelectClauseVisitor

I have the following LINQ query
QueryResult<List<PersonDemographic>> members = new QueryResult<List<PersonDemographic>>();
var query = (from ms in this.Session.Query<MemberSummary>()
where ms.NameSearch.StartsWith(firstName.ToUpper())
&& ms.NameSearch2.StartsWith(lastName.ToUpper())
select new PersonDemographic
{
FirstName = ms.FirstName.ToProperCase(),
LastName = ms.LastName.ToProperCase(),
PersonId = ms.Id,
Address = new Address
{
Line1 = ms.AddressLine1.ToProperCase(),
Line2 = ms.AddressLine2.ToProperCase(),
City = ms.City.ToProperCase(),
State = ms.State,
Zipcode = ms.Zipcode,
},
PhoneNumber = new PhoneNumber
{
Number = string.IsNullOrWhiteSpace(ms.PhoneNumber) ? null : Regex.Replace(ms.PhoneNumber, #"(\d{3})(\d{3})(\d{4})", "$1-$2-$3")
}
});
if (this.Session.Transaction.IsActive)
{
members.Data = query.Distinct().Take(15).ToList();
}
else
{
using (var transaction = this.Session.BeginTransaction())
{
members.Data = query.Distinct().Take(15).ToList();
transaction.Commit();
}
}
The code is running under the transaction section. If I use it without a Distinct I have no problem. Adding the Distinct gives me an exception
{"Expression type 10005 is not supported by this SelectClauseVisitor."}
I can't find anything definitive. Can anyone help?
Thanks,
Paul
There are lots of things in that query that NH can't possibly know how to translate to SQL:
ToProperCase (that looks like an extension method of yours)
string.IsNullOrWhiteSpace (that's new in .NET 4, NH is compiled against 3.5)
Regex.Replace (that's just not possible to do with SQL, unless you have a DB that supports it and write a Dialect for it)

Resources