ibatis can not rereurn primary key for batch insert - mysql

in my project , we use springmvc , spring and ibatis framework, the problem is :
in my dao code is :
#Override
public Integer insertAdzoneEnvInfoBatch(List<AdzoneEnvInfoDO> adzoneEnvInfoList) {
return executeInsertBatch("AdzoneEnvInfoDAO.insertAdzoneEnvInfo",adzoneEnvInfoList);
}
public Integer executeInsertBatch(final String sqlID, final List stList) {
Integer result = new Integer(-1);
if ((sqlID != null) && (stList != null) && !stList.isEmpty()) {
result = (Integer) getSqlMapClientTemplate().execute(
new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor)
throws SQLException {
Integer result = new Integer(-1);
executor.startBatch();
for (int i = 0; i < stList.size(); i++) {
executor.insert(sqlID, stList.get(i));
}
result = new Integer(executor.executeBatch());
return result;
}
});
}
return result;
}
in my sqlmap file ,the sql is
<insert id="AdzoneEnvInfoDAO.insertAdzoneEnvInfo" parameterClass="adzoneEnvInfo">
insert into c_adzone_env_info(
url,adzoneid,pid,total_screen,screen_no,snapshot,adzone_num,ali_adzone_num,same_screen_num,same_screen_ali_num,
covered,ad_link,ad_snapshot,adzone_owner,
adzone_style,adzone_size,date_time,create_time,update_time
)
values(
#url#,#adzoneid#,#pid#,#totalScreen#,#screenNo#,#snapshot#,#adzoneNum#,#aliAdzoneNum#,
#sameScreenNum#,#sameScreenAliNum#,#covered#,#adLink#,#adSnapshot#,#adzoneOwner#,
#adzoneStyle#,#adzoneSize#,#dateTime# , now() , now()
)
<selectKey resultClass="long" keyProperty="id" type="post">
SELECT last_insert_id() as ID from c_adzone_env_info limit 1
</selectKey>
</insert>
and the dataobject has a property id respond to mysql autoincrement primary key
in my unittest ,code is
#Test
public void test(){
AdzoneEnvInfoDO adzoneEnvInfoDO = new AdzoneEnvInfoDO();
adzoneEnvInfoDO.setAdLink("adlink");
adzoneEnvInfoDO.setAdSnapshot("adsnapshot");
adzoneEnvInfoDO.setAdzoneid(99999999L);
adzoneEnvInfoDO.setAdzoneNum(434);
adzoneEnvInfoDO.setAdzoneOwner(11);
adzoneEnvInfoDO.setAdzoneSize("232下232");
adzoneEnvInfoDO.setAdzoneStyle(2);
adzoneEnvInfoDO.setAliAdzoneNum(334);
adzoneEnvInfoDO.setCovered(33);
adzoneEnvInfoDO.setUrl("sds");
adzoneEnvInfoDO.setUrlId(232323L);
adzoneEnvInfoDO.setTotalScreen(32423);
AdzoneEnvInfoDO adzoneEnvInfoDO1 = new AdzoneEnvInfoDO();
adzoneEnvInfoDO1.setAdLink("adlink");
adzoneEnvInfoDO1.setAdSnapshot("adsnapshot");
adzoneEnvInfoDO1.setAdzoneid(99999999L);
adzoneEnvInfoDO1.setAdzoneNum(434);
adzoneEnvInfoDO1.setAdzoneOwner(12);
adzoneEnvInfoDO1.setAdzoneSize("232下232");
adzoneEnvInfoDO1.setAdzoneStyle(22);
adzoneEnvInfoDO1.setAliAdzoneNum(334);
adzoneEnvInfoDO1.setCovered(33);
adzoneEnvInfoDO1.setUrl("sds");
adzoneEnvInfoDO1.setUrlId(232323L);
adzoneEnvInfoDO1.setTotalScreen(32423);
adzoneEnvInfoDAO.insertAdzoneEnvInfoBatch(Arrays.asList(adzoneEnvInfoDO, adzoneEnvInfoDO1));
System.out.println(adzoneEnvInfoDO.getId());
System.out.println(adzoneEnvInfoDO1.getId());
}
and in normal, the two object id should be parimary key in mysql ,but i found it is always null 0
and if i call a not batch method , it will be normal , the single data method is
public Long insertAdzoneEnvInfo(AdzoneEnvInfoDO adzoneEnvInfo) {
return (Long)executeInsert("AdzoneEnvInfoDAO.insertAdzoneEnvInfo",adzoneEnvInfo);
}

