Subsonic 3 Simple Repository And Transactions - subsonic3

So this is what I have so far. Am I doing something wrong or is there a bug in 3.0.0.3?
var Repository = new SimpleRepository("DBConnectionName");
using (TransactionScope ts = new TransactionScope())
{
using (SharedDbConnectionScope scs = new SharedDbConnectionScope("connstring", "providerName"))
{
try
{
for (int i = 0; i < 5; i++)
{
Supplier s = new Supplier();
s.SupplierCode = i.ToString();
s.SupplierName = i.ToString();
Repository.Add<Supplier>(s);
}
ts.Complete();
}
catch
{
}
}
}
I'm getting an error in SubSonic DbDataProvider
public DbConnection CurrentSharedConnection
{
get { return __sharedConnection; }
protected set
{
if(value == null)
{
__sharedConnection.Dispose();
etc..
__sharedConnection == null :( Object Null Reference Exception :(

Finally solved this for myself. All of the above code does not work for me (SubSonic 3.0.0.3, using SQLite) but adding BeginTransaction() caused it to work as expected, greatly speeding up the transaction and rolling back the updates if any exceptions occur.
using (SharedDbConnectionScope sharedConnectionScope = new SharedDbConnectionScope(Access.Provider))
{
using (IDbTransaction ts = sharedConnectionScope.CurrentConnection.BeginTransaction())
{
IRepository repo = new SimpleRepository(Access.Provider);
//Do your database updates
//throw new ApplicationException("Uncomment this and see if the updates get rolled back");
ts.Commit();
}
}
For completeness: Access.Provider is a static property in a helper class for me that returns return SubSonic.DataProviders.ProviderFactory.GetProvider(ConnectionString, "System.Data.SQLite");

Perhaps switching the SharedDbConnectionScope and TransactionScope around may help.
using (SharedDbConnectionScope scs = new SharedDbConnectionScope("connstring", "providerName"))
{
using (TransactionScope ts = new TransactionScope())
{
}
}

This will happen when Migration is set - On tablemigration the dbconnection will be closed.
Try the SimpleRepository with SimpleRepositoryOptions.None.
Don't know if this is a bug. I think the transactions don't work with SimpleRepository, I've always half of the data saved when throwing an exception in the transaction... perhaps it's only for ActiveRecord? Anybody knows?

Related

Connect and query database in Managed C++ using SqlConnection

I'm building a project in C++ in Visual Studio 2012 and I've started by writing some classes for database access. Using SQL Server data tools I've managed to create a SQL project in my solution.
Now, my question is: How can I use the types in System::Data::SqlClient namespace to connect to the database in my code? All the examples I get are using the database as reference.
Thanks in advance
If my answer helps someone, I have used the classes SqlDataReader and SqlCommand in order to select some data from db. Note that I'm fetching the ConnectionString from an App.Config I've created earlier (how it could be done).
SqlDataReader getSqlDataReader(String ^_sql)
{
SqlDataReader ^_sqlDataReader = nullptr;
SqlConnection ^_connection = gcnew SqlConnection();
ConnectionStringSettings ^connectionSettings = ConfigurationManager::ConnectionStrings["AppDefaultConnection"];
this->_connection->ConnectionString = connectionSettings->ConnectionString;
try {
this->_connection->Open();
}
catch (Exception ^_exception)
{
Console::WriteLine("Error : " + _exception->Message);
return nullptr;
}
try
{
SqlCommand ^_sqlCommand = gcnew SqlCommand(_sql,_connection);
_sqlDataReader = _sqlCommand->ExecuteReader();
}
catch(Exception ^_exception)
{
Console::WriteLine("Error : " + _exception->Message);
return nullptr;
}
return _sqlDataReader;
}
To proper build the SQL we should be aware of the class SqlParameter (example for C#) and avoid SQL injection attacks.
To use the getSqlDataReader function:
SqlDataReader ^reader = getSqlDataReader(yourParameterizedQueryString);
List<TypeToFetch>^ data = gcnew List<TypeToFetch^>();
if(reader != nullptr && reader->HasRows)
{
TypeToFetch^ typeToFetch = gcnew TypeToFetch();
while(reader->Read())
{
// example
TypeToFetch->id = (int) reader["Id"];
TypeToFetch->name = reader["Name"]->ToString();
data->Add(typeToFetch);
}
}
This question/answer can help on INSERT.

C++/CX WinRT File Copy

I'm really suffering through the WinRT Windows::Storage namespace with all it's asyncronousness.
I have the following private members in my header file:
//Members for copying the SQLite db file
Platform::String^ m_dbName;
Windows::Storage::StorageFolder^ m_localFolder;
Windows::Storage::StorageFolder^ m_installFolder;
Windows::Storage::StorageFile^ m_dbFile;
And I have the following code block in my implementation file:
//Make sure the SQLite Database is in ms-appdata:///local/
m_dbName = L"DynamicSimulations.db";
m_localFolder = ApplicationData::Current->LocalFolder;
m_installFolder = Windows::ApplicationModel::Package::Current->InstalledLocation;
auto getLocalFileOp = m_localFolder->GetFileAsync(m_dbName);
getLocalFileOp->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>([this](IAsyncOperation<StorageFile^>^ operation, AsyncStatus status)
{
m_dbFile = operation->GetResults();
if(m_dbFile == nullptr)
{
auto getInstalledFileOp = m_installFolder->GetFileAsync(m_dbName);
getInstalledFileOp->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>([this](IAsyncOperation<StorageFile^>^ operation, AsyncStatus status)
{
m_dbFile = operation->GetResults();
m_dbFile->CopyAsync(m_localFolder, m_dbName);
});
}
});
I get a memory access violation when it gets to m_dbFile = operation->GetResults();
What am I missing here? I come from a c# background in which this is really easy stuff to do :/
I've tried using '.then' instead of registering the event but I couldn't even get those to compile.
thank you for your help!
If you are interested in the WinRT solution, here it is:
It seems all you want to do is to copy the DB file from the installed location into the local folder. For that the following code should suffice:
//Make sure the SQLite Database is in ms-appdata:///local/
m_dbName = L"DynamicSimulations.db";
m_localFolder = ApplicationData::Current->LocalFolder;
m_installFolder = Windows::ApplicationModel::Package::Current->InstalledLocation;
create_task(m_installFolder->GetFileAsync(m_dbName)).then([this](StorageFile^ file)
{
create_task(file->CopyAsync(m_localFolder, m_dbName)).then([this](StorageFile^ copiedFile)
{
// do something with copiedFile
});
});
I've tried this thing before. Don't do this:
if(m_dbFile == nullptr)
Instead verify the value of "status".
if(status == AsyncStatus::Error)

Scopes not created from a template cannot have FilterParameters Error

I am trying to build on the "WebSharingAppDemo-SqlProviderEndToEnd" msdn sample application to build out a custom MSF implementation. As part of that I added parameterized filters to the provisioning. I have been referencing http://jtabadero.wordpress.com/2010/09/02/sync-framework-provisioning/ for some idea of how to do this. Now that I have that in place, when I re-initialize the "peer1" database and try to provision it initially I now get an error:
Scopes not created from a template cannot have FilterParameters.
Parameter '#my_param_name' was found on Table '[my_table_name]'.
Please ensure that no FilterParameters are being defined on a scope
that is not created from a template.
The only guess I have as to what a "template" is, is the provisioning templates that the Sync Toolkit's tools can work with, but I don't think that applies in the scenario I'm working with.
I have been unable to find anything that would indicate what I should do to fix this. So how can I get past this error but still provision my database with parameterized filters?
The below code is what I'm using to build the filtering into the provisioning (SqlSyncScopeProvisioning) object.
private void AddFiltersToProvisioning(IEnumerable<TableInfo> tables)
{
IEnumerable<FilterColumn> filters = this.GetFilterColumnInfo();
foreach (TableInfo tblInfo in tables)
{
this.AddFiltersForTable(tblInfo, filters);
}
}
private void AddFiltersForTable(TableInfo tblInfo, IEnumerable<FilterColumn> filters)
{
IEnumerable<FilterColumn> tblFilters;
tblFilters = filters.Where(x => x.FilterLevelID == tblInfo.FilterLevelID);
if (tblFilters != null && tblFilters.Count() > 0)
{
var tblDef = this.GetTableColumns(tblInfo.TableName);
StringBuilder filterClause = new StringBuilder();
foreach (FilterColumn column in tblFilters)
{
this.AddColumnFilter(tblDef, column.ColumnName, filterClause);
}
this.Provisioning.Tables[tblInfo.TableName].FilterClause = filterClause.ToString();
}
}
private void AddColumnFilter(IEnumerable<TableColumnInfo> tblDef, string columnName, StringBuilder filterClause)
{
TableColumnInfo columnInfo;
columnInfo = tblDef.FirstOrDefault(x => x.ColumnName.Equals(columnName, StringComparison.CurrentCultureIgnoreCase));
if (columnInfo != null)
{
this.FlagColumnForFiltering(columnInfo.TableName, columnInfo.ColumnName);
this.BuildFilterClause(filterClause, columnInfo.ColumnName);
this.AddParamter(columnInfo);
}
}
private void FlagColumnForFiltering(string tableName, string columnName)
{
this.Provisioning.Tables[tableName].AddFilterColumn(columnName);
}
private void BuildFilterClause(StringBuilder filterClause, string columnName)
{
if (filterClause.Length > 0)
{
filterClause.Append(" AND ");
}
filterClause.AppendFormat("[base].[{0}] = #{0}", columnName);
}
private void AddParamter(TableColumnInfo columnInfo)
{
SqlParameter parameter = new SqlParameter("#" + columnInfo.ColumnName, columnInfo.GetSqlDataType());
if (columnInfo.DataTypeLength > 0)
{
parameter.Size = columnInfo.DataTypeLength;
}
this.Provisioning.Tables[columnInfo.TableName].FilterParameters.Add(parameter);
}
i guess the error is self-explanatory.
the FilterParameters can only be set if the scope inherits from a filter template. you cannot set the FilterParameters for a normal scope, only FilterClause.
Using parameter-based filters is a two step process: Defining the filter/scope template and creating a scope based on a template.
I suggest you re-read the blog entry again and jump to the section Parameter-based Filters.

J2ME Stub generates an unknown exception with JPA Entity types

I created a web service stub using NetBeans 7.0 and when I try using it, it throws an unknown Exception. I don't even know what part of my code to show here, all I know is that bolded line generates an unknown Exception:
public Businesses[] findBusiness(String query) throws java.rmi.RemoteException {
Object inputObject[] = new Object[]{
query
};
Operation op = Operation.newInstance(_qname_operation_findBusiness, _type_findBusiness, _type_findBusinessResponse);
_prepOperation(op);
op.setProperty(Operation.SOAPACTION_URI_PROPERTY, "");
Object resultObj;
try {
resultObj = op.invoke(inputObject);
} catch (JAXRPCException e) {
Throwable cause = e.getLinkedCause();
if (cause instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException) cause;
}
throw e;
}
return businesses_ArrayfromObject((Object[]) resultObj);
}
private static Businesses[] businesses_ArrayfromObject(Object obj[]) {
if (obj == null) {
return null;
}
Businesses result[] = new Businesses[obj.length];
for (int i = 0; i < obj.length; i++) {
result[i] = new Businesses();
Object[] oo = (Object[]) obj[i];
result[i].setAddress((String) oo[0]); // **exception here**
result[i].setEmail((String) oo[1]);
result[i].setId((Integer) oo[2]);
result[i].setName((String) oo[3]);
result[i].setPhoneno((String) oo[4]);
result[i].setProducts((String) oo[5]);
}
return result;
}`
I tried to consume the same webservice using a web application and it works quite well. I don't have a single clue to what is causing this exception. Any comment would be appreciated.
Update
I tried other services that return a String data type and it works fine. So I thought maybe J2ME has issues with JPA Entity types.
So my question is how do I return the data properly so that the J2ME client can read it well?

AppFabric Cache concurrency issue?

While stress testing prototype of our brand new primary system, I run into concurrent issue with AppFabric Cache. When concurrently calling many DataCache.Get() and Put() with same cacheKey, where I attempt to store relatively large objet, I recieve "ErrorCode:SubStatus:There is a temporary failure. Please retry later." It is reproducible by the following code:
var dcfc = new DataCacheFactoryConfiguration
{
Servers = new[] {new DataCacheServerEndpoint("localhost", 22233)},
SecurityProperties = new DataCacheSecurity(DataCacheSecurityMode.None, DataCacheProtectionLevel.None),
};
var dcf = new DataCacheFactory(dcfc);
var dc = dcf.GetDefaultCache();
const string key = "a";
var value = new int [256 * 1024]; // 1MB
for (int i = 0; i < 300; i++)
{
var putT = new Thread(() => dc.Put(key, value));
putT.Start();
var getT = new Thread(() => dc.Get(key));
getT.Start();
}
When calling Get() with different key or DataCache is synchronized, this issue will not appear. If DataCache is obtained with each call from DataCacheFactory (DataCache is supposed to be thread-safe) or timeouts are prolonged it has no effect and error is still received.
It seems to me very strange that MS would leave such bug. Did anybody faced similar issue?
I also see the same behavior and my understanding is that this is by design. The cache contains two concurrency models:
Optimistic Concurrency Model methods: Get, Put, ...
Pessimistic Concurrency Model: GetAndLock, PutAndLock, Unlock
If you use optimistic concurrency model methods like Get then you have to be ready to get DataCacheErrorCode.RetryLater and handle that appropriately - I also use a retry approach.
You might find more information at MSDN: Concurrency Models
We have seen this problem as well in our code. We solve this by overloading the Get method to catch expections and then retry the call N times before fallback to a direct request to SQL.
Here is a code that we use to get data from the cache
private static bool TryGetFromCache(string cacheKey, string region, out GetMappingValuesToCacheResult cacheResult, int counter = 0)
{
cacheResult = new GetMappingValuesToCacheResult();
try
{
// use as instead of cast, as this will return null instead of exception caused by casting.
if (_cache == null) return false;
cacheResult = _cache.Get(cacheKey, region) as GetMappingValuesToCacheResult;
return cacheResult != null;
}
catch (DataCacheException dataCacheException)
{
switch (dataCacheException.ErrorCode)
{
case DataCacheErrorCode.KeyDoesNotExist:
case DataCacheErrorCode.RegionDoesNotExist:
return false;
case DataCacheErrorCode.Timeout:
case DataCacheErrorCode.RetryLater:
if (counter > 9) return false; // we tried 10 times, so we will give up.
counter++;
Thread.Sleep(100);
return TryGetFromCache(cacheKey, region, out cacheResult, counter);
default:
EventLog.WriteEntry(EventViewerSource, "TryGetFromCache: DataCacheException caught:\n" +
dataCacheException.Message, EventLogEntryType.Error);
return false;
}
}
}
Then when we need to get something from the cache we do:
TryGetFromCache(key, region, out cachedMapping)
This allows us to use Try methods that encasulates the exceptions. If it returns false, we know thing is wrong with the cache and we can access SQL directly.