SQLDataReader object when declared in a foreach loop - garbage-collection

This is something I return to from time to time, but have not yet found a definitive answer. Hopefully I will get it before Microsoft legacies the language (joking... kinda)...
This is almost certainly wrong, but this is how I've been retrieving records from SQLServer... I am passing each row to it's caller as a IDataRecord and using an SQLDataREader object to iterate through it. I have read that the datareader should be closed after use, if not declared in a using statement. Should I be closing this one?
My SQLDataReader is declared in a foreach loop like this...
IEnumerable<IDataRecord> dataset = Select("SELECT Topic FROM Topics WHERE pti=" + pid + " and Ignore = 0");
foreach (SqlDataReader reader in dataset )
{
string topic = reader.GetString(0);
//... do something
}
My db call:
public IEnumerable<IDataRecord> Select(string sql, List<SqlParameter> sparams = null)
{
using (SqlConnection cn = new SqlConnection(ConnString()))
{
cn.Open();
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
if (sparams != null)
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddRange(sparams.ToArray());
}
else
{
cmd.CommandType = CommandType.Text;
}
using (SqlDataReader rdr = cmd.ExecuteReader())
{
if (rdr != null && rdr.FieldCount > 0)
{
while (rdr.Read())
{
yield return rdr;
}
}
}
}
cn.Close();
}
}

There's actually nothing to close. The closable reader object in your code is the one that uses the connection, but it's closed automatically by the using statement in your Select method.
I think the way you did it is pretty uncommon. If you're able to change the method signature, you could simply return a List<> by doing a cast and, removing the yield like this:
public List<IDataRecord> Select(string sql , List<SqlParameter> sparams = null)
{
using (SqlConnection cn = new SqlConnection (ConnectionString))
{
cn.Open ( );
using (SqlCommand cmd = new SqlCommand (sql , cn))
{
if (sparams != null)
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddRange (sparams.ToArray ( ));
}
else
{
cmd.CommandType = CommandType.Text;
}
using (SqlDataReader rdr = cmd.ExecuteReader ( ))
{
return rdr.Cast<IDataRecord> ( ).ToList ( );
}
}
}
}
I've done this in a DB connection class. It's pretty straightforward, but post a comment if you have any questions:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
namespace SqlToDb
{
public class SqlClientData
{
private string connectionstring;
public string ConnectionString { get => connectionstring; set => connectionstring = value; }
public SqlClientData(string connection_string)
{
ConnectionString = connection_string;
}
public T ExecuteScalar<T>(string queryString)
{
using (SqlConnection conn = new SqlConnection (ConnectionString))
{
using (SqlCommand cmd = new SqlCommand (queryString , conn))
{
try
{
conn.Open ( );
var result = cmd.ExecuteScalar ( );
if (Convert.IsDBNull (result) && typeof (T).IsValueType)
return default (T); // if the db value is null, but T is a value type, set T = the default value of the type.
else
return (T) (result);
}
finally
{
conn.Close ( );
}
}
}
}
public List<T> ExecScalarList<T>(string sql , bool exclude_nulls , bool replace_null_with_default)
{
using (SqlConnection conn = new SqlConnection (ConnectionString))
{
using (SqlCommand cmd = new SqlCommand (sql , conn))
{
conn.Open ( );
using (SqlDataReader rdr = cmd.ExecuteReader ( ))
{
var mylist = new List<T> { };
while (rdr.Read ( ))
{
if (!Convert.IsDBNull (rdr[0]) || (exclude_nulls == false && replace_null_with_default == false))
{
mylist.Add ((T) Convert.ChangeType (rdr[0] , typeof (T)));
}
else
{
if (exclude_nulls == false)
{
if (replace_null_with_default == true) mylist.Add (default (T)); // returns the default for the type... not null
}
}
}
return mylist;
}
}
}
}
public List<IDataRecord> ExecReader(string sql)
{
using (SqlConnection conn = new SqlConnection (ConnectionString))
{
using (SqlCommand cmd = new SqlCommand (sql , conn))
{
conn.Open ( );
using (SqlDataReader rdr = cmd.ExecuteReader ( ))
{
return rdr.Cast<IDataRecord> ( ).ToList ( );
}
}
}
}
public int ExecNonQuery(string sql)
{
int result = 0;
using (SqlConnection cn = new SqlConnection (ConnectionString))
{
using (SqlCommand cmd = new SqlCommand (sql , cn))
{
cmd.CommandType = CommandType.Text; // or CommandType.StoredProcedure
cn.Open ( );
try
{
result = (Int32) cmd.ExecuteNonQuery ( ); //returns the number of rows affected
}
finally
{
cn.Close ( );
}
}
}
return result;
}
}
}

Related

I use sqldependency AND signalR AND thread but it goes on infinite loop