I got the same problem as you recently. I just read around the mybatis codes. This one is helpful to insert entities into MySQL. However it is a bit complicated because an ObjectWrapperFactory and a TypeHandler are registered in mybatis configuration file. See
https://github.com/jactive/java/tree/master/test/mybatis-demo
and the entry point
https://github.com/jactive/java/blob/master/test/mybatis-demo/java/com/jactive/mybatis/DaoTest.java

Related

Force engine=innodb when using Entity Framework Code First with mysql

I have created a new .NET MVC 5 web application using Entity Framework 6 and a msyql database. I am using code/model first. The database server has a default storage engine of MyISAM, but I would like for the tables that EF creates to be InnoDb. Does anyone know if there is as way to specify the storage engine that EF will use in the CREATE TABLE statement?
Actually the engine used by MySQL EF provider is ALWAYS InnoDB and you can't change it without rewriting the DDL generator.
To try you can create a simple project and enable log on MySQL. You will notice that every create statement will terminate with engine=InnoDb auto_increment=0
For example this class
public class Blog
{
public int BlogId { get; set; }
[MaxLength(200)]
public string Name { get; set; }
[MaxLength(200)]
public string Topic { get; set; }
public DateTime LastUpdated { get; set; }
[DefaultValue(0)]
public int Order { get; set; }
public virtual List<Post> Posts { get; set; }
}
with standard MySQL EF provider migration, generates this MySQL DDL statement
CREATE TABLE `Blogs` (
`BlogId` INT NOT NULL auto_increment,
`Name` NVARCHAR(200),
`Topic` NVARCHAR(200),
`LastUpdated` DATETIME NOT NULL,
`Order` INT NOT NULL,
PRIMARY KEY (`BlogId`)
) engine = InnoDb auto_increment = 0
Where is engine = InnoDb from? It's hard coded in migration source code.
You can have a look at the migration source code
https://github.com/mysql/mysql-connector-net/blob/6.9/Source/MySql.Data.EntityFramework5/MySqlMigrationSqlGenerator.cs
method MySqlMigrationSqlGenerator.Generate(CreateTableOperation op).
The last statement is sb.Append(") engine=InnoDb auto_increment=0");
So, the right question should be how can I change the engine from InnoDB to another engine.
You can inherit MySqlMigrationSqlGenerator class and override the method, i.e.:
internal class MyOwnMigrationSqlGenerator : MySqlMigrationSqlGenerator
{
public MyOwnMigrationSqlGenerator()
{
Engine = "InnoDB";
}
public MyOwnMigrationSqlGenerator(string engine)
{
Engine = engine;
}
private readonly List<MigrationStatement> _specialStatements = new List<MigrationStatement>();
public string Engine { get; set; }
public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
{
List<MigrationStatement> migrationStatements = base.Generate(migrationOperations, providerManifestToken).ToList();
migrationStatements.AddRange(_specialStatements);
return migrationStatements;
}
protected override MigrationStatement Generate(CreateTableOperation op)
{
StringBuilder sb = new StringBuilder();
string tableName = TrimSchemaPrefix(op.Name);
var autoIncrementCols = (List<string>)(typeof(MySqlMigrationSqlGenerator).GetProperty("autoIncrementCols", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this));
var primaryKeyCols = (List<string>)(typeof(MySqlMigrationSqlGenerator).GetProperty("primaryKeyCols", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this));
sb.Append("create table " + "`" + tableName + "`" + " (");
if (op.PrimaryKey != null)
{
op.PrimaryKey.Columns.ToList().ForEach(col => primaryKeyCols.Add(col));
}
//columns
sb.Append(string.Join(",", op.Columns.Select(c => "`" + c.Name + "` " + Generate(c))));
// Determine columns that are GUID & identity
List<ColumnModel> guidCols = new List<ColumnModel>();
ColumnModel guidPk = null;
foreach (ColumnModel columnModel in op.Columns)
{
if (columnModel.Type == PrimitiveTypeKind.Guid && columnModel.IsIdentity && String.Compare(columnModel.StoreType, "CHAR(36) BINARY", true) == 0)
{
if (primaryKeyCols.Contains(columnModel.Name))
guidPk = columnModel;
guidCols.Add(columnModel);
}
}
if (guidCols.Count != 0)
{
var createTrigger = new StringBuilder();
createTrigger.AppendLine(string.Format("DROP TRIGGER IF EXISTS `{0}_IdentityTgr`;", TrimSchemaPrefix(tableName)));
createTrigger.AppendLine(string.Format("CREATE TRIGGER `{0}_IdentityTgr` BEFORE INSERT ON `{0}`", TrimSchemaPrefix(tableName)));
createTrigger.AppendLine("FOR EACH ROW BEGIN");
foreach (ColumnModel opCol in guidCols)
createTrigger.AppendLine(string.Format("SET NEW.{0} = UUID();", opCol.Name));
createTrigger.AppendLine(string.Format("DROP TEMPORARY TABLE IF EXISTS tmpIdentity_{0};", TrimSchemaPrefix(tableName)));
createTrigger.AppendLine(string.Format("CREATE TEMPORARY TABLE tmpIdentity_{0} (guid CHAR(36))ENGINE=MEMORY;", TrimSchemaPrefix(tableName)));
createTrigger.AppendLine(string.Format("INSERT INTO tmpIdentity_{0} VALUES(New.{1});", TrimSchemaPrefix(tableName), guidPk.Name));
createTrigger.AppendLine("END");
var sqlOp = new SqlOperation(createTrigger.ToString());
_specialStatements.Add(Generate(sqlOp));
}
if (op.PrimaryKey != null) // && !sb.ToString().Contains("primary key"))
{
sb.Append(",");
sb.Append("primary key ( " + string.Join(",", op.PrimaryKey.Columns.Select(c => "`" + c + "`")) + ") ");
}
string keyFields = ",";
autoIncrementCols.ForEach(col => keyFields += (!primaryKeyCols.Contains(col) ? string.Format(" KEY (`{0}`),", col) : ""));
sb.Append(keyFields.Substring(0, keyFields.LastIndexOf(",")));
sb.Append(string.Format(") engine={0} auto_increment=0", Engine));
return new MigrationStatement() { Sql = sb.ToString() };
}
private string TrimSchemaPrefix(string table)
{
if (table.StartsWith("dbo.") || table.Contains("dbo."))
return table.Replace("dbo.", "");
return table;
}
}
Then, in your migration configuration you can specify your own sql generator.
internal sealed class MyContextMigrationConfiguration : DbMigrationsConfiguration<MyContext>
{
public MyContextMigrationConfiguration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
SetSqlGenerator("MySql.Data.MySqlClient", new MyOwnMigrationSqlGenerator("MyPreferredEngine"));
}
}
EDIT
There was a bug on MyOwnMigrationSqlGenerator class. Probably the best thing is to rewrite all MySqlMigrationSqlGenerator. In this case I just fixed the class accessing private fields of MySqlMigrationSqlGenerator (that is quite bad).

