Entity Framework Firebird MigrationSqlGenerator: Deactivate Transaction for Create and Insert in one Table? - entity-framework

As mentioned here Entity Framework Code First - Firebird migration: No MigrationSqlGenerator? I'm trying to enable Migrations on my Firebird-Database.
for that purpose I'm writing the following implementation of the "MigrationSqlGenerator" (not finished!):
public class FirebirdMigrationSQLGenerator : SqlServerMigrationSqlGenerator
{
protected override DbConnection CreateConnection()
{
return DbProviderFactories.GetFactory("FirebirdSql.Data.FirebirdClient").CreateConnection();
}
protected override void Generate(CreateTableOperation createTableOperation)
{
using (var writer = Writer())
{
WriteCreateTable(createTableOperation, writer);
Statement(writer.InnerWriter.ToString(), true);
}
}
private void WriteCreateTable(CreateTableOperation createTableOperation, IndentedTextWriter writer)
{
writer.WriteLine("CREATE TABLE " + Name(createTableOperation.Name) + " (");
writer.Indent++;
var columnCount = createTableOperation.Columns.Count();
createTableOperation.Columns.Each(
(c, i) =>
{
Generate(c, writer);
if (i < columnCount - 1)
{
writer.WriteLine(",");
}
});
if (createTableOperation.PrimaryKey != null)
{
writer.Write(", PRIMARY KEY ");
writer.Write("(");
writer.Write(createTableOperation.PrimaryKey.Columns.Join(Quote));
writer.WriteLine(")");
}
else
{
writer.WriteLine();
}
writer.Indent--;
writer.Write(")");
}
private void Generate(ColumnModel column, IndentedTextWriter writer)
{
writer.Write(Quote(column.Name));
writer.Write(" ");
writer.Write(BuildColumnType(column));
if ((column.IsNullable != null)
&& !column.IsNullable.Value)
{
writer.Write(" NOT NULL");
}
if (column.DefaultValue != null)
{
writer.Write(" DEFAULT ");
writer.Write(Generate((dynamic)column.DefaultValue));
}
else if (!string.IsNullOrWhiteSpace(column.DefaultValueSql))
{
writer.Write(" DEFAULT ");
writer.Write(column.DefaultValueSql);
}
}
protected override void Generate(InsertHistoryOperation op)
{
using (var writer = Writer())
{
WriteinsertHistory(op, writer);
Statement(writer.InnerWriter.ToString(), true);
}
}
private void WriteinsertHistory(InsertHistoryOperation insertHistoryOperation, IndentedTextWriter writer)
{
StringBuilder model = new StringBuilder();
foreach (byte item in insertHistoryOperation.Model)
model.Append(item.ToString("X2"));
writer.Write("INSERT INTO \"" + insertHistoryOperation.Table.ToUpper() + "\" (migrationId, model, productVersion) ");
writer.Write(" values ( '{0}', '{1}', '{2}') ",
insertHistoryOperation.MigrationId,
"0x" + model.ToString(),
insertHistoryOperation.ProductVersion);
}
protected override string Quote(string identifier)
{
return identifier.Replace("PK_dbo.", "").ToUpper();
}
protected override string Name(string inString)
{
return "\"" + inString.Replace("dbo.", "").ToUpper() + "\"";
}
protected override string BuildColumnType(ColumnModel column)
{
String colType = base.BuildColumnType(column);
if (colType == "INT")
colType = "INTEGER";
return colType;
}
}
My problem is that the __MigrationHistory table is created uppercase. But since the "HistoryContext" is not, the first SELECT-Statement is throwing an Exception:
SELECT
"A"."A1" AS "C1"
FROM ( SELECT
COUNT("B"."A1") AS "A1"
FROM ( SELECT
1 AS "A1"
FROM "__MigrationHistory" AS "B"
) AS "B"
) AS "A"
Normaly I would insert "modelBuilder.Conventions.Remove()"
into the Context, but the HistroyContext is part of the framework and can't be changed...
Any ideas?
My Environment: EntityFramework 5.0.0 .NET 4.5 FirebirdClient 3.0.2.0

In Firebird tablenames are only case sensitive when quoted, so you either need to stop quoting tablenames (both on creation and in queries), or you need to stop upper casing tablenames and use them as is.
For example issueing a CREATE TABLE xyz ( ... ) will create a table XYZ that can be accessed using SELECT * FROM xyz, but also with XyZ,XYZ and "XYZ". It cannot be accessed using "xyz".
Creating a table as CREATE TABLE "xyz" ( ... ) wil create a table xyz, which can only be accessed using SELECT * FROM "xyz", but not with xyz (no quotes) or any other combination of casing and with or without quotes. On the other hand CREATE TABLE "XYZ" ( ... ) can be accessed using SELECT * FROM xyz and "XYZ", and any other case without quoting, but not with SELECT * FROM "xyz".
As far as I can tell from your code, you are creating tables unquoted in WriteCreateTable, therefor the name is stored uppercase, but you are inserting into them quoted. You may also want to look into the contract/expectations of the Quote and Name methods, as it looks to me like you got their implementation reversed (Quote does what Name should do and vice versa).