I use sqldependency AND signalR AND thread but it goes on infinite loop
combine BackgroundWorker in global.aspx and sqldependency and signalR
I dont know about problem please help me.
void Application_Start(object sender, EventArgs e)
{
//var session = HttpContext.Current.Session;
//if (session != null && HttpContext.Current != null)
//{
try
{
CSASPNETBackgroundWorker.BackgroundWorker worker = new CSASPNETBackgroundWorker.BackgroundWorker();
worker.DoWork += new CSASPNETBackgroundWorker.BackgroundWorker.DoWorkEventHandler(worker_DoWork);
worker.RunWorker(null);
// This Background Worker is Applicatoin Level,
// so it will keep working and it is shared by all users.
Application["worker"] = worker;
// Code that runs on application startup
}
catch { }
// }
System.Data.SqlClient.SqlDependency.Start(connectionstring);
}
string user_id;
void worker_DoWork(ref int progress,
ref object _result, params object[] arguments)
{
// Do the operation every 1 second wihout the end.
while (true)
{
Random rand = new Random();
int randnum = rand.Next(5000, 20000);
Thread.Sleep(randnum);
// This statement will run every 1 second.
// string user_id = "";
// if (HttpContext.Current != null && HttpContext.Current.Session != null)
{
// user_id = "22";// HttpContext.Current.Session["userId"].ToString();
user_id = ConfigurationManager.AppSettings["session_user_id"].ToString();
updatealarm(user_id);
}
// Other logic which you want it to keep running.
// You can do some scheduled tasks here by checking DateTime.Now.
}
}
AND
public class AlarmInfoRepository {
string connectionstr = ConfigurationManager.ConnectionStrings["officeConnectionString"].ConnectionString;
public IEnumerable GetData(string user_id)
{
using (SqlConnection connection = new SqlConnection(connectionstr))
{
//PersianCalendar jc = new PersianCalendar();
//string todayStr = jc.GetYear(DateTime.Now).ToString("0000") + "/" + jc.GetMonth(DateTime.Now).ToString("00") + "/" +
// jc.GetDayOfMonth(DateTime.Now).ToString("00");
//string timeStr = String.Format("{0:00}:{1:00}:{2:00}", jc.GetHour(DateTime.Now.AddSeconds(10)), jc.GetMinute(DateTime.Now.AddSeconds(10)), jc.GetSecond(DateTime.Now.AddSeconds(10)));
if (connection.State == ConnectionState.Closed)
connection.Open();
using (SqlCommand command = new SqlCommand(#"SELECT dbo.[web_alarmkartable].[id],dbo.[web_alarmkartable].peygir_id,dbo.[web_alarmkartable].user_id,
dbo.[web_alarmkartable].[content],dbo.[web_alarmkartable].[latestcreate_date],dbo.[web_alarmkartable].[latestcreate_time],
dbo.[web_alarmkartable].[firstcreate_date],dbo.[web_alarmkartable].[firstcreate_time],dbo.[web_alarmkartable].[duration],
dbo.[web_alarmkartable].[periodtype_id],dbo.[web_alarmkartable].[period],ISNULL(dbo.[web_alarmkartable].[color],'') AS color,dbo.[web_alarmkartable].id_tel FROM dbo.[web_alarmkartable] where dbo.[web_alarmkartable].content !='' AND dbo.[web_alarmkartable].content IS NOT NULL
AND (dbo.[web_alarmkartable].seen IS NULL OR dbo.[web_alarmkartable].seen =0) AND (dbo.[web_alarmkartable].expier IS NULL OR dbo.[web_alarmkartable].expier =0 )
AND (dbo.[web_alarmkartable].del=0 OR dbo.[web_alarmkartable].del IS NULL) AND dbo.[web_alarmkartable].user_id=" + user_id, connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
using (var reader = command.ExecuteReader())
return reader.Cast<IDataRecord>()
.Select(x => new AlarmInfo()
{
id = x.GetInt32(0),
peygir_id = x.GetInt32(1),
user_id = x.GetInt32(2),
content = x.GetString(3),
latestcreate_date = x.GetString(4),
latestcreate_time = x.GetString(5),
firstcreate_date = x.GetString(6),
firstcreate_time = x.GetString(7),
duration = x.GetDecimal(8),
periodtype_id = x.GetInt32(9),
period = x.GetDecimal(10),
color = x.GetString(11),
id_tel = x.GetInt32(12)
}).ToList();
}
//if (connection.State == ConnectionState.Open)
// connection.Close();
}
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if ((e.Info.ToString() == "Insert" || e.Info.ToString() == "Update") && e.Type == SqlNotificationType.Change)
AlermHub.Show(e.Info.ToString());
}
}
AND

Sharepoint2013 webpart can't load custom dll from GAC

I'm trying to use a third party dll called ASPTokenInputLib in my sharepoint2013 webpart .
It was working for a while when I loaded it in the bin directory but when I tried to move it to the GAC it won't work and it's stopped working if I load it in the bin now as well.
The error I get is object reference not set to an instance of an object. The sharepoint logs shows
System.NullReferenceException: Object reference not set to an instance of an object. at ASPTokenInputLib.ASPTokenInput.OnLoad(EventArgs e)
My package manifest file includes
<Assemblies>
<Assembly Location="ASPTokenInputLib.dll" DeploymentTarget="GlobalAssemblyCache" />
<Assembly Location="BidSearchWebPart.dll" DeploymentTarget="GlobalAssemblyCache">
<SafeControls>
<SafeControl Assembly="BidSearchWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=59049686a9425568" Namespace="BidSearchWebPart.VisualWebPart1" TypeName="*" />
</SafeControls>
</Assembly>
If I remove any ASPTokenInput controls in the webpart the webpart loads correctly so I don't think there's a problem finding the control in the gac (I've used process monitor and it is looking in the correct place in the GAC to find the control). For some reason though it can't load the dll.
Any help would be much appreciated. Thanks!
My ascx.cs files is
using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Web.Script.Serialization;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using ASPTokenInputLib;
namespace BidSearchWebPart.VisualWebPart1
{
[ToolboxItemAttribute(false)]
public partial class BidSearchWebPart : WebPart
{
private enum Columns
{
BidRef, BidName, Client, Area, TeamLead
}
private string TeamLeadsData, ExecLeadsData, StagesData, SectorsData, ServicesData, GradesData, CostCentresData, ClientsData, AreasData;
public BidSearchWebPart()
{
TeamLeadsData = RunSP("uspSelectTeamLeads", "TeamLead", "Name", ConnectionString());
ExecLeadsData = RunSP("uspSelectExecTechLeads", "ExecutiveTechnicalLead", "Name", ConnectionString());
StagesData = RunSP("uspSelectStages", "StageID", "StageDescSearch", ConnectionString());
SectorsData = RunSP("spSelectMarketSectors", "SectorID", "MktSector", CCDConnectionString());
ServicesData = RunSP("spSelectAllServices", "ServiceID", "Service", CCDConnectionString());
GradesData = RunSP("uspSelectGrades", "GradeID", "GradeDesc", ConnectionString());
CostCentresData = RunSP("uspSelectCostCentres", "CostCentre", "Name", ConnectionString());
ClientsData = RunSP("spSelectAllClients", "CompanyRef", "CoName", CCDConnectionString());
AreasData = RunSP("uspSelectAreas", "AreaID", "AreaName", ConnectionString());
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
InitializeControl();
}
protected void Page_Load(object sender, EventArgs e)
{
List<string> ddValues = new List<string>();
if (!Page.IsPostBack)
{
ddValues.Add("Greater than");
ddValues.Add("Less than");
ddCC.DataSource = ddValues;
ddFV.DataSource = ddValues;
ddCC.DataBind();
ddFV.DataBind();
}
btnSearch.Click += btnSearch_Click;
gvSearchResults.RowDataBound += gvSearchResults_RowDataBound;
tiTeamLead.DataSource = ASPTokenInput.DataSourceType.DataSet;
tiTeamLead.DataSet = TeamLeadsData;
tiExecTechLead.DataSource = ASPTokenInput.DataSourceType.DataSet;
tiExecTechLead.DataSet = ExecLeadsData;
tiStage.DataSource = ASPTokenInput.DataSourceType.DataSet;
tiStage.DataSet = StagesData;
tiSector.DataSource = ASPTokenInput.DataSourceType.DataSet;
tiSector.DataSet = SectorsData;
tiService.DataSource = ASPTokenInput.DataSourceType.DataSet;
tiService.DataSet = ServicesData;
tiGrade.DataSource = ASPTokenInput.DataSourceType.DataSet;
tiGrade.DataSet = GradesData;
tiCostCentre.DataSource = ASPTokenInput.DataSourceType.DataSet;
tiCostCentre.DataSet = CostCentresData;
tiClient.DataSource = ASPTokenInput.DataSourceType.DataSet;
tiClient.DataSet = ClientsData;
tiArea.DataSource = ASPTokenInput.DataSourceType.DataSet;
tiArea.DataSet = AreasData;
}
void btnSearch_Click(object sender, EventArgs e)
{
//if (string.IsNullOrEmpty(txtProjectNo.Text) && string.IsNullOrEmpty(txtProjectName.Text) && string.IsNullOrEmpty(txtClient.Text) && string.IsNullOrEmpty(txtKeyword.Text)) // Do nothing if search text boxes are blank
//{
// return;
//} else {
gvSearchResults.PageIndex = 0;
DoSearch();
//}
}
protected void gvSearchResults_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gvSearchResults.PagerTemplate = null;
gvSearchResults.PageIndex = e.NewPageIndex;
DoSearch();
}
public void DoSearch()
{
DataTable dt = new DataTable();
string where = GetWhereClause();
if (!string.IsNullOrEmpty(where))
{
dt = FillTable("spSelectBidSearchResults", where);
}
gvSearchResults.DataSource = dt;
gvSearchResults.PageSize = 10;
gvSearchResults.PagerTemplate = null;
gvSearchResults.DataBind();
}
private DataTable FillTable(string storedProc, string where)
{
SqlConnection conn = new SqlConnection(ConnectionString());
conn.Open();
SqlCommand cmdProject = new SqlCommand(storedProc, conn);
cmdProject.CommandType = CommandType.StoredProcedure;
cmdProject.Parameters.AddWithValue("#whereclause", where);
SqlDataAdapter da = new SqlDataAdapter(cmdProject);
DataTable dt = new DataTable();
da.Fill(dt);
da.Dispose();
conn.Close();
return dt;
}
private string Symbol(string ddText)
{
if (ddText.Equals("Greater than"))
{
return ">";
}
else
{
return "<";
}
}
private string GetWhereClause()
{
string where = "";
where = GetWhereForCol(txtBidName.Text, "", "BidName", "like", where);
where = GetWhereForCol(txtDescription.Text, "", "Description", "like", where);
where = GetWhereForCol(GetTokens(tiTeamLead), "", "TeamLead", "token", where);
where = GetWhereForCol(GetTokens(tiExecTechLead), "", "ExecutiveTechnicalLead", "token", where);
where = GetWhereForCol(txtConstructionCost.Text, ddCC.Text, "ConstructionCost", "numeric", where);
where = GetWhereForCol(txtFeeValue.Text, ddFV.Text, "FeeValue", "numeric", where);
where = GetWhereForCol(GetTokens(tiStage), "", "Stage", "token", where);
where = GetWhereForCol(GetTokens(tiSector), "", "PrimarySector", "token", where, "SecondarySector");
where = GetWhereForCol(GetTokens(tiService), "", "PrimaryService", "token", where);
where = GetWhereForCol(GetTokens(tiGrade), "", "Grade", "token", where);
where = GetWhereForCol(GetTokens(tiCostCentre), "", "PrimaryCostCentre", "token", where);
where = GetWhereForCol(GetTokens(tiClient), "", "ClientRef", "token", where);
where = GetWhereForCol(GetTokens(tiArea), "", "Area", "token", where);
return where;
}
private string GetWhereForCol(string text, string ddText, string colName, string colType, string where, string otherCol = "")
{
if (!string.IsNullOrEmpty(text))
{
if (colType.Equals("like"))
{
where = AddToWhere(where, colName + " LIKE '%" + text + "%'");
}
else if (colType.Equals("numeric"))
{
string symbl = Symbol(ddText);
where = AddToWhere(where, colName + " " + symbl + " " + text);
}
else if (colType.Equals("token"))
{
if (!string.IsNullOrEmpty(otherCol))
{
where = AddToWhere(where, "(" + colName + " in (" + text + ")");
where += " OR " + otherCol + " in (" + text + "))";
}
else
{
where = AddToWhere(where, colName + " in (" + text + ")");
}
}
}
return where;
}
private string AddToWhere(string where, string clause)
{
if (!string.IsNullOrEmpty(clause))
{
if (string.IsNullOrEmpty(where))
{
where = clause;
}
else
{
where += " AND " + clause;
}
}
return where;
}
private string GetTokens(ASPTokenInput ti)
{
StringBuilder strTokens = new StringBuilder();
List<ASPTokenInput.Item> items = ti.SelectedItems;
foreach (ASPTokenInput.Item item in items)
{
if (strTokens.Length > 0)
{
strTokens.Append(", ");
}
strTokens.AppendFormat("'{0}'", item.id);
}
return strTokens.ToString();
}
public string GetSPSingleValue(string spName, string spParamName, string spParamVal, string connectionStr)
{
try
{
SqlConnection conn = new SqlConnection(connectionStr);
SqlCommand cmd = new SqlCommand(spName, conn);
cmd.Parameters.AddWithValue(spParamName, spParamVal);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
string result = cmd.ExecuteScalar().ToString();
conn.Close();
return result;
}
catch
{
return "";
}
}
void gvSearchResults_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
Label l;
DataRowView rowView = (DataRowView)e.Row.DataItem;
string bidRef = rowView["BidRef"].ToString();
string teamLeadID = rowView["TeamLead"].ToString();
string teamLeadName = GetSingleRecord("uspSelectTeamLeadByID", ConnectionString(), "#TeamLead", teamLeadID);
l = (Label)e.Row.Cells[(int)Columns.TeamLead].FindControl("lblTeamLead");
l.Text = teamLeadName;
if (siteCollectionExists(bidRef))
{
l = (Label)e.Row.Cells[(int)Columns.BidRef].FindControl("lblBidRef");
HyperLink hl = new HyperLink();
hl.NavigateUrl = "http://bidstore.gleeds.net/bids/" + bidRef;
hl.Text = bidRef;
e.Row.Cells[(int)Columns.BidRef].Controls.Add(hl);
l.Text = "";
}
}
}
//Check if site collection exists at given web application
private static bool siteCollectionExists(string bidNr)
{
bool returnVal = false;
var r = SPContext.Current.Site.WebApplication.Sites.Where(site => site.Url.Contains(bidNr));
foreach (SPSite s in r)
{
returnVal = true;
}
return returnVal;
}
public string TeamLeads()
{
return TeamLeadsData;
}
public string ExecutiveTechnicalLeads()
{
return ExecLeadsData;
}
public string Stages()
{
return StagesData;
}
public string Sectors()
{
return SectorsData;
}
public string Services()
{
return ServicesData;
}
public string Grades()
{
return GradesData;
}
public string CostCentres()
{
return CostCentresData;
}
public string Clients()
{
return ClientsData;
}
public string Areas()
{
return AreasData;
}
public string GetSingleRecord(string spName, string connectionStr, string param, string value)
{
SqlConnection conn = new SqlConnection();
SqlCommand command = new SqlCommand(spName, conn);
conn = new SqlConnection(connectionStr);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue(param, value);
command.Connection = conn;
conn.Open();
string result = command.ExecuteScalar().ToString();
conn.Close();
return result;
}
public string RunSP(string spName, string idCol, string nameCol, string connectionStr)
{
ArrayList data = new ArrayList();
SqlConnection conn = new SqlConnection();
SqlCommand command = new SqlCommand(spName, conn);
conn = new SqlConnection(connectionStr);
command.CommandType = CommandType.StoredProcedure;
command.Connection = conn;
conn.Open();
SqlDataReader dr = command.ExecuteReader();
while (dr.Read())
{
data.Add(new TokenInputRow(dr[idCol].ToString(), dr[nameCol].ToString()));
}
conn.Close();
return Serialize(data);
}
private static string Serialize(object obj)
{
JavaScriptSerializer ser = new JavaScriptSerializer();
return ser.Serialize(obj);
}
private string ConnectionString()
{
return "Data Source=10.2.40.17;Initial Catalog=BidOpening;Persist Security Info=True;User ID=GTL_BidOpening_User;Password=G#rd3n12";
}
private string CCDConnectionString()
{
return "Data Source=10.2.40.17;Initial Catalog=CCDLive;Persist Security Info=True;User ID=GTL_CCDLive_User;Password=G#rd3n";
}
}
public class TokenInputRow
{
public string id;
public string name;
public TokenInputRow(string _id, string _name)
{
id = _id;
name = _name;
}
}
}
I am able to step through the page load, but I can't step into the ASPTokenInput dll. The code fails after the page load has finished.
The ti controls are included in my .ascx file as so %# Register TagPrefix="ati" Assembly="ASPTokenInputLib" Namespace="ASPTokenInputLib" %> ati:ASPTokenInput ID="tiTeamLead" runat="server" HintText="Start typing TeamLead..." />