jdbcTemplate pass in null value

I'm working with mysql and spring 4.1.6, but am having trouble sending in a null variable to the data base. I know to send a null value the syntax IS NULL is used but the field being sent into the data base is optional(the only optional value in the entire object), so it may be null or may have a value.
My request to database that simple checks if the address exists called by CRUD methods:
Note: the variable in question is street2
public boolean doesExist(Address address){
String sql = "SELECT EXISTS(SELECT * FROM Address WHERE contactType=? AND street1=? AND street2 ? AND city=? AND state=? AND zip=? AND country=?);";
String s = isNullDBQuery(address.getStreet2());
jdbcTemplate = new JdbcTemplate(dataSource);
int exist = jdbcTemplate.queryForObject(sql, new Object[] {address.getContactType().name(), address.getStreet1(), isNullDBQuery(address.getStreet2()), address.getCity(), address.getState().name(), address.getZip(), address.getCountry().name()}, Integer.class);
if(exist == 1){
return true;
} else {
return false;
}
}
My isNullDBQuery:
private String isNullDBQuery(String s){
if(s == null){
return "IS NULL";
} else {
return "=" + s;
}
}
The error that's being returned is a syntax error with 'IS NULL'. The query sent to the database is street2 'IS NULL' rather then street2 IS NULL. Is it possible to get rid of the single quotation marks in my request? or is there a better way to do this?
any help is appreciated
No. Only values may be passed as parameters of a prepared statement. Not arbitrary portions of the query.
You need to use two different SQL queries (or generate it dynamically based on the nullness of the street2).
I managed to figure out how to achieve what I wanted:
public boolean doesExist(Address address){
String street2 = stringIsNull(address.getStreet2());
String sql = "SELECT EXISTS(SELECT * FROM Address WHERE contactType=? AND street1=? AND street2 " + street2 + " AND city=? AND state=? AND zip=? AND country=?);";
jdbcTemplate = new JdbcTemplate(dataSource);
int exist;
if(street2.equals("IS NULL")){
exist = jdbcTemplate.queryForObject(sql, new Object[] {address.getContactType().name(), address.getStreet1(), address.getCity(), address.getState().name(), address.getZip(), address.getCountry().name()}, Integer.class);
} else {
exist = jdbcTemplate.queryForObject(sql, new Object[] {address.getContactType().name(), address.getStreet1(), address.getStreet2(), address.getCity(), address.getState().name(), address.getZip(), address.getCountry().name()}, Integer.class);
}
if(exist == 1){
return true;
} else {
return false;
}
}
private String stringIsNull(String string){
if(string == null) {
return "IS NULL";
} else {
return "=?";
}
}