Related

Java is not supporting special characters in various languages including Japanese, Russian, Spanish, French and Italian to write an excel file

I am reading some info from a database in MySQL and I need to write them in an excel file
XSSFWorkbook workbook =new XSSFWorkbook();
...
cell.setCellValue(addressValue); // suppose addressValue is what I have obtained from mysql
....
try (FileOutputStream outputStream = new FileOutputStream(myfile)) {
workbook.write(outputStream);
}
In MySQL, the table charset is UTF8, and the field is considered utf8_general_ci.
But this way, it does not handle special characters. for example I see something like "名古屋市" while it should be "名古屋市".
Or
"Москва" which should be "Москва".
Or
"St. Honoré" which should be "St. Honoré".
1- Thanks to Mark Rotteveel, I share the code that solved my problem here maybe it works for others as well. The link is:
how to unescape XML in java
public static String unescapeXML( final String xml )
{
Pattern xmlEntityRegex = Pattern.compile( "&(#?)([^;]+);" );
// Matcher requires a StringBuffer instead of a StringBuilder
StringBuffer unescapedOutput = new StringBuffer( xml.length() );
Matcher m = xmlEntityRegex.matcher( xml );
Map<String,String> builtinEntities = null;
String entity;
String hashmark;
String ent;
int code;
while ( m.find() ) {
ent = m.group(2);
hashmark = m.group(1);
if ( (hashmark != null) && (hashmark.length() > 0) ) {
code = Integer.parseInt( ent );
entity = Character.toString( (char) code );
} else {
//must be a non-numerical entity
if ( builtinEntities == null ) {
builtinEntities = buildBuiltinXMLEntityMap();
}
entity = builtinEntities.get( ent );
if ( entity == null ) {
//not a known entity - ignore it
entity = "&" + ent + ';';
}
}
m.appendReplacement( unescapedOutput, entity );
}
m.appendTail( unescapedOutput );
return unescapedOutput.toString();
}
private static Map<String,String> buildBuiltinXMLEntityMap()
{
Map<String,String> entities = new HashMap<String,String>(10);
entities.put( "lt", "<" );
entities.put( "gt", ">" );
entities.put( "amp", "&" );
entities.put( "apos", "'" );
entities.put( "quot", "\"" );
return entities;
}
2- Ok Guys, in case anyone needs it I found out a simpler way to achieve it: you have to import org.apache.commons.text.StringEscapeUtils;
StringEscapeUtils.unescapeHtml4("Your String");
you see in the pticture the text I printed as an output.

Read content of repeating sections with apache POI

