We use Nhibernate 3.3 to connect to our Sybase Ase 15 database. Everything is fine except for the non support of the limit (or top). It is implemented in sybase but not in Nhibernate.
Do you have a solution?
I tried to create a CustomSybaseAse15Dialect where I change this:
public override bool SupportsLimitOffset
{
get { return true; }
}
public override SqlString GetLimitString(SqlString sql, SqlString offset, SqlString limit)
{
int insertionPoint = GetAfterSelectInsertPoint(sql);
if (insertionPoint > 0)
{
SqlStringBuilder limitBuilder = new SqlStringBuilder();
limitBuilder.Add("select");
if (insertionPoint > 6)
{
limitBuilder.Add(" distinct ");
}
limitBuilder.Add(" top ");
limitBuilder.Add(limit);
if (offset != null)
{
limitBuilder.Add(" start at ");
limitBuilder.Add(offset);
}
limitBuilder.Add(sql.Substring(insertionPoint));
return limitBuilder.ToSqlString();
}
else
{
return sql; // unchanged
}
}
/// <summary>
/// Copied from MsSql2000Dialect.
/// </summary>
private int GetAfterSelectInsertPoint(SqlString sql)
{
if (sql.StartsWithCaseInsensitive("select distinct"))
{
return 15;
}
if (sql.StartsWithCaseInsensitive("select"))
{
return 6;
}
throw new NotSupportedException("The query should start with 'SELECT' or 'SELECT DISTINCT'");
}
Using the Linq2Nhibernate syntax, it works good with
Session.Query<product>().First()
limit is correctly set to 1 but if I do this
Session.Query<product>().Take(3).ToList()
limit is set to "?".
What can I do?
as mentioned in the previous comment there is a bug in nHibernate. It is already fixed but not yet included in an official version.
https://nhibernate.jira.com/browse/NH-3281
You can download the main source and build the dll manually from https://github.com/nhibernate/nhibernate-core .
Michael
For anyone finding this question recently:
This is fixed in the release version of nHibernate 4.1.
You also need to add to the dialect:
public override bool SupportsVariableLimit { get { return false; } }
to address the lack of support for placeholders in "select top X" (it defaults to whatever SupportsLimit is)
Related
I have an ASP.NET Core MVC application that might be restarted from time to time (maintenance); how can make some variable values persistent from an execution to the next?
PS: That's the code that needs to write value as persistent. For example "LastMaintenanceRestartTime = 03/04-2020", the maintenance restart occurs once a day so the code needs to remember the last time it was restarted.
In UWP, I could do the following code but I can't seem to find an equivalent for ASP.NET Core:
Windows.Storage.ApplicationData.Current.LocalSettings.Values[key] = value;
The best I could find is the following code but the values are only persistent within the same execution:
AppDomain.CurrentDomain.SetData(key, value);
Some talk about "Application.Settings" but I can't seem to be able to reach this namespace...
I've also seen some people talking about "AppSettings" files that can be modified during execution but it seems rather complex to keep a simple value persistent...
Do you have any recommendation, solution or ideas for me?
I found the solution:
static void ReadSetting(string key)
{
try
{
var appSettings = ConfigurationManager.AppSettings;
string result = appSettings[key] ?? "Not Found";
Console.WriteLine(result);
}
catch (ConfigurationErrorsException)
{
Console.WriteLine("Error reading app settings");
}
}
static void AddUpdateAppSettings(string key, string value)
{
try
{
var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = configFile.AppSettings.Settings;
if (settings[key] == null)
{
settings.Add(key, value);
}
else
{
settings[key].Value = value;
}
configFile.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);
}
catch (ConfigurationErrorsException)
{
Console.WriteLine("Error writing app settings");
}
}
Link: https://learn.microsoft.com/en-us/dotnet/api/system.configuration.configurationmanager.appsettings?redirectedfrom=MSDN&view=dotnet-plat-ext-5.0#System_Configuration_ConfigurationManager_AppSettings
Create a model to save data and last execution time
public class ApplicationData {
public DateTime LastExecutionTime {get;set;}
public string Data {get;set;}
public bool isRunningFirstTime {get;set}
}
1.On first application run, model should be updated to current values and isRunningFirstTime should be set to false.
2. On second run, read or update values based on date and application running count
Expanding on #rashidali answer (and not saying best, but):
public class ApplicationData
{
private DateTime _lastExecutionTime;
public DateTime LastExecutionTime
{
get
{
_lastExecutionTime = (read from file/database);
return _lastExecutionTime;
}
set
{
_lastExecutionTime = value;
(write _lastExecutionTime to file/database);
}
}
public string Data {get;set;}
public bool isRunningFirstTime {get;set}
}
I'm using Linq2NHibernate 3.0 with sybase ASE 15.
My first problem was that the dialect does not support limits ("select top 5 ..."). As a consequence, I made a custom dialect overriding those methods :
public override bool SupportsLimit
{
get { return true; }
}
public override bool SupportsLimitOffset
{
get { return true; }
}
public override bool SupportsVariableLimit
{
get
{
return true;
}
}
public new int GetLimitValue(int offset, int limit)
{
//TOOK FROM ANOTHER DIALECT
if (limit == int.MaxValue)
return int.MaxValue;
if (UseMaxForLimit)
return GetOffsetValue(offset) + limit;
return limit;
}
public override SqlString GetLimitString(SqlString sql, SqlString offset, SqlString limit)
{
//TOOK FROM ANOTHER DIALECT EXCEPT THAT I CALL ANOTHER CUSTOM CLASS
}
NOTE : I USE ANOTHER CLASS TO PASS THE LIMIT VALUE INTO GetLimitString USING LOCKS (I did not find a better alternative)
I thought it worked fine but GetLimitString is only called once, as a result, if I change the limit value, it is not taken into account.
So, my problem can be solved two ways: you have a better custom dialect for Sybase, or you know why GetLimitString is only called once.
Thanks in advance
How do I define a postgis 'geography' type in my C# class model so that OrmLite can easily pass it through to Postgresql so I can run spatial queries in addition to saving spatial data to the 'geography' column?
The best library is NetTopologySuite for this case;
you can use like this;
protected GisSharpBlog.NetTopologySuite.Geometries.Geometry _geom;
public GisSharpBlog.NetTopologySuite.Geometries.Geometry Geom
{
get { return _geom; }
set { _geom = value; }
}
protected string _geomwkt;
public virtual string GeomWKT
{
get
{
if (this.Geom != null)
return this.Geom.ToText();
else
return "";
}
set
{
string wktString = value;
if (string.IsNullOrEmpty(wktString))
_geom = null;
else
{
var fact = new GeometryFactory();
var wktreader = new WKTReader(fact);
_geom = (Geometry)wktreader.Read(wktString);
}
}
}
I am having the difficulty to understand NHibernate an petapoco loading mechanism. Actually I did a test to compare how both behave upon a query.
My class is as follows:
UserTest.cs with the following properties:
private string name;
private int id;
private int customerId;
public int ID
{
get { return id; }
set { id = value; }
}
public string Name
{
get { return name; }
set { name = value; }
}
public int? CustomerID
{
get { return customerId; }
set
{
if (value != customerId)
{
customerId = value;
if (this.ID > 0)
{
DoSomeOtherWork();
}
}
}
}
When I do a User.Load in NHibernate, I have observed that DoSomeOtherWork is never called whereas in PetaPoco, when I do a query from loading User such as Connection.db.Fetch<UserTest>(...) or Connection.db.Query<UserTest>(...), I can see that DoSomeOtherWork is called.
Why is that so?
Is there a way to avoid calling DoSomeOherWork when using PetaPoco such that it has the same behaviour as NHibernate? I dont want to usePetaPoco.Ignoreas I need to get and set theCustomerID`.
PetaPoco it a micro-ORM (much lighter than Nhibernate) and materializes your POCO object when you fetch the record. There is no other magic than that, so the answer is:
No, you can't avoid calling the setter of the property.
This question could be a bit difficult to find the answer. It's a questions in one series with What is the reason that Policy.getPolicy() is considered as it will retain a static reference to the context and can cause memory leak. You can read it so you may know more background.
Graped the source code from org.apache.cxf.common.logging.JDKBugHacks and also from org.apache.catalina.core.JreMemoryLeakPreventionListener.
There is a piece of code. Here it is.
URL url = new URL("jar:file://dummy.jar!/");
URLConnection uConn = new URLConnection(url) {
#Override
public void connect() throws IOException{
// NOOP
}
};
uConn.setDefaultUseCaches(false);
The comment said
/*
* Several components end up opening JarURLConnections without
* first disabling caching. This effectively locks the file.
* Whilst more noticeable and harder to ignore on Windows, it
* affects all operating systems.
*
* Those libraries/components known to trigger this issue
* include:
* - log4j versions 1.2.15 and earlier
* - javax.xml.bind.JAXBContext.newInstance()
*/
However I can hardly understand it. Why did they eagerly call setDefaultUseCaches(false) and why on Windows it's harmful that by default cache is true? I cannot find any clue in java.net.JarURLConnection.
I myself find an answer. Any one can correct me if you think I am wrong.
in sun.net.www.protocol.jar.JarURLConnection. I assume this is the default implementation of java.net.JarURLConnection. There is a piece of code below.
If cache is set to true, then it will not close the JarFile's connection. Which means it is locked.
class JarURLInputStream extends java.io.FilterInputStream {
JarURLInputStream (InputStream src) {
super (src);
}
public void close () throws IOException {
try {
super.close();
} finally {
if (!getUseCaches()) {
jarFile.close(); //will not close
}
}
}
}
public void connect() throws IOException {
if (!connected) {
/* the factory call will do the security checks */
jarFile = factory.get(getJarFileURL(), getUseCaches());
/* we also ask the factory the permission that was required
* to get the jarFile, and set it as our permission.
*/
if (getUseCaches()) {
jarFileURLConnection = factory.getConnection(jarFile);
}
if ((entryName != null)) {
jarEntry = (JarEntry)jarFile.getEntry(entryName);
if (jarEntry == null) {
try {
if (!getUseCaches()) {
jarFile.close(); //will not close
}
} catch (Exception e) {
}
throw new FileNotFoundException("JAR entry " + entryName +
" not found in " +
jarFile.getName());
}
}
connected = true;
}
}