I have a SQL database where one of the value is a XML string.
Now I'm trying to write a search function to check is it xml string contains a searchstring.
Standard SQL command would be like this:
SELECT
[ID], [DisplayName], [XML_String],
[CreatedTime], [ModifiedTime]
FROM
[Simple_SQL_DB].[dbo].[Simple_Table]
WHERE
CAST(XML_String AS nvarchar(max)) LIKE "%SearchString%"
FROM
Simple_Table
ORDER BY
ModifiedTime DESC)
ORDER BY Displayname
I tried something like this:
private SimpleTableEntities db = new SimpleTableEntities ();
var query = db.Simple_Table
.Where(w => w.XML_String.Cast<string>().Contains("%SearchString%"))
.OrderByDescending(x => x.ModifiedTime);
Unfortunately I get this error:
System.ArgumentException: 'DbExpressionBinding requires an input expression with a collection ResultType.
Can somebody help me to write a correct query?
Related
How can I call a stored procedure in Acumatica via PXDataBase which has as input parameter User defined type?
For example, I have the following type:
CREATE TYPE [dbo].[string_list_tblType] AS TABLE(
[RefNbr] [nvarchar](10) NOT NULL,
PRIMARY KEY CLUSTERED
(
[RefNbr] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO
I have the following stored procedure:
CREATE PROCEDURE [dbo].[GetListOfAPInvoices]
#APInvoices as string_list_tblType readonly,
AS
BEGIN
select * from APInvoice a where a.RefNbr in (select RefNbr from #APInvoices)
END
and following fragment of C# code:
var par = new SqlParameter("APInvoices", dt);
par.SqlDbType = SqlDbType.Structured;
par.TypeName = "dbo.string_list_tblType";
par.UdtTypeName = "dbo.string_list_tblType";
par.ParameterName = "APInvoices";
PXSPParameter p1 = new PXSPInParameter("#APInvoices", PXDbType.Udt, par);
var pars = new List<PXSPParameter> { p1};
var results = PXDatabase.Execute(sqlCommand, pars.ToArray());
but when I execute my C# code I'm receiving error message:
UdtTypeName property must be set for UDT parameters
When I debugged with reflector class PXSqlDatabaseProvider, method
public override object[] Execute(string procedureName, params PXSPParameter[] pars)
I noticed that
using (new PXLongOperation.PXUntouchedScope(Thread.CurrentThread))
{
command.ExecuteNonQuery();
}
command.Parameters.Items has my method parameters, but item which is related to Udt type is null. I need to know how to pass user defined table type. Has anybody tried this approach?
Unfortunately UDT parameters are not supported in Acumatica's PXDatabase.Execute(..) method and there is no way to pass one to a stored procedure using the built-in functionality of the platform.
Besides, when writing data-retrieval procedures like the one in your example, you should acknowledge that BQL-based data-retrieval facilities do a lot of work to match company masks, filter out records marked as DeletedDatabaseRecord and apply some other internal logic. If you chose to fetch data with plain select wrapped into a stored procedure you bypass all this functionality. Hardly is this something that you want to achieve.
If you absolutely want to use a stored procedure to get some records from the database but don't want the above side-effect, one option is to create an auxiliary table in the DB and select records into it using a procedure. Then in the application you add a DAC mapped to this new table and use it to get data from the table by means of PXSelect or similar thing.
Coming back to your particular example of fetching some ARInvoices by the list of their numbers, you could try using dynamic BQL composition to achieve something like this with Acumatica data access facilities.
I am using a simple select object to list all the parent categories as follows.
$select = $this->sql->select();
$select -> where(array('cat_parent_id'=>2));
$statement = $this->sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
When I run the above code, I donot have an error message but I always have a null result. If I use the where clause without the array params then I have the good results.
$select -> where('cat_parent_id=2');
To learn more, I tried to get the sql string using the code below,
$select = $this->sql->select();
$select -> where(array('cat_parent_id'=>2));
$sqlstring = $this->sql->getSqlStringForSqlObject($select);
I have a warning.
Notice: Attempting to quote a value in Zend\Db\Adapter\Platform\Mysql without extension/driver support can introduce security vulnerabilities in a production environment. in D:\wamp\www\shops\vendor\ZF2\library\Zend\Db\Adapter\Platform\Mysql.php on line 128
I really would like to use the array method inside the where clause. Any help would be very appreciated. :)
I have the following query working which gets the results I want:
int associatedId = 123;
MyObject alias = null;
var subQuery = QueryOver.Of<DatabaseView>()
.Where(view => view.AssociatedId == associatedId)
.And(view => view.ObjectId == alias.ObjectId)
.Select(view => view.ObjectId);
var results = session.QueryOver<MyObject>(() => alias)
.WithSubquery.WhereExists(subQuery)
.List();
The DatabaseView has been mapped as an actual NHibernate entity (so I can use it with QueryOver), but it is not associated to MyObject in the HBM mappings.
This query returns an IList<MyObject> using a SELECT ... FROM MyObject WHERE EXISTS (subquery for DatabaseView here). How can I re-write this to return the same data but using a JOIN instead of sub query?
In NHibernate 5.1+ it's possible for QueryOver/Criteria via Entity Join:
int associatedId = 123;
MyObject alias = null;
DatabaseView viewAlias = null;
var results = session.QueryOver<MyObject>(() => alias)
.JoinEntityAlias(() => viewAlias, () => viewAlias.ObjectId == alias.ObjectId && viewAlias.AssociatedId == associatedId)
.List();
Criteria example:
int associatedId = 123;
var results = session.CreateCriteria<MyObject>("alias")
.CreateEntityAlias(
"viewAlias",
Restrictions.EqProperty("viewAlias.ObjectId", "alias.ObjectId")
&& Restrictions.Eq("viewAlias.AssociationId", associatedId),
JoinType.InnerJoin,
typeof(DatabaseView).FullName)
.List();
You can join onto unrelated entities with Linq in NHibernate 3+
Funnily enough you use the join query expression element:
from type1 in Repository.Query<MyType1>()
join type2 in Repository.Query<MyType2>()
on type1.Id equals type2.Id
Note: Repository.Query is just returning an IQueryable Query from the session
I'm hoping there is a solution for QueryOver as I don't always want to model two-way relationships in my domain but they are still useful for querying.
Also, you can map a Access="noop" 2 way relationship using Criteria API without putting into your POCO classes:
http://ayende.com/blog/4054/nhibernate-query-only-properties
I realize this question is 5 years old, and the "correct" answer is definitely that you can't do this with QueryOver, as the other answers indicate. However, if you really need this functionality (as I did), there is a decent workaround that I found.
The solution is to use a "loader query" with native SQL in your mapping XML to produce a related collection (see http://nhibernate.info/doc/nhibernate-reference/querysql.html#querysql-load). In the OP's specific example, you would go ahead and map your DatabaseView as an entity as suggested, and then write the following in your mapping:
<class name="MyObject"...>
...
<set name="MyViews" inverse="true">
<key column="ObjectId" foreign-key="none"/>
<one-to-many class="MyObject"/>
<loader query-ref="myObjectViewsLoadQuery"/>
</set>
</class>
Then we just need to define our named myObjectViewsLoadQuery in raw SQL to explain to NH how to join the two:
<sql-query name="myObjectViewsLoadQuery">
<load-collection alias="view" role="MyObject.MyViews"/>
SELECT view.*
FROM DatabaseView view
WHERE view.ObjectId = :id
</sql-query>
We can now pretend like there is a "real" collection named MyViews relating MyObject to DatabaseView in our query:
MyObject alias = null;
DatabaseView view = null;
var results = session.QueryOver<MyObject>(() => alias)
.JoinAlias( () => alias.MyViews, () => view )
//.Where( () => view.Property == "myValue" ) // optionally, restrict the view etc.
.List();
Certainly, this is a lot of trouble to go through if you only care about an "elegant" query. However, if the reason you are using QueryOver is that you want to be able to accept arbitrary input Expressions to filter your DatabaseView by, or various similar activities, this works very nicely.
I have simple query with two joins:
SELECT p.id, BU.ID, BU.TEXTLANG as Title FROM PROJEKT P
JOIN Text BT ON BT.ID = P.TITEL_ID
JOIN Uebersetzung BU ON BU.TEXT_ID = BT.ID
WHERE BU.TEXTLANG LIKE '%Spatial%';
This query must be converted to a typesafe query, what i tried is:
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<Projekt> query = criteriaBuilder.createQuery(Projekt.class);
final Root<Projekt> projekt = query.from(Projekt.class);
Join<Projekt, Text> bt = projekt.join(Projekt_.titel);
Join<Text, Uebersetzung> bu = bt.join(Text_.uebersetzungen);
Predicate condition = criteriaBuilder.like(bu.get(Uebersetzung_.textLang),"%Spatial%");
query.where(condition);
query.distinct(true);
query.orderBy(criteriaBuilder.asc(projekt.get(Projekt_.id)));
My problem is, that i want to get the field Uebersetzung_.textLang as selection. But when i try to add selection to the query, for example:
query.multiselect(bu.get(Uebersetzung_.textLang));
i get an error message:
org.apache.openjpa.persistence.OptimisticLockException: Unable to obtain an object lock on "null".
I need this field, because i want to access it from the jsp page. Is there any other way to get this field in the selection?
What is wrong with my query below? This is using the standard Membership tables.
var clientRole = rushDB.aspnet_Roles.Single(r => r.LoweredRoleName == "client" );
//var users = rushDB.aspnet_Users.Where(u => u.aspnet_Roles.Contains(client)).AsEnumerable();
var users = from u in rushDB.aspnet_Users
where u.aspnet_Roles.Contains(clientRole)
select u;
return View(users.ToList());
I get this error on my view...
Unable to create a constant value of type 'RushToIt.Models.aspnet_Roles'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
I would expect that you are trying (or rather LINQ is trying) to use the clientRole as a where-clause to a select statement. You can only send simple types are parameters.
Instead you would need to evaluate the role inline.
However it's probably easier if you just traverse in reverse (that sounds good, right?). You should be able to do this:
var clientRole = rushDB.aspnet_Roles.Single(r => r.LoweredRoleName == "client" );
return View(clientRole.aspnet_Users.ToList());