How does EBean map classes to tables?
I have tables like "expense_details" and classes like model.ExpenseDetails, for example, and the classes just use the #Entity annotation without explicit mapping to a table.
Is the mapping done automatically by EBean (is it smart enough with all those "_" and CamelCase names)?
Yes it is, it uses exactly rule that you described, for SomeModel model it looks for some_model table, of course you can override it ie. using #Table annotation like:
#Entity
#Table(name = "my_custom_table_name")
public class SomeModel extends Model {
...
}
Related
I have a few data classes, that is short, so I group them together in a file.
I can defined them in a Kotlin file as it is, but would prefer it to be scope within a class/object, so the file is not just a file, but under class/object for better grouping
I could do
object Model {
data class Result(val query: Query)
data class Query(val searchinfo: SearchInfo)
data class SearchInfo(val totalhits: Int)
}
and I could also do
class Model {
data class Result(val query: Query)
data class Query(val searchinfo: SearchInfo)
data class SearchInfo(val totalhits: Int)
}
They both looks the same to me. What's the different, and if there's a preferred way in term of scoping my data classes?
I would advise against using classes for scoping other classes. As Todd explains in his answer, you can use sealed classes which offer an actual benefit of exhaustive when checks. If you don't need this feature, Kotlin has a built-in mechanism for scoping - packages:
package org.company.model
data class Result(val query: Query)
data class Query(val searchinfo: SearchInfo)
data class SearchInfo(val totalhits: Int)
I can defined them in a Kotlin file as it is, but would prefer it to be scope within a class/object, so the file is not just a file, but under class/object for better grouping
There's nothing wrong with a file containing multiple top-level elements. This is a useful language feature and is used in exactly this kind of situation.
Another option is to make all of your data classes a subclass of a sealed Model class. This will give you the benefit of defining them all in one place, because Kotlin enforces that for sealed classs. Also, having the type system know about all instances of type Model is helpful in when expressions as well because then it won't require you to put an else -> block.
sealed class Model
data class Result(val query: Query) : Model()
data class Query(val searchinfo: SearchInfo) : Model()
data class SearchInfo(val totalhits: Int) : Model()
And you can just use them directly:
val r = Result(Query(SearchInfo(3))
Instead of wrapping them in another class or object, where you'd have to refer to them like this:
val r = Model.Result(Model.Query(Model.SearchInfo(3)))
Consider the following scenario in Laravel 4.1
there is a Set model that may have many items (sorted by precedence, but this can be put aside for now)
each of these items can be of a different "kind" (think of a bag (the Set) that contains keys,wallet,cigs...)
Ideally I would like to achieve the following:
have a simplified, eager-loadable relationship between a Set and its items (explained better below)
keep the item models DRY (ideally each item extends an abstract class with basic boilerplate code)
To better illustrate what I have in mind:
class Set extends Eloquent {
// ...
public function items() {
// provides a "transparent" method to access ALL of its items ... no matter what class
}
}
and
class SubItemOne extends Item { // ... }
class SubItemTwo extends Item { // ... }
abstract class Item extends Eloquent {
public function set() {
return $this->belongsTo('Set');
}
}
because at its core each sub-class shares a lot in common with the others (think of: they can all be moved around in the set, or they can be attached an image etc. ... all of which could be defined within the abstract Item class).
Essentially, I want to be able to access all of the items belonging to my Set in situations like
Set::with('items')->find(1);
but I'm really unsure about what kind of relationship to use for the 'inverse'.
Things I've considered so far:
take out the subclassed models and just keep one Item model with a "item_kind" flag to identify its type. Have each item define a relationship to another class based on this flag... (already sounds butt-ugly to me)
polymorphic relations (including the new N-2-N introduced in L 4.1) although they don't really seem to be thought for this specific scenario: especially N2N still doesn't solve the problem of accessing ALL the items via one simple relation
ditch the eager-loadable relation and write a custom "get_items()" method that would access the individual relationships (as in ->subitemones(), ->subitemtwos() etc ) but this seems like a rather dumb way to solve this problem (i really would like to be able to access the relationship within the query builder)
I'm kinda stuck here but I can't believe I'm the only one facing this situation... I'm really hoping for a "best practice" kind of suggestion here!
You could consinder maping your class hierarcy to DB hierarcy. There are many ways to represent inheritance in your DB schema.
Considering your scenario you can have the following tables:
Set: This entity maps your parent class and stores all common information of a Set Item (eg Position etc)
SubItemOne: Extends the "set" entity, and stores only the additional information specific to this type.
SubitemTwo... etc
SubItemXXX have a 1:1 relationship with the Set entity. All you have to do is a simple JOIN to merge SubItemXXX and Set
You can read more at: How can you represent inheritance in a database?
At this moment we are keeping all Entities and Mappings into same assembly. Our entities derived from a basic class Entity which is an EntityWithTypedId
Also we are having a table name Convention telling to pluralize the table names.
Now I want to create other two base types e.q. AggregateRootEntity and AggregateEntity, both derive from Entity.
And I would like to create two set of conventions for both base entities:
Let's say:
For for all entities derived from AggregateRootEntity tables should be prefixed with "ag_" and Id is incremental generated, but for all entities derived from AggregateEntity tables should be prefixed with "a_" and Ids should be assigned.
Is it possible to Set Conventions based on some conditions?
You can do it with multiple conventions, each checking for a specific type in their Accept methods
something like:
public class LegacyEntityTableConvention : IClassConvention, IClassConventionAcceptance
{
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
criteria.Expect(x => x.EntityType.IsAny(typeof(OldClass), typeof(AnotherOldClass)));
}
public void Apply(IClassInstance instance)
{
instance.Table("tbl_" + instance.EntityType.Name);
}
}
Just a block of code out of the FNH Wiki
http://wiki.fluentnhibernate.org/Acceptance_criteria
I'm having some trouble using nHibernate, automapping and a class structure using multiple chains of abstract classes
It's something akin to this
public abstract class AbstractClassA {}
public abstract class AbstractClassB : AbstractClassA {}
public class ClassA : AbstractClassB {}
When I attempt to build these mappings, I receive the following error
"FluentNHibernate.Cfg.FluentConfigurationException was unhandled
Message: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
Database was not configured through Database method."
However, if I remove the abstract keyword from AbstractClassB, everything works fine. The problem only occurs when I have more than one abstract class in the class hierarchy.
I've manually configured the automapping to include both AbstractClassA and AbstractClassB using the following binding class
public class BindItemBases : IManualBinding
{
public void Bind(FluentNHibernate.Automapping.AutoPersistenceModel model)
{
model.IncludeBase<AbstractClassA>();
model.IncludeBase<AbstractClassB>();
}
}
I've had to do a bit of hackery to get around this, but there must be a better way to get this working. Surely nHibernate supports something like this, I just haven't figured out how to configure it right.
Cheers,
James
Why do you include abstract classes in your AutoMappings, are they presented in the database too? Could you provide the inner exception Fluent throws?
model.IncludeBase<AbstractClassA>();
model.IncludeBase<AbstractClassB>();
With this in place you are trying to map AbstractClassB to the database, which is supposedly not what you want.
Possibly a dumb question but I have a number of entities all inheriting from a base entity. The base entity does not have a table in the database. Each entity has its own table and the table definition is exactly the same. Extremely simplified example of the code is below.
public abstract class BaseEntity
{
public virtual string someProperty {get; set;}
}
public class Entity1 : BaseEntity{}
public class Entity2 : BaseEntity{}
public class CompletelyDifferentEntity
{
public virtual IList<BaseEntity> {get; set;}
}
I created the mappings for the entities. In my other domain classes if I reference the concrete classes everything works fine but if I change my other classes to reference BaseEntity instead I get a mapping Exception because the BaseEntity is not mapped. Is this something where I should use a subclass discriminator? I guess I'm not seeing the correct way to do this if the base doesn't have an associated table and the subclasses don't have a specific column that is different between the table definitions.
You have to use one of three available inheritance mappings strategies. From your description, you should consider using table-per-concrete-class mapping, or change your db scheme.
You can find more information about pros and cons of strategies here: https://www.hibernate.org/hib_docs/nhibernate/html/inheritance.html.