With OrmLite, is there a way to automatically update table schema when my POCO is modified?

Can OrmLite recognize differences between my POCO and my schema and automatically add (or remove) columns as necessary to force the schema to remain in sync with my POCO?
If this ability doesn't exist, is there way for me to query the db for table schema so that I may manually perform the syncing? I found this, but I'm using the version of OrmLite that installs with ServiceStack and for the life of me, I cannot find a namespace that has the TableInfo classes.
I created an extension method to automatically add missing columns to my tables. Been working great so far. Caveat: the code for getting the column names is SQL Server specific.
namespace System.Data
{
public static class IDbConnectionExtensions
{
private static List<string> GetColumnNames(IDbConnection db, string tableName)
{
var columns = new List<string>();
using (var cmd = db.CreateCommand())
{
cmd.CommandText = "exec sp_columns " + tableName;
var reader = cmd.ExecuteReader();
while (reader.Read())
{
var ordinal = reader.GetOrdinal("COLUMN_NAME");
columns.Add(reader.GetString(ordinal));
}
reader.Close();
}
return columns;
}
public static void AlterTable<T>(this IDbConnection db) where T : new()
{
var model = ModelDefinition<T>.Definition;
// just create the table if it doesn't already exist
if (db.TableExists(model.ModelName) == false)
{
db.CreateTable<T>(overwrite: false);
return;
}
// find each of the missing fields
var columns = GetColumnNames(db, model.ModelName);
var missing = ModelDefinition<T>.Definition.FieldDefinitions
.Where(field => columns.Contains(field.FieldName) == false)
.ToList();
// add a new column for each missing field
foreach (var field in missing)
{
var alterSql = string.Format("ALTER TABLE {0} ADD {1} {2}",
model.ModelName,
field.FieldName,
db.GetDialectProvider().GetColumnTypeDefinition(field.FieldType)
);
Console.WriteLine(alterSql);
db.ExecuteSql(alterSql);
}
}
}
}
No there is no current support for Auto Migration of RDBMS Schema's vs POCOs in ServiceStack's OrmLite.
There are currently a few threads being discussed in OrmLite's issues that are exploring the different ways to add this.
Here is a slightly modified version of code from cornelha to work with PostgreSQL. Removed this fragment
//private static List<string> GetColumnNames(object poco)
//{
// var list = new List<string>();
// foreach (var prop in poco.GetType().GetProperties())
// {
// list.Add(prop.Name);
// }
// return list;
//}
and used IOrmLiteDialectProvider.NamingStrategy.GetTableName and IOrmLiteDialectProvider.NamingStrategy.GetColumnName methods to convert table and column names from PascalNotation to this_kind_of_notation used by OrmLite when creating tables in PostgreSQL.
public static class IDbConnectionExtensions
{
private static List<string> GetColumnNames(IDbConnection db, string tableName, IOrmLiteDialectProvider provider)
{
var columns = new List<string>();
using (var cmd = db.CreateCommand())
{
cmd.CommandText = getCommandText(tableName, provider);
var tbl = new DataTable();
tbl.Load(cmd.ExecuteReader());
for (int i = 0; i < tbl.Columns.Count; i++)
{
columns.Add(tbl.Columns[i].ColumnName);
}
}
return columns;
}
private static string getCommandText(string tableName, IOrmLiteDialectProvider provider)
{
if (provider == PostgreSqlDialect.Provider)
return string.Format("select * from {0} limit 1", tableName);
else return string.Format("select top 1 * from {0}", tableName);
}
public static void AlterTable<T>(this IDbConnection db, IOrmLiteDialectProvider provider) where T : new()
{
var model = ModelDefinition<T>.Definition;
var table = new T();
var namingStrategy = provider.NamingStrategy;
// just create the table if it doesn't already exist
var tableName = namingStrategy.GetTableName(model.ModelName);
if (db.TableExists(tableName) == false)
{
db.CreateTable<T>(overwrite: false);
return;
}
// find each of the missing fields
var columns = GetColumnNames(db, model.ModelName, provider);
var missing = ModelDefinition<T>.Definition.FieldDefinitions
.Where(field => columns.Contains(namingStrategy.GetColumnName(field.FieldName)) == false)
.ToList();
// add a new column for each missing field
foreach (var field in missing)
{
var columnName = namingStrategy.GetColumnName(field.FieldName);
var alterSql = string.Format("ALTER TABLE {0} ADD COLUMN {1} {2}",
tableName,
columnName,
db.GetDialectProvider().GetColumnTypeDefinition(field.FieldType)
);
Console.WriteLine(alterSql);
db.ExecuteSql(alterSql);
}
}
}
I implemented an UpdateTable function. The basic idea is:
Rename current table on database.
Let OrmLite create the new schema.
Copy the relevant data from the old table to the new.
Drop the old table.
Github Repo: https://github.com/peheje/Extending-NServiceKit.OrmLite
Condensed code:
public interface ISqlProvider
{
string RenameTableSql(string currentName, string newName);
string GetColumnNamesSql(string tableName);
string InsertIntoSql(string intoTableName, string fromTableName, string commaSeparatedColumns);
string DropTableSql(string tableName);
}
public static void UpdateTable<T>(IDbConnection connection, ISqlProvider sqlProvider) where T : new()
{
connection.CreateTableIfNotExists<T>();
var model = ModelDefinition<T>.Definition;
string tableName = model.Name;
string tableNameTmp = tableName + "Tmp";
string renameTableSql = sqlProvider.RenameTableSql(tableName, tableNameTmp);
connection.ExecuteNonQuery(renameTableSql);
connection.CreateTable<T>();
string getModelColumnsSql = sqlProvider.GetColumnNamesSql(tableName);
var modelColumns = connection.SqlList<string>(getModelColumnsSql);
string getDbColumnsSql = sqlProvider.GetColumnNamesSql(tableNameTmp);
var dbColumns = connection.SqlList<string>(getDbColumnsSql);
List<string> activeFields = dbColumns.Where(dbColumn => modelColumns.Contains(dbColumn)).ToList();
string activeFieldsCommaSep = ListToCommaSeparatedString(activeFields);
string insertIntoSql = sqlProvider.InsertIntoSql(tableName, tableNameTmp, activeFieldsCommaSep);
connection.ExecuteSql(insertIntoSql);
string dropTableSql = sqlProvider.DropTableSql(tableNameTmp);
//connection.ExecuteSql(dropTableSql); //maybe you want to clean up yourself, else uncomment
}
private static String ListToCommaSeparatedString(List<String> source)
{
var sb = new StringBuilder();
for (int i = 0; i < source.Count; i++)
{
sb.Append(source[i]);
if (i < source.Count - 1)
{
sb.Append(", ");
}
}
return sb.ToString();
}
}
MySql implementation:
public class MySqlProvider : ISqlProvider
{
public string RenameTableSql(string currentName, string newName)
{
return "RENAME TABLE `" + currentName + "` TO `" + newName + "`;";
}
public string GetColumnNamesSql(string tableName)
{
return "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + tableName + "';";
}
public string InsertIntoSql(string intoTableName, string fromTableName, string commaSeparatedColumns)
{
return "INSERT INTO `" + intoTableName + "` (" + commaSeparatedColumns + ") SELECT " + commaSeparatedColumns + " FROM `" + fromTableName + "`;";
}
public string DropTableSql(string tableName)
{
return "DROP TABLE `" + tableName + "`;";
}
}
Usage:
using (var db = dbFactory.OpenDbConnection())
{
DbUpdate.UpdateTable<SimpleData>(db, new MySqlProvider());
}
Haven't tested with FKs. Can't handle renaming properties.
I needed to implement something similiar and found the post by Scott very helpful. I decided to make a small change which will make it much more agnostic. Since I only use Sqlite and MSSQL, I made the getCommand method very simple, but can be extended. I used a simple datatable to get the columns. This solution works perfectly for my requirements.
public static class IDbConnectionExtensions
{
private static List<string> GetColumnNames(IDbConnection db, string tableName,IOrmLiteDialectProvider provider)
{
var columns = new List<string>();
using (var cmd = db.CreateCommand())
{
cmd.CommandText = getCommandText(tableName, provider);
var tbl = new DataTable();
tbl.Load(cmd.ExecuteReader());
for (int i = 0; i < tbl.Columns.Count; i++)
{
columns.Add(tbl.Columns[i].ColumnName);
}
}
return columns;
}
private static string getCommandText(string tableName, IOrmLiteDialectProvider provider)
{
if(provider == SqliteDialect.Provider)
return string.Format("select * from {0} limit 1", tableName);
else return string.Format("select top 1 * from {0}", tableName);
}
private static List<string> GetColumnNames(object poco)
{
var list = new List<string>();
foreach (var prop in poco.GetType().GetProperties())
{
list.Add(prop.Name);
}
return list;
}
public static void AlterTable<T>(this IDbConnection db, IOrmLiteDialectProvider provider) where T : new()
{
var model = ModelDefinition<T>.Definition;
var table = new T();
// just create the table if it doesn't already exist
if (db.TableExists(model.ModelName) == false)
{
db.CreateTable<T>(overwrite: false);
return;
}
// find each of the missing fields
var columns = GetColumnNames(db, model.ModelName,provider);
var missing = ModelDefinition<T>.Definition.FieldDefinitions
.Where(field => columns.Contains(field.FieldName) == false)
.ToList();
// add a new column for each missing field
foreach (var field in missing)
{
var alterSql = string.Format("ALTER TABLE {0} ADD {1} {2}",
model.ModelName,
field.FieldName,
db.GetDialectProvider().GetColumnTypeDefinition(field.FieldType)
);
Console.WriteLine(alterSql);
db.ExecuteSql(alterSql);
}
}
}
So I took user44 answer, and modified the AlterTable method to make it a bit more efficient.
Instead of looping and running one SQL query per field/column, I merge it into one with some simple text parsing (MySQL commands!).
public static void AlterTable<T>(this IDbConnection db, IOrmLiteDialectProvider provider) where T : new()
{
var model = ModelDefinition<T>.Definition;
var table = new T();
var namingStrategy = provider.NamingStrategy;
// just create the table if it doesn't already exist
var tableName = namingStrategy.GetTableName(model.ModelName);
if (db.TableExists(tableName) == false)
{
db.CreateTable<T>(overwrite: false);
return;
}
// find each of the missing fields
var columns = GetColumnNames(db, model.ModelName, provider);
var missing = ModelDefinition<T>.Definition.FieldDefinitions
.Where(field => columns.Contains(namingStrategy.GetColumnName(field.FieldName)) == false)
.ToList();
string alterSql = "";
string addSql = "";
// add a new column for each missing field
foreach (var field in missing)
{
var alt = db.GetDialectProvider().ToAddColumnStatement(typeof(T), field); // Should be made more efficient, one query for all changes instead of many
int index = alt.IndexOf("ADD ");
alterSql = alt.Substring(0, index);
addSql += alt.Substring(alt.IndexOf("ADD COLUMN")).Replace(";", "") + ", ";
}
if (addSql.Length > 2)
addSql = addSql.Substring(0, addSql.Length - 2);
string fullSql = alterSql + addSql;
Console.WriteLine(fullSql);
db.ExecuteSql(fullSql);
}

