I have two classes:
public class Source {
String a;
}
public class Target {
String a, b;
}
When I map from source to target the attribute a is perfectly mapped. But the attribut b, which is not existing in the source, is always set to null. Is there a way to avoid this bahaviour?
When new object is instantiated all attributes are set to null. Orika will set only used attributes the others will keep their null value.
Related
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 don't quite understand what is going on in my code right now. From what I understand, a groovy set does not contain duplicates. However, I am seeing duplicates in a set and also seeing duplicates persisted to the database. Although when retrieved from the database, the duplicates are not in the set.
I have two classes (some properties removed for brevity):
class EntityType {
static hasMany = [attributes: Attribute]
}
class Attribute {
String keyname
}
In my service, I pass in a jsonarray of attributes that are added to the EntityType using type.addToAttributes(attr). If I execute the same call more than once, duplicates are added to the Set. And when persisting, the duplicates are persisted. However, when I retrieve the Set from the database, the Set is retrieved without any duplicates. So the end result is it doesn't seem to hurt anything other than filling up the database table with unnecessary data.
What am I missing about Sets?
EDIT: Here's something odd I just noticed. The duplicates are not created for all of the attributes. Only n-1 duplicates are created. When iterating through the attribute jsonarry, the first attribute is not duplicated, but each one after that is. So if my array was {a:1,b:2,c:3} it would only create duplicates of b and c.
I figured this out. I ended up having to override the int hashCode() and boolean equals(Object o) methods as such:
#Override
int hashCode() {
return keyname.hashCode() + id.hashCode()
}
#Override
boolean equals(Object o) {
Attribute other = o as Attribute
return keyname.equals(other.keyname) && id.equals(other.id)
}
While I don't really like this because it forces me to update these methods if I add new properties, it works for now.
I would agree with aiolos that the most obvious reason is that you have multiple attributes with the same name.
you can prevent this making keyname unique
class Attribute {
String keyname
static constraints = {
keyname unique:true
}
}
I have a bunch of subclasses like so:
abstract class Fruit {
...
String getType() {
// get the discriminator value for this type
GrailsDomainBinder.getMapping(this.class).discriminator
}
}
class Apple extends Fruit {
static mapping = {
discriminator 'Apple'
}
}
class Pear extends Fruit {
static mapping = {
discriminator 'Pear'
}
}
In other words, Fruit is a base type with Apple and Pear as subtypes. I exposed a type property that gets the discriminator value that's set in the subclasses.
Now I have a JsonExportService that exports an instance as JSON data. When I'm running the application, this service correctly exports the type property filled in with the discriminator value.
I now need to write a unit test for JsonExportService. Problem is, GrailsDomainBinder doesn't seem to be mocked out in unit tests, and I'm getting NPE: cannot access discriminator property on a null object.
I can work around it in two ways:
Create a static property in each subclass that has the same value as the discriminator:
class Pear extends Fruit {
static String type = 'Pear'
...
}
This seems really hacky though, and I'm declaring the same value in two places.
Change the getType() code to:
GrailsDomainBinder.getMapping(this.class)?.discriminator
This works, but now I'm basically ignoring the discriminator altogether, and the unit test is not 'complete' because it requires a follow-up integration test to ensure that the getType() method is returning the correct value.
Does anyone know of a better, unit-testing-friendly way of getting the discriminator value from the domain mapping?
It seems that DefaultGrailsDomainConfiguration is the responsible to initializing the mappings, so you can try:
def domainClass = grailsApplication.getDomainClass(Pear.class.name)
DefaultGrailsDomainConfiguration.configureDomainBinder(grailsApplication, [domainClass] as Set)
println GrailsDomainBinder.getMapping(Pear)
In Domain class FooReward I added a method
int getQuantity() {
FooRewardAssignment.countByReward(this)
}
Usage in GSP should be fooRewardInstance.quantity, but that errors on startup (in bootstrap) with message that it has no setter method found.
If I change it to
Set<FooRewardAssignment> getListOfFoos() {
FooRewardAssignment.findAllByReward(this)
}
and change the usage in GSP to be badeRewardInstance.listOfFoos.size(), it works and shows me how often a special FooReward is assigned.
Any idea what is wrong in version 1?
Two workarounds for this problem:
Changing the return value to def:
def getQuantity() {
FooRewardAssignment.countByReward(this)
}
Or by adding transients list:
static transients = ['quantity']
int getQuantity() {
FooRewardAssignment.countByReward(this)
}
Sometimes GORM create column in tabel on the basis of setters and getters method inside domain class. And in this situation GORM want add column like 'quantity' but the error occur because GORM see only getter, and don't see setter. So we can say that we don't want create this column in database (static transients) or we can set return value as def - but don't ask me why 'def getters' are not taken into account by GORM ;)
I am using ASP.NET MVC2 and Entity Framework. I am going to simplify the situation a little; hopefully it will make it clearer, not more confusing!
I have a controller action to create address, and the country is a lookup table (in other words, there is a one-to-many relationship between Country and Address classes). Let's say for clarity that the field in the Address class is called Address.Land. And, for the purposes of the dropdown list, I am getting Country.CountryID and Country.Name.
I am aware of Model vs. Input validation. So, if I call the dropdown field formLand - I can make it work. But if I call the field Land (that is, matching the variable in Address class) - I am getting the following error:
"The parameter conversion from type
'System.String' to type 'App.Country'
failed because no type converter can
convert between these types."
OK, this makes sense. A string (CountryID) comes from the form and the binder doesn't know how to convert it to Country type. So, I wrote the converter:
namespace App {
public partial class Country {
public static explicit operator Country(string countryID) {
AppEntities context = new AppEntities();
Country country = (Country) context.GetObjectByKey(
new EntityKey("AppEntities.Countries", "CountryID", countryID));
return country;
}
}
}
FWIW, I tried both explicit and implicit. I tested it from the controller - Country c = (Country)"fr" - and it works fine. However, it never got invoked when the View is posted. I am getting the same "no type converter" error in the model.
Any ideas how to hint to the model binder that there is a type converter?
Thanks
A type converter is not the same as an explicit or implicit conversion, it's an object that converts values between various types.
I think you need to create a class inherited from TypeConverter that converts between Country and other types, and apply the TypeConverterAttribute to your class to specify the converter to use :
using System.ComponentModel;
public class CountryConverter : TypeConverter
{
// override CanConvertTo, CanConvertFrom, ConvertTo and ConvertFrom
// (not sure about other methods...)
}
[TypeConverter(typeof(CountryConverter))]
public partial class Country
{
...
}