In the next version of my app, I need to update a column from NVarChar(16) to NVarChar(255) on one of the tables in my local database. Currently the column is marked up as follows:
[global::System.Data.Linq.Mapping.TableAttribute()]
public partial class Message : INotifyPropertyChanged
{
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Name", DbType = "NVarChar(16) NOT NULL", CanBeNull = false)]
public string Name
{
...
}
}
All examples that I've seen point to the DatabaseSchemaUpdater class, however, it has methods to Add a column, but none to update the length of the column.
How do I update the column length?
It turns out the API does not allow you to do that. Or drop columns. The only thing you could do is add a new column (it must be nullable for some reason), use it and ignore the ones you no longer want.
Weak API design.
Related
I would like to add new column in my existed table using domain class but it is not happening. if I use create-drop in application.yml file then it works but at the same time I lost my data. I needed to keep the data as well as I needed to add new column by updating domain class property in grails 3.3.0 and SQL Server 2012
package com.alumni
class Student
{
String studentId
String studentName
String age
static constraints = {
}
}
Database is not updating with column address
It's unclear from your code snippet, but it sounds like you're trying to add
String address
Note that columns are made NOT NULL by default, so if data exists in the table, it's attempting to add a non-nullable column, with null data on every row, so the column will fail to create. You need to allow this column to be nullable in the constraints block as well
static constraints = {
address(nullable: true)
}
If you add that, the column should create successfully.
I am using dapper and also dapper.contrib.My question is how can I create an generic pagination class.
Here is the what I have tried so far.
public class GenericRepository<T> :IGenericRepository<T> where T : class
{
public async Task<IEnumerable<T>> GetAllPagedAsync(int limit,int offset)
{
var list = await Connection.GetAllAsync<T>();//but this return IEnumarable
return list;
}
}
What I am thinking is get the T name of the class which is the same as Table name,and write an sql string called sql_statement which is apply pagination.later apply this code.
var list = await Connection.QueryAsync<T>("sql_statement")
Does this make sense? I s there any better way to achive that.
It looks currently as though you are planning to retrieve all of the rows in the table and then select from them the page of data you actually require. It would likely be quicker to just select the page you need straight from the database, unless you do actually need all of the rows for some reason.
Assuming that your table names are always going to match exactly with their respective class/entity names, the following will give you a paged result (using postgres):
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
public async Task<IEnumerable<T>> GetAllPagedAsync(int limit, int offset)
{
var tableName = typeof(T).Name;
// assuming here you want the newest rows first, and column name is "created_date"
// may also wish to specify the exact columns needed, rather than *
var query = "SELECT * FROM #TableName ORDER BY created_date DESC Limit #Limit Offset #Offset";
var results = Connection.QueryAsync<T>(query, new {Limit = limit, Offset = offset});
return results;
}
}
A note regarding this. I am obviously not familiar with the structure or size of your database, however for most general purposes the limit/offset approach to paging shown here will most probably be sufficient. There are however some potential issues you may wish to consider:
When the offset value gets very large performance may suffer.
Paging tables with a high frequency of inserts in this fashion may cause results to be duplicated/ appear on multiple pages as the offset values does not take into account new rows added to the table since the last retrieval.
Whether or not these are likely to cause issues to your particular case, these potential drawbacks, as well as some alternatives solutions are outlined here.
Is it possible to fetch a default value in grails if a column is null? If I were to represent following query via grails domain object then how could I achieve it:
SELECT IFNULL(empsalary,0.00) from Employee;
Domain object:
class Employee{
Integer id,
Float empsalary
static constraints = {
id unique: true, blank:false
empsalary nullable:true
}
}
making empsalary nullable false isn't an option due to existing data
validator on empsalary seems to work when inserting rows but not while data fetch
we can consider writing say getEmpSalary() method on domain and perform check there but there are several other fields we need to do this so trying to avoid massive code changes
If you want a default value to come out of the database without having to code anything into your classes, I suggest you update every row where it is null and set it to 0 in the database. If data is getting inserted from another application and that application is allowing a null value, put a 'DEFAULT 0' on your database column.
Grails also offers an "afterLoad" event which is run when a domain object gets loaded from the database. See the documentation here: http://grails.org/doc/2.3.7/guide/GORM.html.
I think you can do this with HQL:
def salary = Employee.executeQuery('SELECT COALESCE(empsalary, 0.0) FROM Employee')[0]
See this SO Question.
Please try setting Float empsalary = 0.0 in your domain object.
So I have a class with a property like this:
public class Foo
{
[Column("GBBRSH")
public static string Gibberish { get; set;}
....
}
For saving data, I have it configured so that the update/insert statements use a custom function:
public static string GetTableColumnName(PropertyInfo property)
{
var type = typeof(ColumnAttribute);
var prop = property.GetCustomAttributes(type, false);
if (propr.Count() > 0)
return ((ColumnAttribute)prop.First()).Name;
return property.Name;
}
This handles fine, but I noticed that when I go to retrieve the data, it isn't actually pulling data back via the function for this particular column. I noticed that the other data present was pulled, but the column in question was the only field with data that didn't retrieve.
1) Is there a way to perhaps use the GetTableColumnName function for the retrieval part of Dapper?
2) Is there a way to force Dapper.NET to throw an exception if a scenario like this happens? I really don't want to have a false sense of security that everything is working as expected when it actually isn't (I get that I'm using mapping that Dapper.NET doesn't use by default, but I do want to set it up in that manner).
edit:
I'm looking in the SqlMapper source of Dapper and found:
private static IEnumerable<T> QueryInternal<T>(params) // my knowledge of generics is limited, but how does this work without a where T : object?
{
...
while (reader.Read())
{
yield return (T)func(reader);
}
...
}
so I learned about two things after finding this. Read up on Func and read up on yield (never used either before). My guess is that I need to pass reader.Read() to another function (that checks against column headers and inserts into objects appropriately) and yield return that?
You could change your select statement to work with aliases like "SELECT [Column("GBBRSH")] AS Gibberish" and provide a mapping between the attribute name and the poco property name.
That way, Dapper would fill the matching properties, since it only requires your POCO's to match the exact name of the column.
I have the following class and need to manually increment the nextId field.
class SomeIdClass {
Family family
Integer nextId = 0
long timeCreated = new Date().time }
So far I've been trying to retrieve and the latest db entry to increment it and I'm just not having any luck with that. Or am I just going about it in a totally wrong manner?
Thaks
ps: this is what I tried but get a list of Package.SomeId objects
def si = SomeId.executeQuery(" from SomeId where nextId = (select max( nextId ) from SomeId) ")
My two cents for return the last row in Grails:
DomainClass.find("from DomainClass order by id desc")
You can simply get the last saved value this way:
//works only if the primary key 'id' is non-composite
def lastEntry = SomeIdClass.last(sort: 'id')
//alternative method which will work even for composite primary key
def entryList= SomeIdClass.findAll{[sort:'id',order:'asc']}.last()
You can do this:
def maxNextId = DomainClass.executeQuery("select max(nextId) from DomainClass")[0]
Without seeing the whole context, it's hard to tell what you're doing, but as an aside, this looks pretty questionable. This method to assign ids to domain objects is probably the wrong way to go about it. But in any case, what if a new object gets inserted into the database with a greater nextId in between the time you do the query and use the value?
What about replacing
long timeCreated = new Date().time
with
Date dateCreated
which grails automatically populates, to your domain class?
Then you could do something along the lines of
SomeIdClass.listOrderByDateCreated(max: 1, order: "desc")
Also, you do know that by default grails gives every domain object an id that auto-increments right?
Why not using a sequence? You can use a sequence that is global to all your domain classes or you can define a specific sequence for that domain. You can do something like this:
static mapping = {
id generator: 'sequence', params: [sequence: 'some_name_sequence']
}
..and if for some reason you still need to have a nextId, you can create a get method that returns the value of id, something like:
def getNextId() {
return id
}
If you do this then you would need to define nextId as a transient value.
This of course assuming you don't need id and nextId to be different.
From http://www.hsqldb.org/doc/guide/ch09.html#create_table-section
The last inserted value into an identity column for a connection is available using the function IDENTITY(), for example (where Id is the identity column):
INSERT INTO Test (Id, Name) VALUES (NULL,'Test');
CALL IDENTITY();
So, assuming you're using HSQL, you may be able to do:
SomeIdClass.executeQuery("call identity();")
to get the last inserted ID and add to it. MySQL has its own similar feature if HSQL is not the correct route.
This answer is NOT TESTED.
// retrieve the last person
def p = Person.last()
//get the current id
def currentId = p.id
//increment the id manually
def nextId = currentId+1
You can also use the generator in the domain class mappings.
static mapping = {
table 'PERSON'
id generator: 'increment'
version false
}
Ummh, try
SomeIdClass.where {
// any criteria - or none
}.max('nextId').list()[0]
But of course you should be using a sequence generator for ids.