Loading millions of DB row in wicket table through a list causing outofmemory error

I'm loading million lines of data by sortabledataprovider
.. the query returns a list(Arraylist) as I sent it to a Wicket ajax enabled table and pagination enable table.
So the problem is that - If there are concurrent queries - the application might get crashed.
I'm already getting Java heap space error with just 100,000 rows in DB.
So what I want to achieve is this - when a user click on next page or may be number 10th page - it will load only the number 10th pages data from the DB - not the whole query which might have million lines in it.
here is how I loading the list by query
final SyslogProvider<SyslogParsed> sysLogProviderAjax = new SyslogProvider<SyslogParsed>(new ArrayList<SyslogParsed>());
*
*
daoList = syslogParsedDao.findByDatesAndHostName(utcStartDate, utcEndDate, null);
sysLogProviderAjax.setList(daoList);
**
DB query returning the big list of all rows
public List<logParsed> findByDatesAndHostName() {
return getJpaTemplate().execute(new JpaCallback<List<SyslogParsed>>() {
return query.getResultList();
}
});
}
=========
my data provider
public class logProvider<logParsed> extends SortableDataProvider{
/**
*
*/
private static final long serialVersionUID = 1L;
#SpringBean(name="logParsedDao")
private logParsedDao logParsedDao;
class SortableDataProviderComparator implements Comparator<logParsed>, Serializable {
public int compare(logParsed log1, logParsed log2) {
PropertyModel<Comparable> model1 = new PropertyModel<Comparable>(log1, getSort().getProperty());
PropertyModel<Comparable> model2 = new PropertyModel<Comparable>(log1, getSort().getProperty());
int result = model1.getObject().compareTo(model2.getObject());
if (!getSort().isAscending()) {
result = -result;
}
return result;
}
}
private List<logParsed> list = new ArrayList<logParsed>();
private SortableDataProviderComparator comparator = new SortableDataProviderComparator();
public logProvider(List<logParsed> sentModel){
setSort("numberOfEntries",SortOrder.DESCENDING);
list = sentModel;
}
public Iterator<logParsed> iterator(int first, int count) {
//ArrayList<logParsed> newList = (ArrayList<logParsed>) logParsedDao.findAll();
//Collections.sort(newList, comparator);
Iterator<logParsed> iterator = null;
try {
if(getSort() != null) {
Collections.sort(list, new Comparator<logParsed>() {
private static final long serialVersionUID = 1L;
public int compare(logParsed sl1, logParsed sl2) {
int result=1;
PropertyModel<Comparable> model1= new PropertyModel<Comparable>(sl1, getSort().getProperty());
PropertyModel<Comparable> model2= new PropertyModel<Comparable>(sl2, getSort().getProperty());
if(model1.getObject() == null && model2.getObject() == null)
result = 0;
else if(model1.getObject() == null)
result = 1;
else if(model2.getObject() == null)
result = -1;
else
result = model1.getObject().compareTo(model2.getObject());
result = getSort().isAscending() ? result : -result;
return result;
}
});
}
if (list.size() > (first+count))
iterator = list.subList(first, first+count).iterator();
else
iterator = list.iterator();
}
catch (Exception e) {
e.printStackTrace();
}
return iterator;
}
public int size() {
// TODO Auto-generated method stub
return list.size();
}
public IModel<logParsed> model(final Object object) {
return new AbstractReadOnlyModel<logParsed>() {
#Override
public logParsed getObject() {
return (logParsed) object;
}
};
}
public void setList(List<logParsed> newList){
list = newList;
}
}
The problem with query.list() is it returns all rows at once.
Instead of query.list() you can use either:
query.scroll(), which returns the query results as ScrollableResults
query.iterate(), which returns the query results as an Iterator
Both of these options return one row at a time, which is what you need.
Note that the query remains "executing" for the duration of processing, so you may find that the tables are locked etc depending on the isolation level you've chosen.
You have to use a JPA query that sort and returns only the desired rows each time that iterator(int first, int count) of your IDataProvider is called.
Something similar to this:
public Iterator<logParsed> iterator(int first, int count) {
Query query = entityManager.createQuery("from LogParsed m ORDER BY m.numberOfEntries DESC", LogParsed.class);
List<LogParsed> output = query.setFirstResult(first).setMaxResults(count).getResultList();
return output.iterator();
}
Have a look at this question.

