C# 在执行ISQLQuery.UniqueResult<;日期时间>;()?
TLDR:C# 在执行ISQLQuery.UniqueResult<;日期时间>;()?,c#,sqlite,datetime,nhibernate,isqlquery,C#,Sqlite,Datetime,Nhibernate,Isqlquery,TLDR: 以下代码在不同的数据库Oracle中运行:selectsysdatefromtoualSQLiteselectdatetime('now') 执行Session.CreateSQLQuery(cmd).UniqueResult()操作Oracle时,结果是日期时间,但操作SQLite时是字符串 这感觉像是SQLite驱动程序中的一个bug,检查返回的类型并执行DateTime.Parse()操作(如果是字符串)。我可以这么做,但是有没有办法让NHibernate返回正确的类型 我正在
以下代码在不同的数据库Oracle中运行:
selectsysdatefromtoual
SQLiteselectdatetime('now')
执行Session.CreateSQLQuery(cmd).UniqueResult()
操作Oracle时,结果是日期时间,但操作SQLite时是字符串
这感觉像是SQLite驱动程序中的一个bug,检查返回的类型并执行DateTime.Parse()操作(如果是字符串)。我可以这么做,但是有没有办法让NHibernate返回正确的类型 我正在尝试从数据库获取当前数据库时间。它在使用Oracle时运行良好,但当我尝试对SQLite(在我的单元测试中)执行此操作时,它会中断,因为返回的日期不是DateTime,而是字符串 我见过使用自定义IUserType的解决方案,但我不知道在这种情况下应该如何使用它。有什么建议吗
using System;
using System.Collections.Generic;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Dialect.Function;
namespace My.Common.Types {
public class MyNHibernateDialectException : Exception {
public MyNHibernateDialectException(string message) : base(message) { }
}
/// <summary>
/// Define all custom functions here by name. It is important that when adding a new custom sql function, that function will work
/// in all dialects supported.
/// </summary>
public static class MyDatabaseDialects {
public enum Query {
SysDate
}
/// <summary>
/// Dialect implementations will use this function to verify that they all implement the same functions.
/// </summary>
/// <param name="dialect"></param>
public static void VerifyRegistrations(this NHibernate.Dialect.Dialect dialect) {
// Verify that the required function are there
foreach (var func in Enum.GetValues(typeof(Function))) {
var enumName = func.ToString();
if (!dialect.Functions.ContainsKey(enumName)) {
throw new MyNHibernateDialectException(
string.Format("The custom function '{0}' is not defined. Did you forget it in factory '{1}'?", enumName, dialect));
}
}
}
}
/// <summary>
/// An interface to reveal more advanced functionality that is database specific
/// </summary>
public interface IDialectExtensions {
/// <summary>
/// Fetch a query specfic for the current database.
/// </summary>
ISQLQuery GetQuery(ISession session, MyDatabaseDialects.Query query);
/// <summary>
/// Fetch a parameterized query specfic for the current database.
/// </summary>
ISQLQuery GetQuery(ISession session, MyDatabaseDialects.Query query, params object[] queryParams);
}
/// <summary>
/// Class to store database specific objects except functions (which are supported by NHibernate).
/// </summary>
class DialectExtension {
private readonly Dictionary<MyDatabaseDialects.Query, string> queryDictionary = new Dictionary<MyDatabaseDialects.Query, string>();
public ISQLQuery GetQuery(ISession session, MyDatabaseDialects.Query query) {
return this.GetQuery(session, query, null);
}
public ISQLQuery GetQuery(ISession session, MyDatabaseDialects.Query query, params object[] queryParams) {
var cmd = (queryParams == null) ? queryDictionary[query] : string.Format(queryDictionary[query], queryParams);
return session.Session.CreateSQLQuery(cmd);
}
public void RegisterQuery(MyDatabaseDialects.Query query, string hqlString) {
queryDictionary.Add(query, hqlString);
}
public void VerifyQueryRegistrations() {
foreach (var query in Enum.GetValues(typeof(MyDatabaseDialects.Query))) {
if (!queryDictionary.ContainsKey((MyDatabaseDialects.Query)query)) {
throw new MyNHibernateDialectException(string.Format("The custom query '{0}' is not defined.", query.ToString()));
}
}
}
}
public class MyOracle10gDialect : NHibernate.Dialect.Oracle10gDialect, IDialectExtensions {
private readonly DialectExtension dialectExtension = new DialectExtension();
public MyOracle10gDialect() {
#region Dialect extensions
dialectExtension.RegisterQuery(MyDatabaseDialects.Query.SysDate, @"select sysdate from dual");
dialectExtension.VerifyQueryRegistrations();
#endregion Dialect extensions
}
public ISQLQuery GetQuery(ISession session, MyDatabaseDialects.Query query) {
return dialectExtension.GetQuery(session, query);
}
public ISQLQuery GetQuery(ISession session, MyDatabaseDialects.Query query, params object[] queryParams) {
return dialectExtension.GetQuery(session, query, queryParams);
}
}
public class MySqliteDialect : NHibernate.Dialect.SQLiteDialect, IDialectExtensions {
private readonly DialectExtension dialectExtension = new DialectExtension();
public MySqliteDialect() {
#region Dialect extensions
dialectExtension.RegisterQuery(MyDatabaseDialects.Query.SysDate, @"select datetime('now')");
dialectExtension.VerifyQueryRegistrations();
#endregion Dialect extensions
}
public ISQLQuery GetQuery(ISession session, MyDatabaseDialects.Query query) {
return dialectExtension.GetQuery(session, query);
}
public ISQLQuery GetQuery(ISession session, MyDatabaseDialects.Query query, params object[] queryParams) {
return dialectExtension.GetQuery(session, query, queryParams);
}
}
}
使用系统;
使用System.Collections.Generic;
使用NHibernate;
使用NHibernate.标准;
使用NHibernate.dial.Function;
名称空间My.Common.Types{
公共类MyNHibernateDialectException:异常{
公共MyNHibernateDialectException(字符串消息):基(消息){}
}
///
///在此处按名称定义所有自定义函数。添加新的自定义sql函数时,该函数将正常工作,这一点很重要
///在所有方言中都支持。
///
公共静态类MyDatabase方言{
公共枚举查询{
系统日期
}
///
///方言实现将使用此函数验证它们是否都实现相同的函数。
///
///
公共静态无效验证注册(此NHibernate.dialogue.dialogue){
//验证所需的功能是否存在
foreach(Enum.GetValues中的var func(typeof(Function))){
var enumName=func.ToString();
if(!dialent.Functions.ContainsKey(enumName)){
抛出新的MyNHibernateDialectException(
Format(“未定义自定义函数“{0}”。是否在工厂“{1}”中忘记了它?”,enumName,方言));
}
}
}
}
///
///一个界面,用于显示特定于数据库的更高级功能
///
公共接口IDialectExtensions{
///
///获取当前数据库的特定查询。
///
ISQLQuery GetQuery(ISession会话,MyDatabaseDialogons.Query);
///
///获取当前数据库的参数化查询specfic。
///
ISQLQuery GetQuery(ISession会话,MyDatabaseDialogons.Query查询,参数对象[]queryParams);
}
///
///类来存储特定于数据库的对象,函数除外(由NHibernate支持)。
///
类方言扩展{
私有只读字典queryDictionary=新字典();
公共ISQLQuery GetQuery(ISession会话,MyDatabaseDialogons.Query查询){
返回此.GetQuery(会话,查询,空);
}
公共ISQLQuery GetQuery(ISession会话,MyDatabaseDialogons.Query查询,参数对象[]queryParams){
var cmd=(queryParams==null)?queryDictionary[query]:string.Format(queryDictionary[query],queryParams);
返回session.session.CreateSQLQuery(cmd);
}
public void RegisterQuery(mydatabasedialogons.Query查询,字符串hqlString){
添加(查询,hqlString);
}
公共无效验证查询注册(){
foreach(Enum.GetValues(typeof(mydatabasedialogons.query))中的变量查询){
if(!queryDictionary.ContainsKey((mydatabasedialogs.Query)Query)){
抛出新的MyNHibernateDialectException(string.Format(“自定义查询“{0}”未定义。”,query.ToString());
}
}
}
}
公共类Myoracle10gDialogue:NHibernate.dialogue.oracle10gDialogue,IDialectExtensions{
私有只读方言扩展=新方言扩展();
公共myoracle10g方言(){
#区域方言扩展
RegisterQuery(MyDatabaseDiagnols.Query.SysDate,@“从双变量中选择SysDate”);
方言扩展。VerifyQueryRegistrations();
#端区方言扩展
}
公共ISQLQuery GetQuery(ISession会话,MyDatabaseDialogons.Query查询){
返回tylension.GetQuery(会话,查询);
}
公共ISQLQuery GetQuery(ISession会话,MyDatabaseDialogons.Query查询,参数对象[]queryParams){
return方言扩展名.GetQuery(会话、查询、查询参数);
}
}
公共类mysqlitedialent:NHibernate.dialent.sqlitedialent,IDialectExtensions{
私有只读方言扩展=新方言扩展();
公共mysqlite方言(){
#区域方言扩展
RegisterQuery(MyDatabaseDiagnols.Query.SysDate,@“选择日期时间('now')”);
方言扩展。VerifyQueryRegistrations();
#端区方言扩展
}
公共ISQLQuery GetQuery(ISession会话,MyDatabaseDialogons.Query查询){
返回tylension.GetQuery(会话,查询);
}
公共ISQLQuery GetQuery(ISession会话,MyDatabaseDialogons.Query查询,参数对象[]queryParams){
return方言扩展名.GetQuery(会话、查询、查询参数);
}
}
}
我使用上面的代码如下:
/// <summary>
/// Fetches a DialectExtensions object allowing us to have more advanced functionality that is database specific
/// </summary>
public static IDialectExtensions GetDialectExtensions(this IOperationContext operationContext) {
return Session.GetSessionImplementation().Factory.Dialect as IDialectExtensions;
}
/// <summary>
/// Get the database time by executing a raw SQL statement.
/// </summary>
public static DateTime? GetDatabaseTime() {
DateTime? result = null;
try {
result = GetDialectExtensions()
.GetQuery(Session, MyDatabaseDialects.Query.SysDate)
.UniqueResult<DateTime>();
} catch {
// SQLite will throw exception here as the result is returned as a string instead of a DateTime
}
return result;
}
//
///获取一个对象,使我们能够拥有更高级的特定于数据库的功能
///
公共静态IDialectExtensions GetDiagnolExtensions(t
select cast(Property as DateTime) from Entity
var value = Convert.ToDateTime(query.UniqueResult());
public class SQLiteDialect extends Dialect {
public SQLiteDialect() {
super();
registerColumnType(Types.BIT, "integer");
registerColumnType(Types.TINYINT, "tinyint");
registerColumnType(Types.SMALLINT, "smallint");
registerColumnType(Types.INTEGER, "integer");
registerColumnType(Types.BIGINT, "bigint");
registerColumnType(Types.FLOAT, "float");
registerColumnType(Types.REAL, "real");
registerColumnType(Types.DOUBLE, "double");
registerColumnType(Types.NUMERIC, "numeric");
registerColumnType(Types.DECIMAL, "decimal");
registerColumnType(Types.CHAR, "char");
registerColumnType(Types.VARCHAR, "varchar");
registerColumnType(Types.LONGVARCHAR, "longvarchar");
registerColumnType(Types.DATE, "date");
registerColumnType(Types.TIME, "time");
registerColumnType(Types.TIMESTAMP, "longvarchar");
registerColumnType(Types.TIMESTAMP, "datetime");
registerColumnType(Types.BINARY, "blob");
registerColumnType(Types.VARBINARY, "blob");
registerColumnType(Types.LONGVARBINARY, "blob");
// registerColumnType(Types.NULL, "null");
registerColumnType(Types.BLOB, "blob");
registerColumnType(Types.CLOB, "clob");
registerColumnType(Types.BOOLEAN, "integer");
registerColumnType(Types.NULL, "null");
registerHibernateType(Types.NULL, "null");
registerFunction("concat", new VarArgsSQLFunction(IntegerType.INSTANCE,
"", "||", ""));
registerFunction("mod", new SQLFunctionTemplate(IntegerType.INSTANCE,
"?1 % ?2"));
registerFunction("substr", new StandardSQLFunction("substr",
IntegerType.INSTANCE));
registerFunction("substring", new StandardSQLFunction("substr",
IntegerType.INSTANCE));
registerFunction("replace", new StandardSQLFunction("replace",
IntegerType.INSTANCE));
registerFunction("current_time", new NoArgSQLFunction(
"datetime('now')",
CalendarType.INSTANCE, false));
registerFunction("current_timestamp", new NoArgSQLFunction(
"strftime('%s','now')*1000", CalendarType.INSTANCE, false));
registerFunction("current_date", new NoArgSQLFunction(
"strftime('%s','now')*1000",
CalendarType.INSTANCE, false));
registerFunction(
"trunc",
new SQLFunctionTemplate(IntegerType.INSTANCE,
"cast (strftime(\"%d-%m-%Y\", ?1/1000, 'unixepoch', 'localtime') as string)"));
registerFunction(
"second",
new SQLFunctionTemplate(IntegerType.INSTANCE,
"cast (strftime(\"%S\", ?1/1000, 'unixepoch', 'localtime') as integer)"));
registerFunction(
"minute",
new SQLFunctionTemplate(IntegerType.INSTANCE,
"cast (strftime(\"%M\", ?1/1000, 'unixepoch', 'localtime') as integer)"));
registerFunction(
"hour",
new SQLFunctionTemplate(IntegerType.INSTANCE,
"cast (strftime(\"%H\", ?1/1000, 'unixepoch', 'localtime') as integer)"));
registerFunction(
"day",
new SQLFunctionTemplate(IntegerType.INSTANCE,
"cast (strftime(\"%d\", ?1/1000, 'unixepoch', 'localtime') as integer)"));
registerFunction(
"month",
new SQLFunctionTemplate(IntegerType.INSTANCE,
"cast (strftime(\"%m\", ?1/1000, 'unixepoch', 'localtime') as integer)"));
registerFunction(
"year",
new SQLFunctionTemplate(IntegerType.INSTANCE,
"cast (strftime(\"%Y\", ?1/1000, 'unixepoch', 'localtime') as integer)"));
registerFunction("trim", new AbstractAnsiTrimEmulationFunction() {
protected SQLFunction resolveBothSpaceTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING,
"trim(?1)");
}
protected SQLFunction resolveBothSpaceTrimFromFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING,
"trim(?2)");
}
protected SQLFunction resolveLeadingSpaceTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING,
"ltrim(?1)");
}
protected SQLFunction resolveTrailingSpaceTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING,
"rtrim(?1)");
}
protected SQLFunction resolveBothTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING,
"trim(?1, ?2)");
}
protected SQLFunction resolveLeadingTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING,
"ltrim(?1, ?2)");
}
protected SQLFunction resolveTrailingTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING,
"rtrim(?1, ?2)");
}
});
}
@Override
public boolean supportsIdentityColumns() {
return true;
}
/*
* public boolean supportsInsertSelectIdentity() { return true; // As
* specify in NHibernate dialect }
*/
@Override
public boolean hasDataTypeInIdentityColumn() {
return false; // As specify in NHibernate dialect
}
/*
* public String appendIdentitySelectToInsert(String insertString) { return
* new StringBuffer(insertString.length()+30). // As specify in NHibernate
* dialect append(insertString).
* append("; ").append(getIdentitySelectString()). toString(); }
*/
@Override
public String getIdentityColumnString() {
// return "integer primary key autoincrement";
return "integer";
}
@Override
public String getIdentitySelectString() {
return "select last_insert_rowid()";
}
@Override
public boolean supportsLimit() {
return true;
}
// Added fix from bug,
// http://code.google.com/p/hibernate-sqlite/issues/detail?id=1
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
@Override
public String getLimitString(String query, boolean hasOffset) {
return new StringBuffer(query.length() + 20).append(query)
.append(hasOffset ? " limit ? offset ?" : " limit ?").toString();
}
@Override
public String getLimitString(final String s, final int min, final int max) {
String limitString = super.getLimitString(s, min, max);
return limitString;
}
@Override
public boolean supportsTemporaryTables() {
return true;
}
@Override
public String getCreateTemporaryTableString() {
return "create temporary table if not exists";
}
@Override
public boolean dropTemporaryTableAfterUse() {
return false;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public String getCurrentTimestampSelectString() {
return "select current_timestamp";
}
@Override
public boolean supportsUnionAll() {
return true;
}
@Override
public boolean hasAlterTable() {
return false; // As specify in NHibernate dialect
}
@Override
public boolean dropConstraints() {
return false;
}
@Override
public String getAddColumnString() {
return "add column";
}
@Override
public String getForUpdateString() {
return "";
}
@Override
public boolean supportsOuterJoinForUpdate() {
return false;
}
@Override
public String getDropForeignKeyString() {
throw new UnsupportedOperationException(
"No drop foreign key syntax supported by SQLiteDialect");
}
@Override
public String
getAddForeignKeyConstraintString(String constraintName,
String[] foreignKey,
String referencedTable,
String[] primaryKey,
boolean referencesPrimaryKey) {
throw new UnsupportedOperationException(
"No add foreign key syntax supported by SQLiteDialect");
}
@Override
public String getAddPrimaryKeyConstraintString(String constraintName) {
throw new UnsupportedOperationException(
"No add primary key syntax supported by SQLiteDialect");
}
@Override
public boolean supportsIfExistsBeforeTableName() {
return true;
}
@Override
public boolean supportsIfExistsAfterTableName() {
return false;
}
@Override
public boolean supportsCascadeDelete() {
return false;
}
}
private SessionFactory buildSessionFactory() throws Exception {
StandardServiceRegistryBuilder serviceRegistryBuilder =
new StandardServiceRegistryBuilder();
org.hibernate.cfg.Configuration config = new Configuration();
config.setProperty("hibernate.dialect", dialect);
//Any additional config options, or just set this in your hibernate xml config...
serviceRegistryBuilder.applySettings(config.getProperties());
ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
sessionFactory = config.buildSessionFactory(serviceRegistry);
return sessionFactory;
}