I want to add new fields to a domain class so that it updates the generated table's attributes set. I have a domain class like this,,
Class Book {
String name
static constraints = {
name nullable:false
}
String toString() {
return name
}
}
The GORM generated includes name along with id and version. Now I want to add ISBN to Book domain class as following
Class Book {
String name
String ISBN
static constraints = {
name nullable:false
ISBN nullable:true
}
String toString() {
return name
}
}
I don't want to use create-drop in DataSource.groovy because it will delete all my previous data. My DataSource.groovy looks like this,,
dataSource {
dbCreate = "update"
url = "jdbc:jtds:sqlserver://localhost:1433/databaseName"
username = "username"
password = "password"
}
I want GORM to add ISBN field to book table. But its not happening. Where am I wrong ?
I am using sql server 2008 and grails version 2.1.1
dataSource {
dbCreate = "update"
}
should do the trick. It updates you db without dropping the tables
you will need to crate this field in sql server by hand it use to be a easy task in sqlserver because all its tools, and you should take a look to grails database migration plugin documentation. It should be already installed in your grails version
Related
I'm using DBUnit to insert data (dumped from a Postgres DB) into SQL Server, but want to do the insert into schema "rules", not the default "dbo" schema:
Class.forName(net.sourceforge.jtds.jdbc.Driver.class.getName());
Connection sqlsCon = DriverManager.getConnection("jdbc:jtds:sqlserver://5.5.5.5:7000;databaseName=THE_DB", "THE_USER", "THE_PW");
IDatabaseConnection sqlsDbCon = new DatabaseConnection(sqlsCon);
DatabaseOperation.CLEAN_INSERT.execute(sqlsDbCon, partialDataSet);
Thank you!
If you use spring boot 2 then you can provide a custom configuration in your config:
#TestConfiguration
public class MyDbUnitConfiguration {
#Bean
public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnection(DataSource dataSource) {
DatabaseConfigBean databaseConfig = new DatabaseConfigBean();
databaseConfig.setQualifiedTableNames(Boolean.TRUE);
DatabaseDataSourceConnectionFactoryBean databaseDataSourceConnectionFactory =
new DatabaseDataSourceConnectionFactoryBean();
databaseDataSourceConnectionFactory.setDatabaseConfig(databaseConfig);
databaseDataSourceConnectionFactory.setDataSource(dataSource);
return databaseDataSourceConnectionFactory;
}
}
Include this configuration and update your datasets.xml to fully qualified names.
There are a few ways to support that, see the documentation here:
http://dbunit.sourceforge.net/faq.html#AmbiguousTableNameException
For example you could enable the qualified table names property and use the fully qualified table names like SCHEMA.TABLE. Enabling that involves the following code:
conn=getConnection();
conn.getConfig().setProperty(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, true);
Working with database-first approach creating ASPNETCORE MVC web app with user authentication, I would like to override the way the parameters from IdentityUser class are queried to the database. The reason is the current implementation of IdentityUser has two new parameters NormalizedEmail and NormalizedUserName (which in my opinion retracts from Normalization).
Is there a way I can write the code below in the Model class so that those two parameters are not included in the query to the database or is that something that needs to be done in the controller class?
public class IdentityUser : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser
{
public override string NormalizedUserName
{ get { return null; } set { value = null; } }
public override string NormalizedEmail
{ get { return null; } set { value = null; } }
}
Not far as I can tell, both parameters are part of the data model and as explained in this Issue #351
About Identity 3.0:
...Instead we compute a normalized representation of the user name and we
store it in a separate column so that lookups by normalized user name
should now be sargable.
So in other words, if you "override the way the parameters from IdentityUser class are queried to the database" in essence you'll be doing exactly the opposite the class intends to do.
I'm using C#, .NET 4.5 and Entity Framework 6 in my project. It uses both Oracle and SQL Server, depending on the installation at the client.
The approach is database-first, as this database existed already by the time we decided to change the ORM from NHibernate to Entity Framework 6.
The mapping looks like this:
ToTable(schema + ".Motorista");
Property(x => x.Criacao).HasColumnName("criacao").IsOptional();
The table and column names are all in PascalCase in the mapping, which works fine with SQL Server but, in Oracle, all the names are UpperCase which causes an error:
ORA-00942: table or view does not exist
If I manually make it uppercase, then it works fine on Oracle. But I can't do that because of compatibility to SQL Server.
How can I say to Entity Framework to uppercase all the names when using Oracle?
Can I use conventions in this scenario?
When the database names (tables and columns) are equal to the class and property names in the class model it's very easy to introduce custom code-first conventions:
In the context's OnModelCreating overload you can add these lines to add conventions how table and column names will be derived from the class and property names, respectively:
modelBuilder.Types().Configure
(c => c.ToTable(c.ClrType.Name.ToUpper(), schema));
modelBuilder.Properties().Configure
(c => c.HasColumnName(c.ClrPropertyInfo.Name.ToUpper()));
Of course you should do this conditionally, i.e. when connecting to Oracle. For instance by checking a global constant like OnOracle that you could set by
ConfigurationManager.ConnectionStrings[0].ProviderName
== "System.Data.OracleClient"
on application start up.
Check the providerName attribute in the named connection string to see if your connection is for SQL Server or Oracle (OR add a redundant value in the appSettings section of the configuration). Then do what #AaronLS suggested and add a helper method to case your names correctly and apply any additional formatting. The helper method should be tasked with checking the database type as mentioned above and applying or not applying casing/formatting.
Here is an example.
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new SomeMappedTypeMapper());
base.OnModelCreating(modelBuilder);
}
}
public class SomeMappedType
{
public int SomeMappedColumnId { get; set; }
public string SomeMappedColumn { get; set; }
}
public class SomeMappedTypeMapper : EntityTypeConfiguration<SomeMappedType>
{
public SomeMappedTypeMapper()
{
this.HasKey(x => x.SomeMappedColumnId);
this.ToTable("SomeMappedType"); // If needed, apply the same technique as used in the column name extension
this.Property(x => x.SomeMappedColumnId).HasColumnNameV2("SomeMappedColumnId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(x => x.SomeMappedColumn).HasColumnNameV2("SomeMappedColumn");
}
}
public static class TypeHelper
{
private static bool isOracle;
static TypeHelper()
{
isOracle = System.Configuration.ConfigurationManager.ConnectionStrings["yourDbConnectionName"].ProviderName.IndexOf("oracle", StringComparison.OrdinalIgnoreCase) >= 0;
}
public static PrimitivePropertyConfiguration HasColumnNameV2(this PrimitivePropertyConfiguration property, string columnName)
{
if (isOracle)
return property.HasColumnName(columnName.ToUpper());
return property.HasColumnName(columnName);
}
}
This link is in EF CORE but it may help you, this converts ToUpper, but you can change ToLower, you can also use the Nuget ** Humanizer ** for another type of capitalize.
Import that file into your project and use it like this.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ToUpperCaseTables();
modelBuilder.ToUpperCaseColumns();
// ...
}
Consider a table called "Person" with a column called "Name" in SQL Server but in oracle the table is called "PERSON" with a column called "NAME".
We were able to use our models generated against sql server on our oracle database by adding the following code to the DBContext classe's OnModelCreating
modelBuilder.Entity<Person>()
.HasEntitySetName("Person")
.ToTable("PERSON");
modelBuilder.Entity<Person>()
.Property(t => t.Name)
.HasColumnName("NAME");
I have just created an ASP.NET MVC 4 & WebAPI project. After that I have added .edmx data source to project.
I have multiple databases with the same schema. Dynamically I want to replace connection string using default constructor provided in EF.
But in Model1.Designer.cs, every time I get error like "Member with same signature already declared".
I'm unable to solve this problem.
Yes, it works! All you need to change is the connection string.
And I have just tested it in order to satisfy my own curiosity.
Here are the steps that I took:
Take an existing database and create a model for it.
Create a new empty database.
In SQL Management Studio right click the first database -> Tasks -> Export Data. Export all it's data to the newly created database.
Remove some records from the second database.
Write this code:
TMS_MiscEntities db = new TMS_MiscEntities();
TMS_MiscEntities dbCopy = new TMS_MiscEntities();
dbCopy.Database.Connection.ConnectionString = db.Database.Connection.ConnectionString.Replace("initial catalog=TMS_Misc", "initial catalog=TMS_Misc_new");
Response.Write(string.Format("DB 1 records: {0}<br/>", db.ZipCodes.Count()));
Response.Write(string.Format("DB 2 records: {0}<br/>", dbCopy.ZipCodes.Count()));
Check results:
DB 1 records: 869164
DB 2 records: 868709
Conclude that it works :)
This is how my connection string looks:
<add name="TMS_MiscEntities" connectionString="metadata=res://*/DbModel.csdl|res://*/DbModel.ssdl|res://*/DbModel.msl;provider=System.Data.SqlClient;provider connection string="data source=ws2008;initial catalog=TMS_Misc;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
I'm using Entity Framework 6.1.3. I have added a constructor to my DbContext that takes a string parameter. This string can be the name of the connection stored in your App.config or a full connection string. Something like this:
public partial class MyDBContext : DbContext
{
public MyDBContext(string connectionString)
: base(connectionString)
{
}
// DbSets, OnModelCreating, etc
}
In my case, I manage a multi-tenant application and I use a ContextFactory to build the proper connection string and return my initialized context.
public class ContextFactory
{
public MyDbContext GetContext()
{
string connectionString;
// do some stuff here
return new MyDbContext(connectionString);
}
}
I have a domain that looks something like
class Foo {
String name
static mapping = {
table 'foo'
}
}
but I want to make is more like :
static mapping = {
table "foo_${dynamicVarThatComesFromRequest}"
}
What I want to know is whether this is even possible?
Thanks!
It is possible. You can add a Hibernate interceptor to process all SQL statements and parse/replace some token in the table name you enter in the mapping with the actual table name you want to use.
src/groovy/DynamicTableNameInterceptor.groovy :
import org.hibernate.EmptyInterceptor
public class DynamicTableNameInterceptor extends EmptyInterceptor {
public String onPrepareStatement(String sql) {
// some kind of replacement logic here
def schema=SomeHelperClass.resolveSchema()
return sql.replaceAll('_SCHEMA_', schema)
}
}
grails-app/conf/spring/resources.groovy:
beans = {
// This is for Grails 1.3.x , in previous versions, the bean name is eventTriggeringInterceptor
entityInterceptor(DynamicTableNameInterceptor)
}
I don't think that's possible. Upon application startup, the mapping closure is evaluated and Hibernate mapping are generated as a result. This happens once upon startup, so dynamic resolution will not occur.
Something comparable is done in the multi-tenant-core plugin, using the 'single tenant' setup, you have a seperate database for each tenant.