I'm trying to get the Int64 value of a Directory Services object's "uSNChanged" value. Unfortunately, it is always coming back as a COM object of some kind. I've tried using casting to Int64, calling Int64.Parse(), and calling Convert.ToInt64(). None of these work.
For a given DirectoryEntry object, this code will display the properties:
private static void DisplaySelectedProperties(DirectoryEntry objADObject)
{
try
{
string[] properties = new string[] {
"displayName",
"whenCreated",
"whenChanged",
"uSNCreated",
"uSNChanged",
};
Console.WriteLine(String.Format("Displaying selected properties of {0}", objADObject.Path));
foreach (string strAttrName in properties)
{
foreach (var objAttrValue in objADObject.Properties[strAttrName])
{
string strAttrValue = objAttrValue.ToString();
Console.WriteLine(String.Format(" {0, -22} : {1}", strAttrName, strAttrValue));
}
}
Console.WriteLine();
}
catch (Exception ex)
{
throw new ApplicationException(string.Format("Fatal error accessing: {0} - {1}", objADObject.Path, ex.Message), ex);
}
}
This is the output:
Displaying selected properties of LDAP://server/o=org/cn=obj
displayName : Display Name
whenCreated : 7/8/2009 7:29:02 PM
whenChanged : 7/8/2009 10:42:23 PM
uSNCreated : System.__ComObject
uSNChanged : System.__ComObject
How do I convert that System.__ComObject into a Int64?
Solution Used:
This is the solution I used based on marc_s's solution below:
public static Int64 ConvertADSLargeIntegerToInt64(object adsLargeInteger)
{
var highPart = (Int32)adsLargeInteger.GetType().InvokeMember("HighPart", System.Reflection.BindingFlags.GetProperty, null, adsLargeInteger, null);
var lowPart = (Int32)adsLargeInteger.GetType().InvokeMember("LowPart", System.Reflection.BindingFlags.GetProperty, null, adsLargeInteger, null);
return highPart * ((Int64)UInt32.MaxValue + 1) + lowPart;
}
I'm using this snippet of code in my ADSI Browser BeaverTail which is written in C#:
Int64 iLargeInt = 0;
IADsLargeInteger int64Val = (IADsLargeInteger)oPropValue.LargeInteger;
iLargeInt = int64Val.HighPart * 4294967296 + int64Val.LowPart;
As far as I can tell, this should work just fine.
Marc
It looks like it's an IADsLargeInteger type, so a little interop magic will be required to extract the values. This Thread contains a sample VB implementation -- and mentions problems similar to your own -- however I'm nowhere near able to verify the usefulness of it right now. Hope this helps.
Related
This has baffled me for a while now and I cannot seem to get the grasp of it. I'm using Cell Value Factory to populate a simple one column table and it does not populate in the table.
It does and I click the rows that are populated but I do not see any values in them- in this case String values. [I just edited this to make it clearer]
I have a different project under which it works under the same kind of data model. What am I doing wrong?
Here's the code. The commented code at the end seems to work though. I've checked to see if the usual mistakes- creating a new column instance or a new tableview instance, are there. Nothing. Please help!
//Simple Data Model
Stock.java
public class Stock {
private SimpleStringProperty stockTicker;
public Stock(String stockTicker) {
this.stockTicker = new SimpleStringProperty(stockTicker);
}
public String getstockTicker() {
return stockTicker.get();
}
public void setstockTicker(String stockticker) {
stockTicker.set(stockticker);
}
}
//Controller class
MainGuiController.java
private ObservableList<Stock> data;
#FXML
private TableView<Stock> stockTableView;// = new TableView<>(data);
#FXML
private TableColumn<Stock, String> tickerCol;
private void setTickersToCol() {
try {
Statement stmt = conn.createStatement();//conn is defined and works
ResultSet rsltset = stmt.executeQuery("SELECT ticker FROM tickerlist order by ticker");
data = FXCollections.observableArrayList();
Stock stockInstance;
while (rsltset.next()) {
stockInstance = new Stock(rsltset.getString(1).toUpperCase());
data.add(stockInstance);
}
} catch (SQLException ex) {
Logger.getLogger(WriteToFile.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Connection Failed! Check output console");
}
tickerCol.setCellValueFactory(new PropertyValueFactory<Stock,String>("stockTicker"));
stockTableView.setItems(data);
}
/*THIS, ON THE OTHER HAND, WORKS*/
/*Callback<CellDataFeatures<Stock, String>, ObservableValue<String>> cellDataFeat =
new Callback<CellDataFeatures<Stock, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<Stock, String> p) {
return new SimpleStringProperty(p.getValue().getstockTicker());
}
};*/
Suggested solution (use a Lambda, not a PropertyValueFactory)
Instead of:
aColumn.setCellValueFactory(new PropertyValueFactory<Appointment,LocalDate>("date"));
Write:
aColumn.setCellValueFactory(cellData -> cellData.getValue().dateProperty());
For more information, see this answer:
Java: setCellValuefactory; Lambda vs. PropertyValueFactory; advantages/disadvantages
Solution using PropertyValueFactory
The lambda solution outlined above is preferred, but if you wish to use PropertyValueFactory, this alternate solution provides information on that.
How to Fix It
The case of your getter and setter methods are wrong.
getstockTicker should be getStockTicker
setstockTicker should be setStockTicker
Some Background Information
Your PropertyValueFactory remains the same with:
new PropertyValueFactory<Stock,String>("stockTicker")
The naming convention will seem more obvious when you also add a property accessor to your Stock class:
public class Stock {
private SimpleStringProperty stockTicker;
public Stock(String stockTicker) {
this.stockTicker = new SimpleStringProperty(stockTicker);
}
public String getStockTicker() {
return stockTicker.get();
}
public void setStockTicker(String stockticker) {
stockTicker.set(stockticker);
}
public StringProperty stockTickerProperty() {
return stockTicker;
}
}
The PropertyValueFactory uses reflection to find the relevant accessors (these should be public). First, it will try to use the stockTickerProperty accessor and, if that is not present fall back to getters and setters. Providing a property accessor is recommended as then you will automatically enable your table to observe the property in the underlying model, dynamically updating its data as the underlying model changes.
put the Getter and Setter method in you data class for all the elements.
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.
Using the example code below as context... When I run this query I get the 'Id' field coming back as default value (which is 0 for an int). I would like to tell dapper to run in a manner where it would throw an exception if there is a column in the result set that does not get mapped to a property on my result object. (I understand that the issue is just that I need to remove the extra 'd' in the SQL query but I'm interested in having this expose itself more explicitly)
I've been unable to find anything on this topic. Please let me know if this is even possible with Dapper.
Thanks in advance (besides this issue, and for anyone who hasn't taken the plunge, Dapper really is the greatest thing since sliced bread!).
class CustomerRecord
{
public int Id { get; set; }
public string Name { get; set; }
}
CustomerRecord[] GetCustomerRecords()
{
CustomerRecord[] ret;
var sql = #"SELECT
CustomerRecordId AS Idd,
CustomerName as Name
FROM CustomerRecord";
using (var connection = new SqlConnection(this.connectionString))
{
ret = connection.Query<CustomerRecord>(sql).ToArray();
}
return ret;
}
You could create your own type map where you use Dapper's DefaultTypeMap and throw an exception when it cannot find the member:
public class ThrowWhenNullTypeMap<T> : SqlMapper.ITypeMap
{
private readonly SqlMapper.ITypeMap _defaultTypeMap = new DefaultTypeMap(typeof(T));
public ConstructorInfo FindConstructor(string[] names, Type[] types)
{
return _defaultTypeMap.FindConstructor(names, types);
}
public ConstructorInfo FindExplicitConstructor()
{
return _defaultTypeMap.FindExplicitConstructor();
}
public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
{
return _defaultTypeMap.GetConstructorParameter(constructor, columnName);
}
public SqlMapper.IMemberMap GetMember(string columnName)
{
var member = _defaultTypeMap.GetMember(columnName);
if (member == null)
{
throw new Exception();
}
return member;
}
}
Downside of this, is that you have to configure all the type maps for every entity:
SqlMapper.SetTypeMap(typeof(CustomerRecord), typeof(ThrowWhenNullTypeMap<CustomerRecord>));
This could be configured using reflection, however.
I came here after I solved this same problem for the IEnumerable<dynamic> methods in Dapper. Then I found the proposal to solve the issue for Query<T>; but that doesn't seem to be going anywhere.
My answer builds on the answer proposed by #HenkMollema, and uses his class in the solution, so credit to him for that...
To solve the IEnumerable<dynamic> scenario, I had created a "SafeDynamic" class (follow the link above to see that). I refactored the static "Create" method into an extension method:
public static class EnumerableDynamicExtensions
{
public static IEnumerable<dynamic> Safe(this IEnumerable<dynamic> rows)
{
return rows.Select(x => new SafeDynamic(x));
}
}
and then I created a DapperExtensions class to provide 'Safe' versions of Query and Read (Read is used after QueryMultiple), to give me...
internal static class DapperExtensions
{
public static IEnumerable<dynamic> SafeQuery(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = default(int?), CommandType? commandType = default(CommandType?))
{
return cnn.Query(sql, param, transaction, buffered, commandTimeout, commandType).Safe();
}
public static IEnumerable<dynamic> SafeRead(this SqlMapper.GridReader gridReader, bool buffered = true)
{
return gridReader.Read(buffered).Safe();
}
}
So to solve this issue I added a "SafeQuery<T>" method to DapperExtensions, which takes care of setting up that type mapping for you:
private static readonly IDictionary<Type, object> TypesThatHaveMapper = new Dictionary<Type, object>();
public static IEnumerable<T> SafeQuery<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = default(int?), CommandType? commandType = default(CommandType?))
{
if (TypesThatHaveMapper.ContainsKey(typeof(T)) == false)
{
SqlMapper.SetTypeMap(typeof(T), new ThrowWhenNullTypeMap<T>());
TypesThatHaveMapper.Add(typeof(T), null);
}
return cnn.Query<T>(sql, param, transaction, buffered, commandTimeout, commandType);
}
So if the original poster changes the call to Query to become SafeQuery, it should do what he requested
Edit 25/1/17
Improvements to avoid threading issues on the static dictionary:
private static readonly ConcurrentDictionary<Type, object> TypesThatHaveMapper = new ConcurrentDictionary<Type, object>();
public static IEnumerable<T> SafeQuery<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = default(int?), CommandType? commandType = default(CommandType?))
{
TypesThatHaveMapper.AddOrUpdate(typeof(T), AddValue, UpdateValue);
return cnn.Query<T>(sql, param, transaction, buffered, commandTimeout, commandType);
}
private static object AddValue(Type type)
{
SqlMapper.SetTypeMap(type, XXX); // Apologies... XXX is left to the reader, as my implementation has moved on significantly.
return null;
}
private static object UpdateValue(Type type, object existingValue)
{
return null;
}
I'd like to expand on #Richardissimo 's answer by providing a visual studio project that includes his "SafeQuery" extention to Dapper, wrapped up nice and neat and tested.
https://github.com/LarrySmith-1437/SafeDapper
I use this in all my projects now to help keep the DAL clean of mismapped data, and felt the need to share. I would have posted up a Nuget, but the dependency on Dapper itself makes it much easier to post the project where consumers can update the reference to the Dapper version they want. Consume in good health, all.
Based on this thread and some other resources on SO, I've created an extension method without any custom mapper. What I needed was to throw when some property of my DTO was not set because for example SQL query has some column missing in SELECT statement.
This way my DTO would be set with default property silently and that's kinda dangerous.
The code can be simplified a little by not checking firstly for all properties being present in result, but throwing exception in the last Select call where we could iterate through properties of our type and check if query result has this property as well.
public static class Extensions
{
public static async Task<IEnumerable<T>> SafeQueryAsync<T>(
this IDbConnection cnn,
string sql,
object param = null,
IDbTransaction transaction = null,
int? commandTimeout = default(int?),
CommandType? commandType = default(CommandType?))
where T : new()
{
Dictionary<string, PropertyInfo> propertySetters = typeof(T)
.GetProperties().Where(p => p.CanRead && p.CanWrite)
.ToDictionary(p => p.Name.ToLowerInvariant(), p => p);
HashSet<string> typeProperties = propertySetters
.Select(p => p.Key)
.ToHashSet();
var rows = (await cnn.QueryAsync(sql, param, transaction, commandTimeout, commandType)).ToArray();
if (!rows.Any())
{
return Enumerable.Empty<T>();
}
var firstRow = rows.First();
HashSet<string> rowColumns = ((IDictionary<string, object>) firstRow)
.Select(kvp=>kvp.Key.ToLowerInvariant()).ToHashSet();
var notMappedColumns = typeProperties.Except(rowColumns).ToArray();
if (notMappedColumns.Any())
{
throw new InvalidOperationException(
$"Not all type properties had corresponding columns in SQL query. Query result lacks [{string.Join(", ", notMappedColumns)}]");
}
return rows.Select(row =>
{
IDictionary<string, object> rowDict = (IDictionary<string, object>) row;
T instance = new T();
rowDict.Where(o => propertySetters.ContainsKey(o.Key.ToLowerInvariant()))
.ToList().ForEach(o => propertySetters[o.Key.ToLowerInvariant()].SetValue(instance, o.Value));
return instance;
}).AsEnumerable();
}
}
I want to capture query component mode(Basic | Advanced) in processQuery event listener method for QueryEvent as below:
public void processQuery(QueryEvent queryEvent)
{
// Add event code here...
QueryDescriptor qdesc = queryEvent.getDescriptor();
String searchName = qdesc.getName();
String queryMode =?
I tried to get this value from getUIHints() map using UIHINT_MODE key. but getUIHints() returns empty map.
Try this :
ViewCriteria vc = null;
try
{
Method m =
pQueryDescriptor.getClass().getDeclaredMethod("getViewCriteria",
null);
m.setAccessible(true);
vc = (ViewCriteria) m.invoke(pQueryDescriptor, null);
}
catch (Exception ite)
{
_logger.logp(Level.SEVERE, CLAZZ_NAME, methodName,
"Exception getting ViewCriteria from QueryDescriptor.",
ite);
}
String searchType =
(String) vc .getProperty(ViewCriteriaHints.CRITERIA_MODE);
The idea is to get the ViewCriteria from the QueryDescriptor and to get the mode from the VC. This is becasue the mode is set on the criteria object itself, the VC knows how to display and what to display in each mode, and so it makes the MODE an inherent property of the VC and not just a UI thing....
QueryDescriptor qdesc = queryEvent.getDescriptor();
QueryDescriptor.QueryMode mode = (QueryDescriptor.QueryMode) qdesc.getUIHints().get(qdesc.UIHINT_MODE);
if("BASIC".equals(mode.toString())){
}
I'm using Spring JdbcTemplate, and I'm stuck at the point where I have a query that updates a column that is actually an array of int. The database is postgres 8.3.7.
This is the code I'm using :
public int setUsersArray(int idUser, int idDevice, Collection<Integer> ids) {
int update = -666;
int[] tipi = new int[3];
tipi[0] = java.sql.Types.INTEGER;
tipi[1] = java.sql.Types.INTEGER;
tipi[2] = java.sql.Types.ARRAY;
try {
update = this.jdbcTemplate.update(setUsersArrayQuery, new Object[] {
ids, idUser, idDevice }, tipi);
} catch (Exception e) {
e.printStackTrace();
}
return update;
}
The query is "update table_name set array_column = ? where id_user = ? and id_device = ?".
I get this exception :
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [update acotel_msp.users_mau set denied_sub_client = ? where id_users = ? and id_mau = ?]; The column index is out of range: 4, number of columns: 3.; nested exception is org.postgresql.util.PSQLException: The column index is out of range: 4, number of columns: 3.
Caused by: org.postgresql.util.PSQLException: The column index is out of range: 4, number of columns: 3.
I've looked into spring jdbc template docs but I can't find any help, I'll keep looking, anyway could someone point me to the right direction? Thanks!
EDIT :
Obviously the order was wrong, my fault...
I tried both your solutions, in the first case I had this :
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [update users set denied_sub_client = ? where id_users = ? and id_device = ?]; nested exception is org.postgresql.util.PSQLException: Cannot cast an instance of java.util.ArrayList to type Types.ARRAY
Trying the second solution I had this :
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [update users set denied_sub_client = ? where id_users = ? and id_device = ?]; nested exception is org.postgresql.util.PSQLException: Cannot cast an instance of [Ljava.lang.Object; to type Types.ARRAY
I suppose i need an instance of java.sql.Array, but how can I create it using JdbcTemplate?
After struggling with many attempts, we settled to use a little helper ArraySqlValue to create Spring SqlValue objects for Java Array Types.
usage is like this
jdbcTemplate.update(
"UPDATE sometable SET arraycolumn = ?",
ArraySqlValue.create(arrayValue))
The ArraySqlValue can also be used in MapSqlParameterSource for use with NamedParameterJdbcTemplate.
import static com.google.common.base.Preconditions.checkNotNull;
import java.sql.Array;
import java.sql.JDBCType;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Locale;
import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.jdbc.support.SqlValue;
public class ArraySqlValue implements SqlValue {
private final Object[] arr;
private final String dbTypeName;
public static ArraySqlValue create(final Object[] arr) {
return new ArraySqlValue(arr, determineDbTypeName(arr));
}
public static ArraySqlValue create(final Object[] arr, final String dbTypeName) {
return new ArraySqlValue(arr, dbTypeName);
}
private ArraySqlValue(final Object[] arr, final String dbTypeName) {
this.arr = checkNotNull(arr);
this.dbTypeName = checkNotNull(dbTypeName);
}
#Override
public void setValue(final PreparedStatement ps, final int paramIndex) throws SQLException {
final Array arrayValue = ps.getConnection().createArrayOf(dbTypeName, arr);
ps.setArray(paramIndex, arrayValue);
}
#Override
public void cleanup() {}
private static String determineDbTypeName(final Object[] arr) {
// use Spring Utils similar to normal JdbcTemplate inner workings
final int sqlParameterType =
StatementCreatorUtils.javaTypeToSqlParameterType(arr.getClass().getComponentType());
final JDBCType jdbcTypeToUse = JDBCType.valueOf(sqlParameterType);
// lowercasing typename for Postgres
final String typeNameToUse = jdbcTypeToUse.getName().toLowerCase(Locale.US);
return typeNameToUse;
}
}
this code is provided in the Public Domain
private static final String ARRAY_DATATYPE = "int4";
private static final String SQL_UPDATE = "UPDATE foo SET arr = ? WHERE d = ?";
final Integer[] existing = ...;
final DateTime dt = ...;
getJdbcTemplate().update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(final Connection con) throws SQLException {
final PreparedStatement ret = con.prepareStatement(SQL_UPDATE);
ret.setArray(1, con.createArrayOf(ARRAY_DATATYPE, existing));
ret.setDate(2, new java.sql.Date(dt.getMillis()));
return ret;
}
});
This solution is kind of workaround using postgreSQL built-in function, which definitely worked for me.
reference blog
1) Convert String Array to Comma Separated String
If you are using Java8, it's pretty easy. other options are here
String commaSeparatedString = String.join(",",stringArray); // Java8 feature
2) PostgreSQL built-in function string_to_array()
you can find other postgreSQL array functions here
// tableName ( name text, string_array_column_name text[] )
String query = "insert into tableName(name,string_array_column_name ) values(?, string_to_array(?,',') )";
int[] types = new int[] { Types.VARCHAR, Types.VARCHAR};
Object[] psParams = new Object[] {"Dhruvil Thaker",commaSeparatedString };
jdbcTemplate.batchUpdate(query, psParams ,types); // assuming you have jdbctemplate instance
The cleanest way I found so far is to first convert the Collection into an Integer[] and then use the Connection to convert that into an Array.
Integer[] idArray = ids.toArray(new Integer[0]);
Array idSqlArray = jdbcTemplate.execute(
(Connection c) -> c.createArrayOf(JDBCType.INTEGER.getName(), idArray)
);
update = this.jdbcTemplate.update(setUsersArrayQuery, new Object[] {
idSqlArray, idUser, idDevice })
This is based on information in the documentation: https://jdbc.postgresql.org/documentation/head/arrays.html
The argument type and argument is not matching.
Try changing the argument type order
int[] tipi = new int[3];
tipi[0] = java.sql.Types.ARRAY;
tipi[1] = java.sql.Types.INTEGER;
tipi[2] = java.sql.Types.INTEGER;
or use
update = this.jdbcTemplate.update(setUsersArrayQuery, new Object[] {
ids.toArray(), idUser, idDevice })
and see if it works
http://valgogtech.blogspot.com/2009/02/passing-arrays-to-postgresql-database.html explains how to create java.sql.Array postgresql
basically Array.getBaseTypeName should return int and Array.toString should return the array content in "{1,2,3}" format
after you create the array you can set it using preparedstatement.setArray(...)
from PreparedStatementCreator e.g.
jdbcTemplate.update(
new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
Good Luck ..
java.sql.Array intArray = connection.createArrayOf("int", existing);
List<Object> values= new ArrayList<Object>();
values.add(intArray);
values.add(dt);
getJdbcTemplate().update(SQL_UPDATE,values);