Jsf datatable writes my data 3 times - jsf

I am trying to learn JSF and i have a problem with datatable.
I get datas from database and add them to my list and try to show them in my page. It write datas 3 times. Why is it? Here is my code...
here is related part of bean..
public ArrayList<videos> getVideoss() {
Connection con1 = null;
PreparedStatement pst1 = null;
ResultSet rs1 = null;
String url1 = "jdbc:postgresql://localhost:5432/db";
String user1 = "postgres";
String password11 = "123";
try {
Class.forName("org.postgresql.Driver");
con1 = DriverManager.getConnection(url1, user1, password11);
pst1 = con1
.prepareStatement("SELECT video_name FROM videos WHERE video_course = '"
+ selectedCourse + "';");
rs1 = pst1.executeQuery();
while (rs1.next()) {
videoss.add(new videos(rs1.getString(1)));
}
System.out.println(videoss.size());
.....
xhtml file
<h:dataTable value="#{videoSearch.videoss}" var="videos">
<h:column>
<f:facet name="header">Video Name</f:facet>
#{videos.videoName}
</h:column>
</h:dataTable>
when i look the size of the list it goes like 6 , 12 , 18.. but it should be 6..
Thanks for your support..

As I commented, you are recreting the list every time the getter is called, so the list is growing because you are not clearing it anywhere. Here is a better way to do it :
// Will be called only one time
#PostConstruct
public init()
{
Connection con1 = null;
PreparedStatement pst1 = null;
ResultSet rs1 = null;
String url1 = "jdbc:postgresql://localhost:5432/Thesis";
String user1 = "postgres";
String password11 = "123";
videoss = new ArrayList();
try
{
Class.forName("org.postgresql.Driver");
con1 = DriverManager.getConnection(url1, user1, password11);
pst1 = con1.prepareStatement("SELECT video_name FROM videos WHERE video_course = '" + selectedCourse + "';");
rs1 = pst1.executeQuery();
while (rs1.next())
{
videoss.add(new videos(rs1.getString(1)));
}
System.out.println(videoss.size());
//.....
}
catch(Excepption e)
{
e.printStackTrace();
}
}
public ArrayList<videos> getVideoss()
{
return videoss;
}

Related

ServiceStack OrmLite-Oracle: Can't insert object with sequence attribute

I'm testing ServiceStack.OrmLite.Oracle (5.5.1) but can't save data to database when create model with Sequence attribute. Try to test with API & generated SQL, API not insert data but generated SQL is correct. How to fix this?
using System;
using System.Data;
using NUnit.Framework;
using ServiceStack.DataAnnotations;
using ServiceStack.OrmLite;
namespace Tests
{
public class DatabaseTest
{
private readonly IDbConnection _db;
public DatabaseTest()
{
var dbFactory = new OrmLiteConnectionFactory(
#"Data Source = (DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = ora-test)(PORT = 1521))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = twcms12c))); User Id=scott; Password=Ab123456",
OracleDialect.Provider);
_db = dbFactory.OpenDbConnection();
}
[Test]
public void CustomerInsertTest()
{
_db.DropAndCreateTable<Person>();
var customer = new Person {FirstName = "John", LastName = "Smith", Age = 20};
//Insert by API not work
_db.Insert(customer);
var customers = _db.Select<Person>();
Console.WriteLine("Person count (API) = {0}",customers.Count);
//Insert by SQL working
_db.ExecuteSql(_db.ToInsertStatement(customer));
customers = _db.Select<Person>();
Console.WriteLine("Person count (SQL) = {0}",customers.Count);
}
}
public class Person
{
[AutoIncrement]
[Sequence("PERSON_SEQ")]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int? Age { get; set; }
}
}
And output result is:
Person count (API) = 0
Person count (SQL) = 1
In ServiceStack.OrmLite.Oracle (5.5.1) have a bug in method GetNextValue (ServiceStack.OrmLite.Oracle.OracleOrmLiteDialectProvider.cs):
private object GetNextValue(IDbCommand dbCmd, string sequence, object value)
{
if (value.ToString() != "0")
{
object retObj;
if (long.TryParse(value.ToString(), out var nv))
{
LastInsertId = nv;
retObj = LastInsertId;
}
else
{
LastInsertId = 0;
retObj = value;
}
return retObj;
}
dbCmd.CommandText = $"SELECT {Quote(sequence)}.NEXTVAL FROM dual";
long result = (long)dbCmd.LongScalar();
LastInsertId = result;
return result;
}
I change it to:
private object GetNextValue(IDbCommand dbCmd, string sequence, object value)
{
if (value.ToString() != "0")
{
object retObj;
if (long.TryParse(value.ToString(), out var nv))
{
LastInsertId = nv;
retObj = LastInsertId;
}
else
{
LastInsertId = 0;
retObj = value;
}
return retObj;
}
var lastSql = dbCmd.CommandText;
dbCmd.CommandText = $"SELECT {Quote(sequence)}.NEXTVAL FROM dual";
long result = (long)dbCmd.LongScalar();
LastInsertId = result;
dbCmd.CommandText = lastSql;
return result;
}
and it work well.
P/s: I have create a pull request it was accepted by ServiceStack.

Add note to custom object

I have tried everything I can find on the net and in the existing code, but I cannot get a note added to the notes table and attached to my custom table row. I am in a real bind trying to get this note attached. Any help will be greatly appreciated.
Here is the note id def:
#region NoteID
public abstract class noteID : PX.Data.IBqlField { }
protected Guid? _NoteID;
[PXNote()]
public virtual Guid? NoteID { get; set; }
#endregion
Here is the code to insert the row and attach the note:
//Retrieve EDI Document remittance
foreach (LingoSearchResults ediRemit in docRemits)
{
resRemit = lingo.RetrieveRemit(ediRemit.documentId, docType);
partnerCustomerMap pcmap = lstPartnerCustomer.Find(delegate (partnerCustomerMap pcm)
{ return pcm.partner == resRemit.DataRemit.partner; });
int newRemittanceId = 0;
var remittance = new EDRemittance();
//Set all field values
remittance.Status = "A";
remittance.Type = resRemit.DataRemit.type;
remittance.DocumentId = resRemit.DataRemit.documentId;
remittance.RecordId = resRemit.DataRemit.recordId;
remittance.TagId = resRemit.DataRemit.tagId;
remittance.Account = resRemit.DataRemit.account;
remittance.PartnerId = resRemit.DataRemit.partner;
remittance.DocumentNumber = resRemit.DataRemit.documentNumber;
remittance.SenderType = resRemit.DataRemit.senderType;
remittance.PaymentNumber = resRemit.DataRemit.paymentNumber;
remittance.PaymentFormat = resRemit.DataRemit.paymentFormat;
remittance.PaymentReason = resRemit.DataRemit.paymentReason;
strDate = resRemit.DataRemit.remitDate.ToString();
if (DateTime.TryParseExact(strDate, "yyyyMMdd",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None, out tempDate))
remittance.RemitDate = tempDate;
else
remittance.RemitDate = DateTime.Today;
remittance.CurrencyEntity = resRemit.DataRemit.currencyEntity;
remittance.DepartmentNumber = resRemit.DataRemit.departmentNumber;
if (DateTime.TryParse(strDate, out tempDate))
remittance.ReceiveDate = tempDate;
else
remittance.ReceiveDate = DateTime.Today;
remittance.HandlingCode = resRemit.DataRemit.handlingCode;
remittance.RemitTotal = resRemit.DataRemit.remitTotal;
remittance.DetailLineCount = resRemit.DataRemit.detailLineCount;
remittance.BatchNumber = resRemit.DataRemit.batchNumber;
remittance.ReceiverType = resRemit.DataRemit.receiverType;
remittance.BatchStatus = resRemit.DataRemit.batchStatus;
remittance.PaymentMethod = resRemit.DataRemit.paymentMethod;
remittance.CurrencyCode = resRemit.DataRemit.currencyCode;
remittance.PaymentStatus = resRemit.DataRemit.paymentStatus;
remittance.Vendor = resRemit.DataRemit.vendor;
remittance.RemitNumber = resRemit.DataRemit.remitNumber;
//Insert new row, save, and retrieve new Id value
remitGraph.Remittance.Insert(remittance);
remitGraph.Persist();
newRemittanceId = (int)remitGraph.Remittance.Current.RemittanceNbr;
//Add notes for remittance
noteText = "Remit level note";
foreach (EdiNote note in resRemit.DataRemit.notes)
{
noteText += note.type + ": " + note.note + '\n';
}
if (noteText != "")
{
PXNoteAttribute.GetNoteID<EDRemittance.noteID>(remitGraph.Remittance.Cache, remittance);
PXNoteAttribute.SetNote(remitGraph.Remittance.Cache, remittance, noteText);
//remitGraph.Persist();
}
I would try the following changes
remittance = remitGraph.Remittance.Insert(remittance);
//this saves the object to the cache and gets things like Noteid generated. On the
//return trip this data is available
//remitGraph.Persist();
//PXNoteAttribute.GetNoteID<EDRemittance.noteID>(remitGraph.Remittance.Cache, remittance);
PXNoteAttribute.SetNote(remitGraph.Remittance.Cache, remittance, noteText);
remittance = remitGraph.Remittance.Update(remittance)
//at the end do an Actions.PressSave();

Load checked checkbox from database in JSF based on boolean

I am having dynamic Checkboxes from database and I need them to be checked on page load based on a boolean true or false:
My xhtml:
<h:selectManyCheckbox value="#{report.reports}">
<f:selectItems value="#{report.allreports}" />
</h:selectManyCheckbox>
My Boolean:
public boolean checkedBox(String workclass, String reportname) {
Connection conn;
int count = 0;
try {
conn = db.getDbConnection();
String sql = "select count(*)NUM from rep_access where user_work_class = ? and rep_name = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, workclass);
ps.setString(2, reportname);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
count = rs.getInt(1);
}
DBConnection.closeConn(conn);
} catch (SQLException asd) {
System.out.println(asd.getMessage());
} catch (IOException asd) {
System.out.println(asd.getMessage());
}
return count > 0;
}
How can I get My check boxes to be checked if the boolean return true. reportname is the value of the check box and workclass value is in the session.

JSF Target Unreachable, ''0'' returned null: javax.el.PropertyNotFoundException

a list of Objects :
private ArrayList<LegBeanForInsert> listOfLegs;
I show this array by using the notation with arrays: 0 , 1 , .... positional for example:
<p:selectOneMenu value="#{otcdEventsBean.listOfLegs[0].fixvar}"
effect="fade" style="width:100px; height:25px"
panelStyle="width:80px" >
<f:selectItem itemLabel="Select" itemValue="" />
<f:selectItems value="#{otcdEventsBean.fixedVariableCodes}"
itemValue="#{otcdEventsBean.listOfLegs[0].fixvar}" />
<p:ajax listener="#{otcdEventsBean.fixvarchange}" event="change" update="panelUpdate"/>
</p:selectOneMenu>
ERROR:
value="#{otcdEventsBean.listOfLegs[0].fixvar}": Target Unreachable, ''0'' returned null: javax.el.PropertyNotFoundException
in the constructor of the bean i do:
public void initLeg(){
for(int i=0;i<8;i++){
LegBeanForInsert beanLeg = new LegBeanForInsert();
beanLeg.setCallamount(new BigDecimal(0));
beanLeg.setFixvar("");
this.listOfLegs.add(beanLeg);
}
}
this method is called by another page and when the page is renderd dose not have problem the page:
public void setProduct(Object product1, Object product2) {
System.out.println("BEGIN::setProduct: " + (String) product2);
if (product1 instanceof EqdProduct) {
this.eqdProdToedit = (EqdProduct) product1;
} else if (product1 instanceof CURROPTRBTProduct) {
this.rbtProdType = (CURROPTRBTProduct) product1;
} else if (product1 instanceof COMAsianProduct) {
this.comAsianProd = (COMAsianProduct) product1;
} else if (product1 instanceof CRDProductType) {
this.crdProduct = (CRDProductType) product1;
} else if (product1 instanceof ComSwapProduct) {
firstLegComSw = (ComSwapProduct) product1;
if (product2 instanceof ComSwapProduct) {
System.out.println("Com Sawp second prod");
secondLegComSw = (ComSwapProduct) product2;
}
} else if (product1 instanceof List) {
// bisogna settare LegBeanForInsert, LE GAMBE SONO 8 !!
List<?> legs = (List<?>) product1;
String s = (String) product2;
System.out.println("setProduct 2nd arg: " + product2);
if (s.equals("Legs")) {
for (int i = 0; i < legs.size(); i++) {
Leg leg = (Leg) legs.get(i);
LegBeanForInsert beanLeg = new LegBeanForInsert();
beanLeg.setCallamount(new BigDecimal(leg.getCallamount()));
beanLeg.setCallcurrency(leg.getCallcurrency());
beanLeg.setCallmaturity(leg.getCallmaturityNumber());
beanLeg.setCodintord(leg.getCodintord());
beanLeg.setDayconvention(leg.getDayconvention());
beanLeg.setEnddate(leg.getEnddate());
beanLeg.setEventcode(leg.getEventcode());
beanLeg.setEventtype(leg.getEventtype());
beanLeg.setExercisemode(leg.getExercisemode());
beanLeg.setFixvar(leg.getFixvar());
beanLeg.setEndDate(leg.getFmtenddate());
beanLeg.setStartDate(leg.getFmtstartdate());
beanLeg.setFrequency(leg.getFrequency());
beanLeg.setFrequencymultiplier(leg.getFrequencymultiplier());
beanLeg.setFrequencyunit(leg.getFrequencyunit());
beanLeg.setInareas(leg.getInareas());
beanLeg.setIndexname(leg.getIndexname());
beanLeg.setMargin(leg.getMargin());
beanLeg.setNotional(leg.getNotional());
beanLeg.setNumber(leg.getNumber());
beanLeg.setOptioncashdelivery(leg.getOptioncashdelivery());
beanLeg.setOptionmaturity(leg.getOptionMatirityNumber());
beanLeg.setOptiontype(leg.getOptiontype());
beanLeg.setPaycurrency(leg.getPaycurrency());
beanLeg.setPutamount(leg.getPutamount());
beanLeg.setPutcurrency(leg.getPutcurrency());
beanLeg.setPutmaturity(leg.getPutMatirityNumber());
beanLeg.setQuantityunit(leg.getQuantityunit());
beanLeg.setRate(leg.getRate());
beanLeg.setRateconvention(leg.getRateconvention());
beanLeg.setSign(leg.getSign());
beanLeg.setStartdate(leg.getStartdate());
beanLeg.setStrike(leg.getStrike());
this.listOfLegs.add(beanLeg);
}
} else {
System.out.println("MoneyD 2nd arg: " + product2);
for (int i = 0; i < legs.size(); i++) {
LegMoneyDeal leg = (LegMoneyDeal) legs.get(i);
this.legMoneyD.add(leg);
}
}
} else {
// non nè nessuno di quelli bisogna settare a null tutto quanto
otcdEvents = new OtcdEvents();
crdProduct = new CRDProductType();
firstLegComSw = new ComSwapProduct();
secondLegComSw = new ComSwapProduct();
comAsianProd = new COMAsianProduct();
rbtProdType = new CURROPTRBTProduct();
listOfLegs = new ArrayList<LegBeanForInsert>();
legMoneyD = new ArrayList<LegMoneyDeal>();
eqdProdToedit = new EqdProduct();
}
}
the constructor :
public OtcdEventsBean() {
try {
Context ctx = new InitialContext();
otcdEvents = new OtcdEvents();
crdProduct = new CRDProductType();
firstLegComSw = new ComSwapProduct();
secondLegComSw = new ComSwapProduct();
comAsianProd = new COMAsianProduct();
rbtProdType = new CURROPTRBTProduct();
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/myoracleDS");
rederField = true;
listOfLegs = new ArrayList<LegBeanForInsert>();
initLeg();
eqdProdToedit = new EqdProduct();
legMoneyD = new ArrayList<LegMoneyDeal>();
legMoneyD.add(new LegMoneyDeal());
legMoneyD.add(new LegMoneyDeal());
fieldsEditingDisabled = false;
loginBean = (LoginBean) FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{loginBean}", LoginBean.class);
setFixedVariableCodes(new String[2]);
getFixedVariableCodes()[0] = "Fixed";
getFixedVariableCodes()[1] = "Variable";
setSignPremiumCodes(new String[2]);
signPremiumCodes[0] = "Pay";
signPremiumCodes[1] = "Receive";
setFrequencyUnitCodes(new String[4]);
frequencyUnitCodes[0] = "day";
frequencyUnitCodes[1] = "week";
frequencyUnitCodes[2] = "month";
frequencyUnitCodes[3] = "year";
setCashDeliveryCodes(new String[2]);
cashDeliveryCodes[0] = "C";
cashDeliveryCodes[1] = "D";
setOptionTypeCodes(new String[2]);
optionTypeCodes[0] = "CALL";
optionTypeCodes[1] = "PUT";
} catch (NamingException e) {
e.printStackTrace();
}
}
full bean code:
http://pastebin.com/EbfuSwHN
How is the init method called. Maybe that is not getting called? I do not see a new ArrayList on the definition. When do you call new on ArrayList? You should be getting a null pointer exception in the init method. You could add the new ArrayList to the beginning of the init method before the loop. Remember also that set methods get called multiple times in JSF so you should limit the code in the set method.

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);
}

Resources