running stored procedures into own model with servicestack ormlite

Is there any examples to be found for running a stored procedure on serviceStack MVC using ormlite? mythz ? seen this block of code:
var results = new List<EnergyCompare>
{dbFactory.Exec(dbCmd =>
{
dbCmd.CommandType = CommandType.StoredProcedure;
dbCmd.Parameters.Add(new SqlParameter("#id", 1));
dbCmd.CommandText = "GetAuthorById";
return dbCmd.ExecuteReader().ConvertTo<EnergyCompare>();
}
)};
but came with the text of never worked on the google groups!
i can also write this:
using(var db = new SwitchWizardDb())
{
var results2 = db.dbCmd.ExecuteProcedure()
}
but not sure how to complete this with parameters, and in the source code I looked at, it said obsolete?
thanks
Looks like ServiceStack.ORMLite has been updated to make this easier:
List<Poco> results = db.SqlList<Poco>("EXEC GetAnalyticsForWeek 1");
List<Poco> results = db.SqlList<Poco>("EXEC GetAnalyticsForWeek #weekNo", new { weekNo = 1 });
List<int> results = db.SqlList<int>("EXEC GetTotalsForWeek 1");
List<int> results = db.SqlList<int>("EXEC GetTotalsForWeek #weekNo", new { weekNo = 1 });
This example is on the front page of the github repo.
Well I figured it was best to roll my own handler so have created this, any thoughts would be most welcome, especially with how I could pass over params in some kind of func or something:
I have a main class to deal with easy access to my connection object:
public class DatabaseNameSp : IDisposable
{
private readonly SqlConnection _spConn = new SqlConnection(DatabaseNameSp .dbConString);
public readonly SqlCommand SpCmd;
public DatabaseNameSp (string procedureName)
{
_spConn.Open();
SpCmd = new SqlCommand
{
Connection = _spConn,
CommandType = CommandType.StoredProcedure,
CommandText = procedureName
};
}
public void Dispose()
{
_spConn.Close();
SpCmd.Dispose();
}
}
usage:
using (var db = new DatabaseNameSp ("procedurenname"))
{
db.SpCmd.Parameters.Add(new SqlParameter("#Id", 1));
var rdr = db.SpCmd.ExecuteReader(CommandBehavior.CloseConnection);
var results = new List<CustomDTO>();
while (rdr.Read())
{
results.Add(new CustomDTO { Name = rdr["name"].ToString(), Id = rdr["id"].ToString() });
}
return new CustomDTOResponse { Results = results };
}
Any thoughts !
thanks
Here is an example of running a stored procedure with ormLite that may help you:
IList<MyDTO> myList = DbFactory.Run(dbCnx =>
{
using (var dbCmd = dbCnx.CreateCommand())
{
dbCmd.CommandType = CommandType.StoredProcedure;
dbCmd.CommandText = "mySchema.myStoredProc";
dbCmd.Parameters.Add(new SqlParameter("#param1", val1));
dbCmd.Parameters.Add(new SqlParameter("#param2", val2));
var r = dbCmd.ExecuteReader();
return r.ConvertToList<MyDTO>();
}
});
To just simply run a stored procedure with no data returned:
public class ComsManager : Dbase
{
private IDbConnection dbConn;
public ComsManager()
{
dbConn = Dbase.GetConnection();
}
public void Housekeeping()
{
using(var dbCmd = dbConn.CreateCommand())
dbConn.Exec(res => { dbCmd.CommandType = CommandType.StoredProcedure; dbCmd.CommandText = "SP_housekeeping"; dbCmd.ExecuteNonQuery(); });
}

update record in recordstore j2me

i want to know the method used to update record in recordstore in j2me. thanks....
Simply use RecordStore.setRecord()
try this
Preferences preferences = new Preferences("ChatAppPref");
preferences.put("login", "y");
preferences.save();
String pIsLogin = preferences.get("login");
Preferences class here
package com.util;
import java.util.*;
import javax.microedition.rms.*;
public class Preferences {
private String mRecordStoreName;
private Hashtable mHashtable;
public Preferences(String recordStoreName)
throws RecordStoreException {
mRecordStoreName = recordStoreName;
mHashtable = new Hashtable();
load();
}
public String get(String key) {
return (String)mHashtable.get(key);
}
public void put(String key, String value) {
if (value == null) value = "";
mHashtable.put(key, value);
}
private void load() throws RecordStoreException {
RecordStore rs = null;
RecordEnumeration re = null;
try {
rs = RecordStore.openRecordStore(mRecordStoreName, true);
re = rs.enumerateRecords(null, null, false);
while (re.hasNextElement()) {
byte[] raw = re.nextRecord();
String pref = new String(raw);
// Parse out the name.
int index = pref.indexOf('|');
String name = pref.substring(0, index);
String value = pref.substring(index + 1);
put(name, value);
}
}
finally {
if (re != null) re.destroy();
if (rs != null) rs.closeRecordStore();
}
}
public void save() throws RecordStoreException {
RecordStore rs = null;
RecordEnumeration re = null;
try {
rs = RecordStore.openRecordStore(mRecordStoreName, true);
re = rs.enumerateRecords(null, null, false);
// First remove all records, a little clumsy.
while (re.hasNextElement()) {
int id = re.nextRecordId();
rs.deleteRecord(id);
}
// Now save the preferences records.
Enumeration keys = mHashtable.keys();
while (keys.hasMoreElements()) {
String key = (String)keys.nextElement();
String value = get(key);
String pref = key + "|" + value;
byte[] raw = pref.getBytes();
rs.addRecord(raw, 0, raw.length);
}
}
finally {
if (re != null) re.destroy();
if (rs != null) rs.closeRecordStore();
}
}
}

Resources