I Have a word document with a repeating section, containing other content controls.
In java project, I have a function that gets all sdts (content controls) from a word document in apache POI, in a List List.
When I inspect my repeating section in that list, I can get the text inside all content controls (inside my repeating section) but is apears as a long paragraph instead of other sdt nodes.
Is there a way to inspect content of repeating section sdt with Apache POI ? I can't find anything about it in the doc
function that gets all sdts
private static List
extractSDTsFromBodyElements(List<IBodyElement> elements) {
List<AbstractXWPFSDT> sdts = new ArrayList<AbstractXWPFSDT>();
for (IBodyElement e : elements) {
if (e instanceof XWPFSDT) {
XWPFSDT sdt = (XWPFSDT) e;
sdts.add(sdt);
} else if (e instanceof XWPFParagraph) {
XWPFParagraph p = (XWPFParagraph) e;
for (IRunElement e2 : p.getIRuns()) {
if (e2 instanceof XWPFSDT) {
XWPFSDT sdt = (XWPFSDT) e2;
sdts.add(sdt);
}
}
}
}
return sdts;
}
The XWPF part of apache poi is rudimentary until now and highly in development. In XWPFSDT is this mentioned also: "Experimental class to offer rudimentary read-only processing of of StructuredDocumentTags/ContentControl". So until now your code only gets the surrounding XWPFSDT of the repeating content control but not the inner controls. One could have seen that by having some debugging outputs in the code. See my System.out.println(...).
So to really get all XWPFSDTs we must go other ways using the underlaying XMLdirectly.
Lets have a complete example.
Look at this Worddocument:
As you see there is a single control to input the group name, then a repeating content control around three controls to input name, amount and date and then a single control to input the employee. All controls which shall be read have titles set. So whether the title is set, is the criterion whether a control is important for reading or not.
The following code now can read all controls and their content:
import java.io.FileInputStream;
import org.apache.poi.xwpf.usermodel.*;
import java.util.List;
import java.util.ArrayList;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.apache.xmlbeans.XmlCursor;
import javax.xml.namespace.QName;
public class ReadWordForm {
/*
private static List<AbstractXWPFSDT> extractSDTsFromBodyElements(List<IBodyElement> elements) {
List<AbstractXWPFSDT> sdts = new ArrayList<AbstractXWPFSDT>();
for (IBodyElement e : elements) {
if (e instanceof XWPFSDT) {
XWPFSDT sdt = (XWPFSDT) e;
System.out.println("block: " + sdt);
sdts.add(sdt);
} else if (e instanceof XWPFParagraph) {
XWPFParagraph p = (XWPFParagraph) e;
for (IRunElement e2 : p.getIRuns()) {
if (e2 instanceof XWPFSDT) {
XWPFSDT sdt = (XWPFSDT) e2;
System.out.println("inline: " + sdt);
sdts.add(sdt);
}
}
}
}
return sdts;
}
*/
private static List<XWPFSDT> extractSDTsFromBody(XWPFDocument document) {
XWPFSDT sdt;
XmlCursor xmlcursor = document.getDocument().getBody().newCursor();
QName qnameSdt = new QName("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "sdt", "w");
List<XWPFSDT> allsdts = new ArrayList<XWPFSDT>();
while (xmlcursor.hasNextToken()) {
XmlCursor.TokenType tokentype = xmlcursor.toNextToken();
if (tokentype.isStart()) {
if (qnameSdt.equals(xmlcursor.getName())) {
if (xmlcursor.getObject() instanceof CTSdtRun) {
sdt = new XWPFSDT((CTSdtRun)xmlcursor.getObject(), document);
//System.out.println("inline: " + sdt);
allsdts.add(sdt);
} else if (xmlcursor.getObject() instanceof CTSdtBlock) {
sdt = new XWPFSDT((CTSdtBlock)xmlcursor.getObject(), document);
//System.out.println("block: " + sdt);
allsdts.add(sdt);
}
}
}
}
return allsdts;
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument(new FileInputStream("WordDataCollectingForm.docx"));
/*
List<IBodyElement> bodyelements = document.getBodyElements();
List<AbstractXWPFSDT> sdts = extractSDTsFromBodyElements(bodyelements);
*/
List<XWPFSDT> allsdts = extractSDTsFromBody(document);
for (XWPFSDT sdt : allsdts) {
//System.out.println(sdt);
String title = sdt.getTitle();
String content = sdt.getContent().getText();
if (!(title == null) && !(title.isEmpty())) {
System.out.println(title + ": " + content);
} else {
System.out.println("====sdt without title====");
}
}
document.close();
}
}

Entity Framework 6 ToString(), formatting (DateTime format), query intercept

I`m not found correct way to search with linq2sql in DateTime (DateTime?) fields.
db.Items.Where(x => x.DateTime1.ToString().Contains("2014.08"))
Not work, because in linq2sql create CAST([XXXX.DateTime1] AS NVARCHAR(MAX)) = '04 Aug 2014' NOT 2014.08
I try use custom function mapping, but no result
Why don't you just use the Year and Month property? You should be able to convert the string input into Year and Month number. Then you do something like:
db.Items.Where(x =>
x.DateTime1.Value.Year == 2014
&& x.DateTime1.Value.Month == 8)
It will simply be converted to:
WHERE (2014 = (DATEPART (year, [Extent1].[Date])))
AND (8 = (DATEPART (month, [Extent1].[Date])))
update
You can use SqlFunctions.DatePart and DbFunctions.Right to produce following format yyyy.mm.dd.
db.Items.Where(x =>
(SqlFunctions.DatePart("yyyy", x.DateTime) + "."
+ DbFunctions.Right("0" + SqlFunctions.DatePart("m", x.DateTime1), 2) + "."
+ DbFunctions.Right("0" + SqlFunctions.DatePart("d", x.DateTime1), 2))
.Contains("2014.08"));
Function in MS SQL
CREATE FUNCTION [dbo].[ToString](#P sql_variant)
RETURNS NVARCHAR(20)
AS
BEGIN
IF (sql_variant_property(#P, 'BaseType') = 'datetime')
RETURN CONVERT(NVARCHAR(10), #P, 102) + ' ' + CONVERT(NVARCHAR(8), #P, 108);
RETURN CAST(#P as NVARCHAR(max));
END
Create sql execution Interceptor
public class DbCommandInterceptor : IDbCommandInterceptor
{
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
if (command.CommandText.IndexOf("CAST") != -1)
{
command.CommandText = command.CommandText.Replace("CAST(", "dbo.ToString(");
command.CommandText = command.CommandText.Replace("] AS nvarchar(max))", "])");
}
}
}
Add Interceptor to DbContext
public class DB : DbContext
{
public DB(): base(#"Data Source=localhost\SQLEXPRESS;Initial Catalog=EFTest")
{
DbInterception.Add(new DbCommandInterceptor ());
}
}

Entity Framework T4: POCOs implement generic interface?

I have amended the MyContext.tt T4 template so that all generated POCOs implement IDataEntity:
<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
<#=codeStringGenerator.EntityClassOpening(entity)#> : IDataEntity
{ ... }
Is it possible to generate POCOs so that they implement a generic IDataEntity<T> where T is the type of the primary key column for the given table?
For example, if the primary key of the Customer table is a Guid, then the generated class would be:
public class Customer : IDataEntity<Guid>
{ ... }
I am using Entity Framework 6.
I'm using something like this:
<## Import Namespace="System" #>
<## Import Namespace="System.Data" #>
<## Import Namespace="System.Data.SqlClient" #>
...
<#
DataSet primaryKeys = GetPrimaryKeys();
string primaryKeyName = GetPrimaryKey(primaryKeys, codeStringGenerator.EntityClassOpening(entity));
public class <#=code.Escape(entity)#> : IDataEntity<<#= primaryKeyName #>>
#>
...
<#+
string GetPrimaryKey(DataSet data, string tableName)
{
if (data != null && data.Tables != null && data.Tables[0].Rows != null)
{
foreach (DataRow row in data.Tables[0].Rows)
{
if ((row[0] as string) == tableName)
{
return (row[1] as string);
}
}
}
return null;
}
DataSet GetPrimaryKeys()
{
string connectionString = "...";
SqlConnection connection = new SqlConnection(connectionString);
string getAllExtendedProperties = #"
SELECT table_name, column_name
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1";
SqlCommand sqlSelectCommand = new SqlCommand(getAllExtendedProperties, connection);
try
{
SqlDataAdapter mySqlDataAdapter = new SqlDataAdapter();
mySqlDataAdapter.SelectCommand = sqlSelectCommand;
DataSet data = new DataSet();
if (connection.State != ConnectionState.Open) connection.Open();
mySqlDataAdapter.Fill(data);
return data;
}
catch (Exception ex)
{
//...
return null;
}
finally
{
connection.Close();
}
}
#>
In the MyContext.tt, I made the following changes:
Added a new method to the CodeStringGenerator class:
public string PropertyTypeName(EdmProperty edmProperty)
{
return _typeMapper.GetTypeName(edmProperty.TypeUsage);
}
Added the following declaration:
<#
// Determine the type if the "Id" column for the DomainEntity<T> base type
var idProperty = typeMapper.GetSimpleProperties(entity).SingleOrDefault(p => p.Name.Equals("Id"));
#>
And in the class declaration:
<#=codeStringGenerator.EntityClassOpening(entity)#> : IDataEntity<<#=codeStringGenerator.PropertyTypeName(idProperty)#>>

how to get a Table object given its name (as String) in Jackcess

im starting with java and jackcess, I have this code
public class DataManagement {
static Database db;
static Database dbopen;
static Table Users;
static Set<String> tablename;
static String[] nametabla;
public static void opendatabase(){
try {
dbopen=DatabaseBuilder.open(new File("D:/alex.accdb"));
tablename=dbopen.getTableNames();
nametabla = tablename.toArray(new String[0]);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void readtabla (String name){
System.out.println(name);
for(Column column : name.getColumns()) {
String columnName = column.getName();
System.out.println(columnName + " " );
}
}
public static void main(String[] args){
/*opening an existing database*/
opendatabase();
System.out.println("the name of tables are " + tablename);
System.out.println("the name of table 2 is " + nametabla[1]);
readtabla(nametabla[1]);
}
}
without the "for" inside of the method readtabla I get this
the name of the tables are [Establecimiento, Estado, Medición, Ubicación]
the name of table 2 is Estado
Estado
the problem lies here
for(Column column : name.getColumns())
because name must be (I think) a Table type and I send it as a string type, so how can I convert string type into Table type?
or there's another way ?
thanks in advance
You can use the getTable() method of the Database object to return a Table object:
public static void readtabla (String name) {
System.out.println(name);
Table tbl;
try {
tbl = dbopen.getTable(name);
for(Column column : tbl.getColumns()) {
String columnName = column.getName();
System.out.println(columnName + " " );
}
} catch (IOException e) {
e.printStackTrace();
}
}
you can use jackcess-orm to manipulate only java POJOs