How to use TIME datatype in SQL Server 2008 and C#?

I am developing a web application with C# & SQL Server 2008.
I have a data reader which reads the column PlayTime, defined as TIME datatype.
I want to write a function that returns PlayTime's value.
private static Timespan GetTime(IDataReader rdr, string columnName)`
{
int index = rdr.GetOrdinal(columnName);
if (rdr.IsDBNull(index))
{
return ; // Here I want to return null or zero
}
return (TimeSpan)rdr[index];
}
Am I right using Timespan for time data type?
How to return null if datareader value is nothing?
Best Regards,
RedsDevils
Something like this:
private static TimeSpan? GetTime(IDataReader rdr, string columnName)
{
int index = rdr.GetOrdinal(columnName);
if (rdr.IsDBNull(index))
{
return null;
}
return (TimeSpan)rdr[index];
}
You need to use nullable Timespan
private static Nullable<TimeSpan> GetTime(IDataReader rdr, string columnName)
{
int index = rdr.GetOrdinal(columnName);
if (rdr.IsDBNull(index))
{
return null;
}
return (Nullable<TimeSpan>)rdr[index];
}

SQL Code First DB - Create tables, not drop/create

I'm trying to get a MVC 3 deployment off the ground under the Azure trial, but seem to have hit a wall with getting the EF4.1 database to create itself.
When running, it will connect successfully, but give the error:
Invalid object name 'dbo.TableName'.
I believe this is because the DB exists, but there are no tables in it. I've been able to reproduce it locally - The DB recreation works fine if I delete my SQL Express DB, but not if I then delete all tables and leave the DB.
I've read up on the methods that can be added to Global.asax:
protected void Application_Start()
{
// Use any of:
System.Data.Entity.Database.SetInitializer<MyDatabaseContext>(new DropCreateDatabaseIfModelChanges<MyDatabaseContext>());
System.Data.Entity.Database.SetInitializer<MyDatabaseContext>(new CreateDatabaseIfNotExists<MyDatabaseContext>());
System.Data.Entity.Database.SetInitializer<MyDatabaseContext>(new DropCreateDatabaseAlways<MyDatabaseContext>());
}
... which don't seem to work. Some give errors about not being about to get the model hash in EdmMetadata table.
How can I get EF4.1/Code First to create the DB structure in an already existing DB? (And in Azure...). Or do I have to script the DB from SQL Management studio, and run it against the destination DB?
check David.Cline(Development) blog for "Drop & Create Tables upon Model Change":
http://www.davidcline.info/2012/05/technologies-c-v4.html
and this link may be helpful:
http://blogs.microsoft.co.il/blogs/gilf/archive/2011/05/30/creating-a-code-first-database-initializer-strategy.aspx
Thanks,
Khachatur
You need to create a different database initializer, which will just clean the database instead of recreating.
Here it is
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Data.Entity.Design;
using System.Data.Entity.Infrastructure;
using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
namespace Infrastructure
{
public partial class RecreateSchemaIfModelChanges<T> : IDatabaseInitializer<T> where T : DbContext
{
private EdmMetadata _edmMetaData;
private bool CompatibleWithModel(string modelHash, DbContext context, ObjectContext objectContext)
{
if (objectContext.ExecuteStoreQuery<int>("Select COUNT(*) \r\n FROM INFORMATION_SCHEMA.TABLES T \r\n Where T.TABLE_NAME = 'EdmMetaData'", new object[0]).FirstOrDefault<int>() == 1)
{
this._edmMetaData = context.Set<EdmMetadata>().FirstOrDefault<EdmMetadata>();
if (this._edmMetaData != null)
{
return (modelHash == this._edmMetaData.ModelHash);
}
}
return false;
}
private static string ComputeSha256Hash(string input)
{
byte[] buffer = new SHA256Managed().ComputeHash(Encoding.ASCII.GetBytes(input));
StringBuilder builder = new StringBuilder(buffer.Length * 2);
foreach (byte num in buffer)
{
builder.Append(num.ToString("X2", CultureInfo.InvariantCulture));
}
return builder.ToString();
}
private void CreateTables(ObjectContext objectContext)
{
string commandText = objectContext.CreateDatabaseScript();
objectContext.ExecuteStoreCommand(commandText, new object[0]);
}
private string GetCsdlXmlString(ObjectContext context)
{
if (context != null)
{
ReadOnlyCollection<EntityContainer> items = context.MetadataWorkspace.GetItems<EntityContainer>(DataSpace.SSpace);
if (items != null)
{
EntityModelSchemaGenerator generator = new EntityModelSchemaGenerator(items.FirstOrDefault<EntityContainer>());
StringBuilder output = new StringBuilder();
XmlWriter writer = XmlWriter.Create(output);
generator.GenerateMetadata();
generator.WriteModelSchema(writer);
writer.Flush();
return output.ToString();
}
}
return string.Empty;
}
private string GetModelHash(ObjectContext context)
{
return ComputeSha256Hash(this.GetCsdlXmlString(context));
}
public void InitializeDatabase(T context)
{
ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
string modelHash = this.GetModelHash(objectContext);
if (!this.CompatibleWithModel(modelHash, context, objectContext))
{
this.DeleteExistingTables(objectContext);
this.CreateTables(objectContext);
this.SaveModelHashToDatabase(context, modelHash, objectContext);
this.Seed(context);
}
}
private void SaveModelHashToDatabase(T context, string modelHash, ObjectContext objectContext)
{
if (this._edmMetaData != null)
{
objectContext.Detach(this._edmMetaData);
}
this._edmMetaData = new EdmMetadata();
context.Set<EdmMetadata>().Add(this._edmMetaData);
this._edmMetaData.ModelHash = modelHash;
context.SaveChanges();
}
private void DeleteExistingTables(ObjectContext objectContext)
{
var dropConstraintsScript =
#"declare #cmd varchar(4000)
declare cmds cursor for
select 'ALTER TABLE ' + so.TABLE_NAME + ' DROP CONSTRAINT ' +
so.constraint_name from INFORMATION_SCHEMA.TABLE_CONSTRAINTS so order by
so.CONSTRAINT_TYPE
open cmds
while 1=1
begin
fetch cmds into #cmd
if ##fetch_status != 0 break
print #cmd
exec(#cmd)
end
close cmds
deallocate cmds";
string dropTablesScript =
#"declare #cmd varchar(4000)
declare cmds cursor for
Select 'drop table [' + Table_Name + ']' From INFORMATION_SCHEMA.TABLES
open cmds
while 1=1
begin
fetch cmds into #cmd
if ##fetch_status != 0 break
print #cmd
exec(#cmd)
end
close cmds
deallocate cmds";
objectContext.ExecuteStoreCommand(dropConstraintsScript);
objectContext.ExecuteStoreCommand(dropTablesScript);
}
}
}
Was built for EF6 but still good DbInitializer for that issue:
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity.Migrations;
namespace MyProject.Models
{
public class MrSaleDbInitializer :
//System.Data.Entity.DropCreateDatabaseIfModelChanges<MrSaleDbContext>
System.Data.Entity.DropCreateDatabaseAlways<MrSaleDbContext>
{
/*
* Seed: Don't delete the current db, don't delete any tables, but clear all rows data in current
* db-tables, then seed the db with a new initial data.
* note: Won't clear any Migration like tables or any AspNet tables such as: __MigrationHistory, AspNetUsers, AspNetRoles.
*/
protected override void Seed(MrSaleDbContext context)
{
this.ClearDb(context);
this.SeedAfterClearingDb(context);
base.Seed(context);
}
private void ClearDb(MrSaleDbContext context)
{
//Optional: disable all foreign keys (db-schema will be loosed).
//context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable #command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'");
List<string> tableNames = context.Database.SqlQuery<string>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%Migration%' AND TABLE_NAME NOT LIKE 'AspNet%'").ToList();
for (int i = 0; tableNames.Count > 0; i++)
{
try
{
//To delete all tables and not just clean them from data, replace "DELETE FROM {0}" in "DROP TABLE {0}":
context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count)));
tableNames.RemoveAt(i % tableNames.Count);
i = -1; //flag: a table was removed. in the next iteration i++ will be the 0 index.
}
catch (System.Data.SqlClient.SqlException e) // ignore errors as these are expected due to linked foreign key data
{
//throw new Exception("Unable to clear any relevant table in data-base (due to foriegn key constraint ?). See inner-exception for more details.", e);
if ((i % tableNames.Count) == (tableNames.Count - 1))
{
//end of tables-list without any success to delete any table, then exit with exception:
throw new System.Data.DataException("Unable to clear all relevant tables in database (foriegn key constraint ?). See inner-exception for more details.", e);
}
}
}
context.SaveChanges();
}
/*
* SeedAfterClearingDb: seed the data-base with initial date after database was created.
*/
public void SeedAfterClearingDb(MrSaleDbContext context)
{
//seed the data-base with initial date after database was created.
//then...
//update all posts and save changes:
context.SaveChanges();
}
}
}