I am having a problem were Dapper won't accept multiple models, see my code example. I have the QueueItems and robots models in query but when I add the second (Robots) I get the folowing error "IDBconnection does not contain a definition for Query"
public void getdata()
{
using (IDbConnection connection = new SqlConnection(con))
{
string sql = "Select * from QueueItems";
var queryResult = connection.Query<QueueItems,Robots>(sql).ToList();
}
}
If your resultset contains columns for two pocos, you'll have to wrap them in an envelope (either a typed class or dynamic) object since you can only return one type.
The method signature for that is
var result = connection.Query<QueueItems,Robots,dynamic>(sql, (queueItem,robot) => {
dynamic d = new ExpandoObject();
d.QueueItem = queueItem
d.Robot = robot;
return d;
}, splitOn: "...insert split columns unless they're named Id...");
This will return a dynamic list where each record contains a QueueItem and Robot property.
Dapper by default splits on the "Id" column. If your query returns a recordset like this:
|Id|C1|C2|C3|Id|C4|C5
Id, C1, C2 and C3 will be mapped to queueItem, Id, C4 and C5 will be mapped to robot.
Related
I try to use the Criteria API to create a dynamic JPA-Query. I need to find a key-value pair inside a map of the object.
The Object looks similar to the following one.
public class item {
private UUID id;
#Column(name = "properties", columnDefinition = "nvarchar")
private Map<String, Object> properties;
}
I thought I could use the MapJoin join or joinMap:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Item> criteriaQuery = cb.createQuery(Item.class);
Root<Item> itemRoot = criteriaQuery.from(Item.class);
criteriaQuery.select(itemRoot);
Join<String, Object> properties = itemRoot.join("properties");
// or
//MapJoin<Item, String, Object> properties = itemRoot.joinMap("properties");
Predicate pre1 = cb.equal(properties.get(ITEM_PROPERTY_1), "123");
Predicate pre2 = cb.equal(properties.get(ITEM_PROPERTY_2), "456");
Predicate propertiesPredicate = cb.and(pre1, pre2);
criteriaQuery.where(propertiesPredicate);
Item item = em.createQuery(criteriaQuery).getSingleResult();
But I've read that this is only for associations.
On the join i get an:
IllegalArgumentException: Requested attribute was not a map.
So could sb explain to me, how I will be able to find a key-value pair in a map with the Criteria API?
Edit: I am not able to change anything in the DB.
So I need to guess a little bit because you didn't show us your DB Table, that's why I answer a little bit more freely.
And as a disclaimer: it might be easier and it would be more efficient to query a real table instead of an serialized object/json.
But I would do it this way:
The Table in MSSQL:
create table ${schema}.myTable
(
id bigint identity
constraint PK_myStuff
primary key,
properties nvarchar(max) not null
) go
The Java entity (draft):
public class Item extends AbstractPersistable<...> {
#Column(name = "properties", columnDefinition = "nvarchar")
private String properties;
}
The Java Specification:
protected Specification<Item> customFilter(String filterArg) {
return (root, query, cb) ->
cb.like(root.get(Item_.properties), filterArg);
}
This way your query searches the properties for a string pattern.
Info:
https://vladmihalcea.com/sql-server-json-hibernate/
I'm writing a code generation tool against Sql Server Data Tools and I need to be able to get the data type for:
View Columns
Computed Columns on a table
Where is this information? For tables (with the exception of computed columns), it's here:
TSqlObject table; //retrieved elsewhere
TSqlObject column = table.GetReferenced(Table.Columns).First(); //first column
TSqlObject dataType = column.GetReferenced(Column.DataType).FirstOrDefault();
For computed columns, dataType above is null.
For views, I've tried:
TSqlObject view; //retrieved elsewhere
TSqlObject column = view.GetReferenced(View.Columns).First(); //first column
TSqlObject dataType = column.GetReferenced(Column.DataType).FirstOrDefault();//null
Is this information anywhere? Are there any other options for getting this information other than publishing the source .DACPAC to a database?
EDIT: in response to Ed Elliot below (regarding the use of the strongly-typed DacFx model)
The following code fails to bring back type information for the view:
TSqlTypedModel model = new TSqlTypedModel(#"path.dacpac");
var view = model.GetObjects<TSqlView>(Microsoft.SqlServer.Dac.Model.DacQueryScopes.UserDefined).FirstOrDefault();
var viewcolumns = view.Columns;
//false
bool viewHasTypeInformation = viewcolumns.Any(c => c.DataType.Count() > 0);
var table = model.GetObjects<TSqlTable>(Microsoft.SqlServer.Dac.Model.DacQueryScopes.UserDefined).FirstOrDefault();
var tablecolumns = table.Columns;
//true
bool tableHasTypeInformation = tablecolumns.Any(c => c.DataType.Count() > 0);
I'm starting to think this is a limitation of the DAC model itself.
oooh great topic :)
The easiest way to query using the DacFxStronglyTypedModel object which is available:
https://github.com/Microsoft/DACExtensions
It is a bit odd in that it is a sample which you build and then it gives you easy access to query the DacFx:
https://github.com/Microsoft/DACExtensions/tree/master/DacFxStronglyTypedModel
To get a strongly typed model do:
var model = new TSqlTypedModel("dacpacPath")Íž
Then when you query it for all the views (or whatever) you get a list of typed objects which are a lot "saner" than the DacFx.
The interface that you get back for views:
ISql120TSqlView (change the version number to your version number) has an IEnumerable of Columns:
IEnumerable<Microsoft.SqlServer.Dac.Extensions.Prototype.ISql120TSqlColumn> Columns
{
get;
}
The column interface then has an IEnumerable of DataTypes:
IEnumerable<Microsoft.SqlServer.Dac.Extensions.Prototype.ISqlDataType> DataType
{
get;
}
I haven't got a windows machine right now to get you a full demo but that should be enough, if you dont' get what you need put a comment and i'll get a sample tomorrow (if no one else does in the meantime).
To get the list of columns on a view do:
var views = model.GetObjects<TSqlView>(DacQueryScopes.UserDefined);
foreach (var v in views)
{
Console.WriteLine(v.Columns.Count());
}
This works for me with the 130 version of the Dac dll's.
To get to the details for computed columns you need to view the "ExpressionDependencies" on the column (see v.Columns) which is the same as for tables.
EDIT
So I have been having a play and there are some things that you just can't determine until runtime so the DacFx won't be able to figure out the type for those and they only way I know of it actually generating the record set and examining what you get back but there is some things we can do with computed columns, if we take this example:
create table [dbo].[the_table]
(
[Id] INT not null primary key,
[StringCol] varchar(234) not null,
[a] int,
[b] decimal,
[a_and_b] as [a] + [b]
)
for columns, Id, StringCol, a and b when we use the strongly typed dacfx we can get the column types by doing this:
var tables = model.GetObjects(DacQueryScopes.UserDefined);
foreach (var t in tables)
{
switch (c.ColumnType)
{
case ColumnType.Column:
ShowType(c.DataType);
break;
}
}
ShowType looks like this:
void ShowType(IEnumerable<ISqlDataType> types)
{
var builder = new StringBuilder();
foreach (var type in types)
{
var t = new TSqlDataType(type.Element);
builder.Append($"{t.SqlDataType.ToString()} ");
}
Console.Write(builder);
}
What we do is have a list of data types for each column, it might just be int or something like that but it is a list.
Now because we have a computed column, instead of just the data type(s) we have references to the underlying columns which we can get the data type(s) from:
void ShowDependencies(IEnumerable<ISqlModelElementReference> dependencies)
{
foreach (var dependency in dependencies)
{
if (dependency is TSqlColumnReference)
{
var column = new TSqlColumn(dependency.Element);
Console.Write(column.Name + " ");
ShowType(column.DataType);
}
}
}
to know when to call this version:
var tables = model.GetObjects<TSqlTable>(DacQueryScopes.UserDefined);
foreach (var t in tables)
{
Console.WriteLine($"table - {t.Name}");
foreach (var c in t.Columns)
{
Console.Write("\r\n" + c.Name.ToString() + " ");
switch (c.ColumnType)
{
case ColumnType.Column:
ShowType(c.DataType);
break;
case ColumnType.ComputedColumn:
Console.Write($"({c.Expression}) ");
ShowDependencies(c.ExpressionDependencies);
break;
for the sample table about we get this output:
table - [dbo].[the_table]
[dbo].[the_table].[Id] Int
[dbo].[the_table].[StringCol] VarChar
[dbo].[the_table].[a] Int
[dbo].[the_table].[b] Decimal
[dbo].[the_table].[a_and_b] ([a] + [b]) [dbo].[the_table].[a] Int [dbo].[the_table].[b] Decimal view - [dbo].[mutli_type]
we would then need to decide what the type is, as a guess sql will do an implicit cast as runtime to a decimal but at compile time I don't think it is known (happy to be corrected here!)
If we then take a view as an example:
create view the_view
as
select
*,
object_name(4) some_name,
123 as an_int
from
the_table
we have the columns from the base table which can be enumerated simply but the object_name and 123 are slightly harder, using the same code above but for views we get:
[dbo].[the_view].[Id] [dbo].[the_table].[Id] Int
[dbo].[the_view].[StringCol] [dbo].[the_table].[StringCol] VarChar
[dbo].[the_view].[a] [dbo].[the_table].[a] Int
[dbo].[the_view].[b] [dbo].[the_table].[b] Decimal
[dbo].[the_view].[a_and_b] [dbo].[the_table].[a_and_b]
[dbo].[the_view].[some_name] some_name = an_int =
[dbo].[the_view].[an_int] some_name = an_int =
So no type for the computed columns plus to get to the value for a_and_b we would need to further enumerate again to get the types we had above.
At this point what you have is a view with columns that point to functions / expressions and this is where is starts to get harder :) if you take the example above you could probably work out what object_name returned and determine that but when you get a view that is non-deterministic on either the data or data type what do you do?
If we take:
create view mutli_type
as
select case datepart(day, getdate())
when 1
then 100
when 2
then 'hello'
else
getdate()
end as multitype
depending on the day we get a different data type returned - double ouch.
If you really needed to know what the view returned you could get the select elements in the view and use the TSqlScript Dom to parse them into parts and try and infer each one, I have mocked up a sample that finds the getdate() function in this view to give you an idea of what you need to do but it isn't straightforward and I don't even want to consider stored procedures where you can pass in dynamic sql:
Full sample:
create table [dbo].[the_table]
(
[Id] INT not null primary key,
[StringCol] varchar(234) not null,
[a] int,
[b] decimal,
[a_and_b] as [a] + [b]
)
go
create view the_view
as
select *, object_name(4) some_name, 123 as an_int from the_table
go
create view mutli_type
as
select case datepart(day, getdate())
when 1
then 100
when 2
then 'hello'
else
getdate()
end as multitype
go
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlServer.Dac.Extensions.Prototype;
using Microsoft.SqlServer.Dac.Model;
using Microsoft.SqlServer.TransactSql.ScriptDom;
using ColumnType = Microsoft.SqlServer.Dac.Model.ColumnType;
namespace ConsoleApplication1
{
class Program
{
static void ShowType(IEnumerable<ISqlDataType> types)
{
var builder = new StringBuilder();
foreach (var type in types)
{
var t = new TSqlDataType(type.Element);
builder.Append($"{t.SqlDataType.ToString()} ");
}
Console.Write(builder);
}
static void ShowDependencies(IEnumerable<ISqlModelElementReference> dependencies)
{
foreach (var dependency in dependencies)
{
if (dependency is TSqlColumnReference)
{
var column = new TSqlColumn(dependency.Element);
Console.Write(column.Name + " ");
ShowType(column.DataType);
}
}
}
static void Main(string[] args)
{
var model = new TSqlTypedModel(#"path\Da.dacpac");
var views = model.GetObjects<TSqlView>(DacQueryScopes.UserDefined);
var tables = model.GetObjects<TSqlTable>(DacQueryScopes.UserDefined);
foreach (var t in tables)
{
Console.WriteLine($"table - {t.Name}");
foreach (var c in t.Columns)
{
Console.Write("\r\n" + c.Name.ToString() + " ");
switch (c.ColumnType)
{
case ColumnType.Column:
ShowType(c.DataType);
break;
case ColumnType.ComputedColumn:
Console.Write($"({c.Expression}) ");
ShowDependencies(c.ExpressionDependencies);
break;
case ColumnType.ColumnSet:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
foreach (var v in views)
{
Console.WriteLine($"view - {v.Name}");
foreach (var c in v.Columns)
{
Console.Write("\r\n" + c.Name.ToString() + " ");
var needDomParse = false;
switch (c.ColumnType)
{
case ColumnType.Column:
ShowType(c.DataType);
ShowDependencies(c.ExpressionDependencies);
break;
case ColumnType.ComputedColumn:
ShowType(c.DataType);
ShowDependencies(c.ExpressionDependencies);
if (!c.DataType.Any() && !c.ExpressionDependencies.Any())
{
needDomParse = true;
}
break;
case ColumnType.ColumnSet:
break;
default:
throw new ArgumentOutOfRangeException();
}
if (needDomParse)
{
//ouch
var create = new CreateViewStatement();
var parser = new TSql130Parser(false);
IList<ParseError> errors;
var fragment = parser.Parse(new StringReader(v.GetScript()), out errors);
var selectVisitor = new SelectVisitor();
fragment.Accept(selectVisitor);
foreach (var s in selectVisitor.Selects)
{
var spec = s.QueryExpression as QuerySpecification;
foreach (var element in spec.SelectElements)
{
var select = element as SelectScalarExpression;
if (select != null)
{
Console.Write(select.ColumnName.Value + " = ");
var caseExpression = select.Expression as SimpleCaseExpression;
if (caseExpression != null)
{
var func = caseExpression.ElseExpression as FunctionCall;
Console.WriteLine(func.FunctionName.Value);
}
}
}
}
}
}
}
}
}
internal class SelectVisitor : TSqlConcreteFragmentVisitor
{
public List<SelectStatement> Selects = new List<SelectStatement>();
public override void Visit(SelectStatement node)
{
Selects.Add(node);
base.Visit(node);
}
}
}
I hope it helps, I know it isn't a just do this but hopefully explains some of the challenges :)
Ed
I'd like to know how can I search for empty strings when I'm using a text type field with Entity Framework.
I've looked the SQL query that Entity is generating and It's using LIKE to compare because It's searching in a text type field, so when I use .Equals(""), == "", == string.Empty, .Contains(""), .Contains(string.Empty), and everything else, It's returning all results because it sql query is like '' and the == command throws exception because It uses the = command that is not valid with text type field.
When I try to use .Equals(null), .Contains(null), == null, It returns nothing, because It is generating FIELD ISNULL command.
I already tried the .Lenght == 0 but It throws an exception...
This works for me:
public class POCO
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
static void Main(string[] args)
{
var pocos = new List<POCO>
{
new POCO { Id = 1, Name = "John", Description = "basic" },
new POCO { Id = 2, Name = "Jane", Description = "" },
new POCO { Id = 3, Name = "Joey", Description = string.Empty }
};
pocos.Where(x => x.Description == string.Empty)
.ToList()
.ForEach(x => Console.WriteLine($"{x.Id} {x.Name} {x.Description}"));
}
However the issue MAY BE that your T4 generated object is not fully realized with data you can use, if you are using Entity Framework. EG the translation from the database is not populating objects to interrogate correctly. I would just do an operation like this to see:
using (var context = new YOURCONTEXTNAME())
{
var persons = context.YOURDATABASEOBJECT.ToList();
persons.ForEach(x => Console.WriteLine($"{x.COLUMNINQUESTION}"));
}
If you are successfully having data in it, it should be retrieved. I would not use text if possible. Use a varchar(max) nvarchar(max) xml, whatever text will be deprecated eventually and is bad form so to speak to continue using at this point.
EDIT
Okay I see, the answer is you cannot interogate the object until it is fully realized when it is text. I did a test on my local database and created a context and tested it and sure enough you cannot do a '== string.empty', '== ""', or 'String.IsNullOrEmpty()' on a text. However you can do it once the object is materialized in a realized object. EG:
// Won't work as context does not understand type
//var persons = context.tePersons.Where(x => x.Description == string.Empty).ToList();
//Works fine as transformation got the object translated to a string in .NET
var start = context.tePersons.ToList();
var persons = start.Where(x => x.Description == String.Empty).ToList();
This poses a problem obviously as you need to get ALL your data potentially before performing a predicate. Not the best means by any measure. You could do a sql object for this instead then to do a function, proc, or view to change this.
I am writing a client-server java FX application with a table View. I have a database in the server side and I want from the Client to load the table Columns and table Records from the db to a table View dynamically. So far I have found many hints, on how to do this successfully. The thing is that I want to add to the table a column 'select' which is a check box. Below is my code.
private void AddToTableRecordsFromDB(TabPane tp){
tableview = (TableView) tp.lookup("#table");
ObservableList<Object> data = null;
try {
String[] columnNames = (String[]) Login.Login.in.readObject();
ArrayList<ArrayList> al = (ArrayList<ArrayList>) Login.Login.in.readObject();
/**********************************
* TABLE COLUMN ADDED DYNAMICALLY *
**********************************/
TableColumn select = new TableColumn("Select");
select.setCellValueFactory(new PropertyValueFactory("invited"));
select.setCellFactory(new Callback<TableColumn<ObservableValue, Boolean>, TableCell<ObservableValue, Boolean>>() {
public TableCell<ObservableValue, Boolean> call(TableColumn<ObservableValue, Boolean> p) {
return new CheckBoxTableCell<ObservableValue, Boolean>();
}
});
tableview.getColumns().add(select);
for(int i=0 ; i<columnNames.length; i++){
//use non property style for making dynamic table
final int j = i;
TableColumn col;
col = new TableColumn(columnNames[i]);
col.setCellValueFactory(new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
#Override
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
tableview.getColumns().add(col);
}
/********************************
* Data added to ObservableList *
********************************/
data = FXCollections.observableArrayList();
for(int i=0 ; i<al.size(); i++){
ObservableList<ArrayList> row = FXCollections.observableArrayList(al.get(i));
data.add(row);
}
//FINALLY ADDED TO TableView
tableview.setItems(data);
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger(Developer_Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
I took the CheckBoxTableCell class from the JavaFX2.0 Ensemble.
The database loads successfully in to the table view and also my 'select' column is created, but I can not see any check boxes in the rows.
Any help please ?
You say you are using "non property style" to add columns dynamically, and your table view made of list of list items. I guess there is no getInvited() method in those data structure model. However by setting select.setCellValueFactory(new PropertyValueFactory("invited")); the table column will look for that method. Set cell value factory with valid value.
EDIT: I didn't test but can you try the code below.
select.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>() {
public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> p) {
return new SimpleStringProperty(p.getValue().get(0).toString());
}
});
Note the get(0). Namely it would be better if readObject() returns at least 1 item. Another note is CheckBoxTableCell needs a Callback which returns ObservableProperty<Boolean> and binds bidirectionally so I think it is better to implement your own cell factory containing checkbox, regarding to your data model.
I was going through the SOQL documentation , but couldn't find query to fetch all the field data of an entity say , Account , like
select * from Account [ SQL syntax ]
Is there a syntax like the above in SOQL to fetch all the data of account , or the only way is to list all the fields ( though there are lot of fields to be queried )
Create a map like this:
Map<String, Schema.SObjectField> fldObjMap = schema.SObjectType.Account.fields.getMap();
List<Schema.SObjectField> fldObjMapValues = fldObjMap.values();
Then you can iterate through fldObjMapValues to create a SOQL query string:
String theQuery = 'SELECT ';
for(Schema.SObjectField s : fldObjMapValues)
{
String theLabel = s.getDescribe().getLabel(); // Perhaps store this in another map
String theName = s.getDescribe().getName();
String theType = s.getDescribe().getType(); // Perhaps store this in another map
// Continue building your dynamic query string
theQuery += theName + ',';
}
// Trim last comma
theQuery = theQuery.subString(0, theQuery.length() - 1);
// Finalize query string
theQuery += ' FROM Account WHERE ... AND ... LIMIT ...';
// Make your dynamic call
Account[] accounts = Database.query(theQuery);
superfell is correct, there is no way to directly do a SELECT *. However, this little code recipe will work (well, I haven't tested it but I think it looks ok). Understandably Force.com wants a multi-tenant architecture where resources are only provisioned as explicitly needed - not easily by doing SELECT * when usually only a subset of fields are actually needed.
You have to specify the fields, if you want to build something dynamic the describeSObject call returns the metadata about all the fields for an object, so you can build the query from that.
I use the Force.com Explorer and within the schema filter you can click the checkbox next to the TableName and it will select all the fields and insert into your query window - I use this as a shortcut to typeing it all out - just copy and paste from the query window. Hope this helps.
In case anyone was looking for a C# approach, I was able to use reflection and come up with the following:
public IEnumerable<String> GetColumnsFor<T>()
{
return typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Where(x => !Attribute.IsDefined(x, typeof(System.Xml.Serialization.XmlIgnoreAttribute))) // Exclude the ignored properties
.Where(x => x.DeclaringType != typeof(sObject)) // & Exclude inherited sObject propert(y/ies)
.Where(x => x.PropertyType.Namespace != typeof(Account).Namespace) // & Exclude properties storing references to other objects
.Select(x => x.Name);
}
It appears to work for the objects I've tested (and matches the columns generated by the API test). From there, it's about creating the query:
/* assume: this.server = new sForceService(); */
public IEnumerable<T> QueryAll<T>(params String[] columns)
where T : sObject
{
String soql = String.Format("SELECT {0} FROM {1}",
String.Join(", ", GetColumnsFor<T>()),
typeof(T).Name
);
this.service.QueryOptionsValue = new QueryOptions
{
batchsize = 250,
batchSizeSpecified = true
};
ICollection<T> results = new HashSet<T>();
try
{
Boolean done = false;
QueryResult queryResult = this.service.queryAll(soql);
while (!finished)
{
sObject[] records = queryResult.records;
foreach (sObject record in records)
{
T entity = entity as T;
if (entity != null)
{
results.Add(entity);
}
}
done &= queryResult.done;
if (!done)
{
queryResult = this.service.queryMode(queryResult.queryLocator);
}
}
}
catch (Exception ex)
{
throw; // your exception handling
}
return results;
}
For me it was the first time with Salesforce today and I came up with this in Java:
/**
* #param o any class that extends {#link SObject}, f.ex. Opportunity.class
* #return a list of all the objects of this type
*/
#SuppressWarnings("unchecked")
public <O extends SObject> List<O> getAll(Class<O> o) throws Exception {
// get the objectName; for example "Opportunity"
String objectName= o.getSimpleName();
// this will give us all the possible fields of this type of object
DescribeSObjectResult describeSObject = connection.describeSObject(objectName);
// making the query
String query = "SELECT ";
for (Field field : describeSObject.getFields()) { // add all the fields in the SELECT
query += field.getName() + ',';
}
// trim last comma
query = query.substring(0, query.length() - 1);
query += " FROM " + objectName;
SObject[] records = connection.query(query).getRecords();
List<O> result = new ArrayList<O>();
for (SObject record : records) {
result.add((O) record);
}
return result;
}
I used following to get complete records-
query_all("Select Id, Name From User_Profile__c")
To get complete fields of record, we have to mention those fields as mentioned here-
https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select.htm
Hope will help you !!!