public static IEnumerable<T> ExecuteDataReader<T>(string sql, Func<TdDataReader, T> action)
{
using (var connection = new TdConnection(TDConnstring))
{
connection.Open();
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = sql;
using (var dr = cmd.ExecuteReader())
{
while (dr.Read())
yield return action.Invoke(dr);
}
}
}
}
*how to use async task> rewirte *
public static async Task<IEnumerable<T>> ExecuteDataReaderAsync<T>(string sql, Func<TdDataReader, T> action)
{
using (var connection = new TdConnection(TDConnstring))
{
await connection.OpenAsync();
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = sql;
using (var dr = await cmd.ExecuteReaderAsync())
{
while (await dr.ReadAsync())
{
yield return action.Invoke(dr);
}
}
}
}
}
* error
Severity Code Description Project File Line Suppression State
Error CS1624 The body of 'TeraDataHelper.ExecuteDataReaderAsync(string, Func)' cannot be an iterator block because 'Task>' is not an iterator interface type \TeraDataHelper.cs 141 Active
*
got it
public static async Task<IEnumerable<T>> ExecuteDataReaderAsync<T>(string sql, Func<TdDataReader, T> action)
{
using (var connection = new TdConnection(TDConnstring))
{
await connection.OpenAsync();
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = sql;
using (var dr = await cmd.ExecuteReaderAsync())
{
return dr.Select(r => action(r)).ToList();
}
}
}
}
public static class Extensions
{
public static IEnumerable<T> Select<T>(
this TdDataReader reader, Func<TdDataReader, T> action)
{
while (reader.Read())
{
yield return action(reader);
}
}
}
Related
I'm trying to make use of System.Text.Json serialization for a project I'm working on. When I make use of a custom CosmosSerializer and call GetItemQueryIterator, the ToStream call is being sent a Microsoft.Azure.Cosmos.SqlQuerySpec that cannot be serialized. Here is a sample that should easily reproduce the problem. Any and all help is appreciated!
using Microsoft.Azure.Cosmos;
using System;
using System.IO;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace CosmosTestApp
{
class Program
{
const string endpoint = "<REPLACE>";
const string key = "<REPLACE>";
const string dbName = "test";
const string containerName = "items";
public static async Task Main(string[] args)
{
var options = new CosmosClientOptions()
{
Serializer = new CosmosJsonSerializer()
};
var client = new CosmosClient(endpoint, key, options);
var dbResponse = await client.CreateDatabaseIfNotExistsAsync(dbName);
var db = dbResponse.Database;
var containerDef = new ContainerProperties(containerName, "/id");
var containerResposne = await db.CreateContainerIfNotExistsAsync(containerDef);
var testContainer = containerResposne.Container;
var testDoc = new TestDoc();
var docResponse = await testContainer.CreateItemAsync(testDoc, new PartitionKey(testDoc.Id));
Console.WriteLine($"Created document {docResponse.Resource.Id}");
var query = testContainer.GetItemQueryIterator<TestDoc>("SELECT * FROM c");
while (query.HasMoreResults)
{
var doc = await query.ReadNextAsync();
foreach(var x in doc.Resource)
{
Console.WriteLine($"Retrieved document {x.Id}");
}
}
}
}
internal class CosmosJsonSerializer : CosmosSerializer
{
public override T FromStream<T>(Stream stream)
{
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
stream.Close();
var item = JsonSerializer.Parse<T>(memoryStream.ToArray());
return item;
}
}
//This errors on the SqlQuerySpec
public override Stream ToStream<T>(T input)
=> new MemoryStream(JsonSerializer.ToUtf8Bytes(input));
}
internal class TestDoc
{
[JsonPropertyName("id")]
public string Id { get; set; } = "1";
public string TestString { get; set; } = "testing CosmosJsonSerializer";
}
}
EDIT: Bug has been filed and confirmed here: https://github.com/Azure/azure-cosmos-dotnet-v3/issues/575
I'm using Xamarin, also my SQLite tables contain a large amount of data.
Because I want to avoid UIThread problems in OnCreate(), I need to perform database actions asynchronously.
I'm looking for guidance if I am handling this properly.
First method, which I found on the net:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.InventoryPreviewMain);
Thread thread = new Thread(() =>
{
SQLiteConnection db = new SQLiteConnection(dpPath);
var table = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + Connection.CategoryID + "");
mItems = new List<InventoryPreviewClass>();
foreach (var item in table)
{
mItems.Add(new InventoryPreviewClass() { InventoryItemID = item.InventoryItemID, InventoryItemName = item.InventoryItemName, InventoryItemPrice = item.InventoryItemPrice });
}
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
});
thread.Start();
Second Method, using async
public async void StartTimer()
{
SQLiteConnection db = new SQLiteConnection(dpPath);
var table = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + Connection.CategoryID + "");
mItems = new List<InventoryPreviewClass>();
foreach (var item in table)
{
mItems.Add(new InventoryPreviewClass() { InventoryItemID = item.InventoryItemID, InventoryItemName = item.InventoryItemName, InventoryItemPrice = item.InventoryItemPrice });
}
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
await Task.Delay(500);
}
Which of two examples are more safe for keeping alive UIthread? Is there any other solution for making this?What is more reccomended to do?
Answer
Use the Cross-platform SQLite Library made by #FrankKruger to create/access SQLite databases for Xamarin mobile apps.
This library has a built-in asynchronous connection, so you'll never need to worry about accessing the database from the UI Thread again!
Xamarin.Android Example
"Second Method"
public async Task StartTimer()
{
mItems = await InventoryPreviewClassDatabase.GetAllInventoryPreviewClassAsync();
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
}
BaseDatabase Class
using System;
using System.Threading.Tasks;
using SQLite;
namespace SampleApp
{
public abstract class BaseDatabase
{
#region Constant Fields
static readonly Lazy<SQLiteAsyncConnection> _databaseConnectionHolder = new Lazy<SQLiteAsyncConnection>(() => GetDatabaseConnection());
#endregion
#region Fields
static bool _isInitialized;
#endregion
#region Properties
static SQLiteAsyncConnection DatabaseConnection => _databaseConnectionHolder.Value;
#endregion
#region Methods
protected static async Task<SQLiteAsyncConnection> GetDatabaseConnectionAsync()
{
if (!_isInitialized)
await Initialize().ConfigureAwait(false);
return DatabaseConnection;
}
static async Task Initialize()
{
await DatabaseConnection.CreateTableAsync<InventoryPreviewClass>().ConfigureAwait(false);
_isInitialized = true;
}
SQLiteAsyncConnection GetDatabaseConnection()
{
var sqliteFilename = "YourDatabaseName.db3";
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
var conn = new SQLiteAsyncConnection(path, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.SharedCache);
return conn;
}
#endregion
}
}
Parent Database Class
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace SampleApp
{
public abstract class InventoryPreviewClassDatabase : BaseDatabase
{
#region Methods
public static async Task<IList<InventoryPreviewClass>> GetAllInventoryPreviewClassAsync()
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.Table<InventoryPreviewClass>().ToListAsync().ConfigureAwait(false);
}
public static async Task<InventoryPreviewClass> GetInventoryPreviewClassByIDAsync(int id)
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.Table<InventoryPreviewClass>().Where(x => x.ID.Equals(id)).FirstOrDefaultAsync().ConfigureAwait(false);
}
public static async Task<int> SaveInventoryPreviewClassAsync(InventoryPreviewClass inventoryPreview)
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
var isObjectInDatabase = await GetInventoryPreviewClassByIDAsync(inventoryPreview.ID).ConfigureAwait(false) != null;
if (isObjectInDatabase)
return await databaseConnection.UpdateAsync(inventoryPreview).ConfigureAwait(false);
return await databaseConnection.InsertAsync(inventoryPreview).ConfigureAwait(false);
}
public static async Task<int> DeleteItemAsync(OpportunityModel opportunity)
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.DeleteAsync(opportunity).ConfigureAwait(false);
}
public static async Task<int> GetNumberOfRowsAsync()
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.Table<InventoryPreviewClass>().CountAsync().ConfigureAwait(false);
}
#endregion
}
}
This code was inspired from this Xamarin.Forms sample app
I am using ASP.NET Web API and C#. As i am new to Express Mapper and i am having ADO.NET code which is returning list of results.How to map using Express Mapper?
This is a test to demonstrate how to work with custom mappers in ExpressMapper. I hope you'll be able to use it accordingly -
public static void Main()
{
var ds = new DataSet();
var dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Age", typeof(int));
dt.Rows.Add("Test", 10);
dt.Rows.Add("Test2", 10);
ds.Tables.Add(dt);
var mapped = Mapper.Map<DataTable, List<RequestModel>>(ds.Tables[0], new CustomTypeMapper());
}
where -
class RequestModel
{
public int Age { get; set; }
public string Name { get; set; }
}
class CustomTypeMapper : ICustomTypeMapper<DataTable, List<RequestModel>>
{
public List<RequestModel> Map(IMappingContext<DataTable, List<RequestModel>> context)
{
if (context.Source == null)
throw new ArgumentNullException();
var output = new List<RequestModel>();
foreach (DataRow row in context.Source.Rows)
{
output.Add(new RequestModel
{
Age = row.Field<int>("Age"),
Name = row.Field<string>("Name")
});
}
return output;
}
}
How would I make this parametrized ?!
string query = "";
query += " SELECT DistID FROM Distributor";
query += " WHERE Username = '" + username_id.Text + "'";
query += " AND Password = '" + password.Text + "'";
GeneralFunctions.GetData( query );
Can it be done here or would it have to be done inside the GetData method?
Here are the two methods:
public static DataTable GetData ( string query )
{
SqlDataAdapter dataAdapter;
DataTable table;
try
{
dataAdapter = new SqlDataAdapter( query, GetConnectionString() );
table = new DataTable();
dataAdapter.Fill( table );
return table;
}
catch ( Exception ex )
{
}
finally
{
dataAdapter = null;
table = null;
}
return table;
}
public static string GetConnectionString ()
{
string connectionString = ConfigurationManager.ConnectionStrings[ "CAPortalConnectionString" ].ConnectionString;
return connectionString;
}
I'd recommend you designing specific methods to query your database, like this:
public static int? GetDistID(string username, string password)
{
using (var conn = new SqlConnection(GetConnectionString()))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText =
#"SELECT
DistID
FROM
Distributor
WHERE
Username = #username
AND
Password = #password";
cmd.Parameters.AddWithValue("#username", username);
cmd.Parameters.AddWithValue("#password", password);
using (var reader = cmd.ExecuteReader())
{
if (!reader.Read())
{
// no results found
return null;
}
return reader.GetInt32(reader.GetOrdinal("DistID"));
}
}
}
and then:
var distId = GeneralFunctions.GetDistID(username_id.Text, password.Text);
No need of DataTables/Sets/Adapters. Work with strongly typed objects.
Use the SqlCommand object, and you can create a parameterized query like this:
public object GetDistID(string username, string password)
{
using (var conn = new SqlConnection("..."))
{
using (var cmd = new SqlCommand("SELECT DistID FROM Distributor WHERE Username=#Username AND Password=#Password", conn))
{
cmd.Connection.Open();
cmd.Parameters.AddWithValue("#Username", username);
cmd.Parameters.AddWithValue("#Password", password);
return cmd.ExecuteScalar();
}
}
}
If it's useful to you, here's a class you can use. It's tailored towards stored procedures, but it should be easy enough to add a method that accepts a query:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web;
using System.Xml;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
namespace NESCTC.Data
{
public class DataAccess : IDisposable
{
#region declarations
private SqlCommand _cmd;
private string _SqlConnString;
#endregion
#region constructors
public DataAccess(string ConnectionString)
{
_cmd = new SqlCommand();
_cmd.CommandTimeout = 240;
_SqlConnString = ConnectionString;
}
#endregion
#region IDisposable implementation
~DataAccess()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_cmd.Connection.Dispose();
_cmd.Dispose();
}
}
#endregion
#region data retrieval methods
public DataTable ExecReturnDataTable()
{
using (SqlConnection conn = new SqlConnection(this.ConnectionString))
{
try
{
PrepareCommandForExecution(conn);
using (SqlDataAdapter adap = new SqlDataAdapter(_cmd))
{
DataTable dt = new DataTable();
adap.Fill(dt);
return dt;
}
}
catch
{
_cmd.Connection.Close();
throw;
}
finally
{
_cmd.Connection.Close();
}
}
}
public object ExecScalar()
{
using (SqlConnection conn = new SqlConnection(this.ConnectionString))
{
try
{
PrepareCommandForExecution(conn);
return _cmd.ExecuteScalar();
}
catch (Exception ex)
{
_cmd.Connection.Close();
throw ex;
}
finally
{
_cmd.Connection.Close();
}
}
}
#endregion
#region data insert and update methods
public void ExecNonQuery()
{
using (SqlConnection conn = new SqlConnection(this.ConnectionString))
{
try
{
PrepareCommandForExecution(conn);
_cmd.ExecuteNonQuery();
}
catch
{
_cmd.Connection.Close();
throw;
}
finally
{
_cmd.Connection.Close();
}
}
}
#endregion
#region helper methods
public void AddParm(string ParameterName, SqlDbType ParameterType, object Value)
{ _cmd.Parameters.Add(ParameterName, ParameterType).Value = Value; }
private SqlCommand PrepareCommandForExecution(SqlConnection conn)
{
try
{
_cmd.Connection = conn;
_cmd.CommandType = CommandType.StoredProcedure;
_cmd.CommandTimeout = this.CommandTimeout;
_cmd.Connection.Open();
return _cmd;
}
catch
{
_cmd.Connection.Close();
throw;
}
}
#endregion
#region properties
public int CommandTimeout
{
get { return _cmd.CommandTimeout; }
set { _cmd.CommandTimeout = value; }
}
public string ProcedureName
{
get { return _cmd.CommandText; }
set { _cmd.CommandText = value; }
}
public string ConnectionString
{
get { return _SqlConnString; }
set { _SqlConnString = value; }
}
#endregion
}
}
You can use the class like this:
public object GetDistID(string username, string password)
{
using (var data = new DataAccess("ConnectionString"))
{
data.ProcedureName = "GetDistID";
data.AddParm("#Username", SqlDbType.VarChar, username);
data.AddParm("#Password", SqlDbType.VarChar, password);
return data.ExecScalar();
}
}
is it possible to get the result of an action into a string variable
I need something like this:
public ActionResult Do()
{
var s = this.Index().GetStringResult();
...
}
Omu - try these for size:
public static class ExtensionMethods
{
// usage
/*
var model = _repository.Find(x => x.PropertyID > 3).FirstOrDefault();
var test = this.RenderViewToString("DataModel", model);
return Content(test);
*/
public static string RenderViewToString<T>(this ControllerBase controller,
string viewName, T model)
{
using (var writer = new StringWriter())
{
ViewEngineResult result = ViewEngines
.Engines
.FindView(controller.ControllerContext,
viewName, null);
var viewPath = ((WebFormView)result.View).ViewPath;
var view = new WebFormView(viewPath);
var vdd = new ViewDataDictionary<T>(model);
var viewCxt = new ViewContext(
controller.ControllerContext,
view,
vdd,
new TempDataDictionary(), writer);
viewCxt.View.Render(viewCxt, writer);
return writer.ToString();
}
}
public static string RenderPartialToString<T>(
this ControllerBase controller,
string partialName, T model)
{
var vd = new ViewDataDictionary(controller.ViewData);
var vp = new ViewPage
{
ViewData = vd,
ViewContext = new ViewContext(),
Url = new UrlHelper(controller.ControllerContext.RequestContext)
};
ViewEngineResult result = ViewEngines
.Engines
.FindPartialView(
controller.ControllerContext,
partialName);
if (result.View == null)
{
throw new InvalidOperationException(
string.Format("The partial view '{0}' could not be found",
partialName));
}
var partialPath = ((WebFormView)result.View).ViewPath;
vp.ViewData.Model = model;
Control control = vp.LoadControl(partialPath);
vp.Controls.Add(control);
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
{
using (var tw = new HtmlTextWriter(sw))
{
vp.RenderControl(tw);
}
}
return sb.ToString();
}
}
usage (normal view):
var s = this.RenderViewToString("Index", null); // or model if required
and for a partial:
var s = this.RenderPartialToString("PartialView, model) // etc
Why not take the Index action and extract all it's code into a seperate function like this:
public ActionResult Index()
{
Response.Write(GetActionString());
return new EmptyResult();
}
private void GetActionString()
{
//Code which produces the index string;
}
public ActionResult Do()
{
var s = GetActionString();
...
return View();
}
If you are in need of the rendered HTML from index after it has been passed to a view then you will need to create an HttpRequest in code and read the result from this.