lets say i have an orders table that is going to have a many-to-many relation to three other tables named typings, translates and theses . I know pivot table should be somehow like many to many polymorphic relation but that is not exactly what im looking for.
how should i implement pivot table?
You would create a polymorphic relationship with orders and the other three tables through a pivot table named orderables
// TABLES NEEDED
orders
id - integer
typings
id - integer
translates
id - integer
theses
id - integer
orderables
order_id - integer
orderable_id - integer
orderable_type - string
// MODELS/RELATIONSHIPS NEEDED
class Typing extends Model
{
public function orders()
{
return $this->morphToMany('App\Order', 'orderable');
}
}
class Translate extends Model
{
public function orders()
{
return $this->morphToMany('App\Order', 'orderable');
}
}
class Thesis extends Model
{
public function orders()
{
return $this->morphToMany('App\Order', 'orderable');
}
}
class Order extends Model
{
public function typings()
{
return $this->morphedByMany('App\Typing', 'orderable');
}
public function translates()
{
return $this->morphedByMany('App\Translate', 'orderable');
}
public function theses()
{
return $this->morphedByMany('App\Thesis', 'orderable');
}
}
Then, you could get the orders of a model like this:
$thesis = Thesis::find(1);
$orders = $thesis->orders;
And the inverse:
$order = Order::find(1);
$theses = $order->theses;
Related
I want to persist an entity. I want to skip it in case it already exists in the datastore. Assume the name field is part of the primary key. Assume p1 exists in the datastore. Only p2 should be inserted. Inserting p1 produces duplicate key exception.
#Entity
public class PersonEntity extends PanacheEntity {
String name;
public PersonEntity(String name){
this.name=name;
}
public static Uni<PersonEntity> findByName(String name) {
return find("name", name).firstResult();
}
}
#QuarkusTest
public class PersonResourceTest {
#Test
#ReactiveTransactional
void persistListOfPersons() {
List<PersonEntity> persons = List.of(new PersonEntity("p1"), new PersonEntity("p2"));
Predicate<PersonEntity> personExists = entity -> {
//How to consume Uni?
Uni<PersonEntity> entityUni = PersonEntity.findByName(entity.name);
//entityUni.onItem().ifNull().continueWith(???);
//include entity in filtered stream
//return true;
//exclude entity from filtered stream
return false;
};
List<PersonEntity> filteredPersons = persons.stream().filter(personExists).toList();
PersonEntity.persist(filteredPersons);
}
}
I can't produce a valid filter predicate. I need a boolean value somehow produced by the person query. But how?
This should serve as a minimum reproducable example.
I have table table_name(id, cart_token, data , created_at, updated_at ) that wants to associate with shopware cart table using token column (table_name.cart_token = cart.token).
How can we do this association using DAL as long as cart table doesn't have a CartEntity and CartDefinition.
For example: Select * from table_name leftjoin cart on table_name.cart_token=cart.token where cart.token=null.
Without a definition and accompanying entity class you simply won't be able to retrieve the cart as a mapped object using the DAL. You could add your own definition and entity for the cart table but I wouldn't recommend it, as this would just cause problems if multiple extensions got the same idea. I would recommend injecting Doctrine\DBAL\Connection in a service of your plugin and just fetching the cart using raw SQL.
class CartFetcherService
{
private Connection $connection;
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
public function fetchCart(YourCustomEntity $entity): ?array
{
$cart = $this->connection->fetchAssociative(
'SELECT * FROM `cart` WHERE `token` = :token',
[
'token' => $entity->getToken(),
]
);
return $cart ?: null;
}
}
If you want to retrieve the Cart object directly, you could also inject the Shopware\Core\Checkout\Cart\CartPersister service to load the cart.
class CartLoaderService
{
private CartPersister $persister;
public function __construct(CartPersister $persister)
{
$this->persister = $persister;
}
public function getCart(YourCustomEntity $entity, SalesChannelContext $context): ?Cart
{
try {
$cart = $this->persister->load($entity->getToken(), $context)
} catch (\Throwable $exception) {
$cart = null;
}
return $cart;
}
}
I'm trying to create a simple schema using ReflectiveSchema and then trying to project an Employee "table" using Groovy as my programming language. Code below.
class CalciteDemo {
String doDemo() {
RelNode node = new CalciteAlgebraBuilder().build()
return RelOptUtil.toString(node)
}
class DummySchema {
public final Employee[] emp = [new Employee(1, "Ting"), new Employee(2, "Tong")]
#Override
String toString() {
return "DummySchema"
}
class Employee {
Employee(int id, String name) {
this.id = id
this.name = name
}
public final int id
public final String name
}
}
class CalciteAlgebraBuilder {
FrameworkConfig config
CalciteAlgebraBuilder() {
SchemaPlus rootSchema = Frameworks.createRootSchema(true)
Schema schema = new ReflectiveSchema(new DummySchema())
SchemaPlus rootPlusDummy = rootSchema.add("dummySchema", schema)
this.config = Frameworks.newConfigBuilder().parserConfig(SqlParser.Config.DEFAULT).defaultSchema(rootPlusDummy).traitDefs((List<RelTraitDef>)null).build()
}
RelNode build() {
RelBuilder.create(config).scan("emp").build()
}
}
}
I seem to be correctly passing in the "schema" object to the constructor of the ReflectiveSchema class, but I think its failing while trying to get the fields of the Employee class.
Here's the error
java.lang.StackOverflowError
at java.lang.Class.copyFields(Class.java:3115)
at java.lang.Class.getFields(Class.java:1557)
at org.apache.calcite.jdbc.JavaTypeFactoryImpl.createStructType(JavaTypeFactoryImpl.java:76)
at org.apache.calcite.jdbc.JavaTypeFactoryImpl.createType(JavaTypeFactoryImpl.java:160)
at org.apache.calcite.jdbc.JavaTypeFactoryImpl.createType(JavaTypeFactoryImpl.java:151)
at org.apache.calcite.jdbc.JavaTypeFactoryImpl.createStructType(JavaTypeFactoryImpl.java:84)
at org.apache.calcite.jdbc.JavaTypeFactoryImpl.createType(JavaTypeFactoryImpl.java:160)
at org.apache.calcite.jdbc.JavaTypeFactoryImpl.createStructType(JavaTypeFactoryImpl.java:84)
What is wrong with this example?
Seems that by just moving the Employee class a level above, ie. making it a sibling of the DummySchema class, makes the problem go away.
I think the way the org.apache.calcite.jdbc.JavaTypeFactoryImpl of Calcite is written doesn't handle Groovy's internal fields well.
I want to create the table with custom name but I cannot find the sample code. I notice the only way to create table is by generic type like db.CreateTable(). May I know if there is a way to create the table name dynamically instead of using Alias? The reason is because sometime we want to store the same object type into different tables like 2015_january_activity, 2015_february_activity.
Apart from this, the db.Insert also very limited to object type. Is there anyway to insert by passing in the table name?
I think these features are very important as it exists in NoSQL solution for long and it's very flexible. Thanks.
OrmLite is primarily a code-first ORM which uses typed POCO's to create and query the schema of matching RDMBS tables. It also supports executing Custom SQL using the Custom SQL API's.
One option to use a different table name is to change the Alias at runtime as seen in this previous answer where you can create custom extension methods to modify the name of the table, e.g:
public static class GenericTableExtensions
{
static object ExecWithAlias<T>(string table, Func<object> fn)
{
var modelDef = typeof(T).GetModelMetadata();
lock (modelDef) {
var hold = modelDef.Alias;
try {
modelDef.Alias = table;
return fn();
}
finally {
modelDef.Alias = hold;
}
}
}
public static void DropAndCreateTable<T>(this IDbConnection db, string table) {
ExecWithAlias<T>(table, () => { db.DropAndCreateTable<T>(); return null; });
}
public static long Insert<T>(this IDbConnection db, string table, T obj, bool selectIdentity = false) {
return (long)ExecWithAlias<T>(table, () => db.Insert(obj, selectIdentity));
}
public static List<T> Select<T>(this IDbConnection db, string table, Func<SqlExpression<T>, SqlExpression<T>> expression) {
return (List<T>)ExecWithAlias<T>(table, () => db.Select(expression));
}
public static int Update<T>(this IDbConnection db, string table, T item, Expression<Func<T, bool>> where) {
return (int)ExecWithAlias<T>(table, () => db.Update(item, where));
}
}
These extension methods provide additional API's that let you change the name of the table used, e.g:
var tableName = "TableA"'
db.DropAndCreateTable<GenericEntity>(tableName);
db.Insert(tableName, new GenericEntity { Id = 1, ColumnA = "A" });
var rows = db.Select<GenericEntity>(tableName, q =>
q.Where(x => x.ColumnA == "A"));
rows.PrintDump();
db.Update(tableName, new GenericEntity { ColumnA = "B" },
where: q => q.ColumnA == "A");
rows = db.Select<GenericEntity>(tableName, q =>
q.Where(x => x.ColumnA == "B"));
rows.PrintDump();
This example is also available in the GenericTableExpressions.cs integration test.
POST EDITED - see edit below
I have a query about the FLuent Automapping which is used as part of the SHarp Architecture. Running one of the tests cases will generate a schema which I can use to create tables in my DB.
I'm developing a site with Posts, and Tags associated with these posts. I want a tag to be able to be associated with more than one post, and for each post to have 0 or more tags.
I wanting to achieve a DB schema of:
Post {Id, Title, SubmitTime, Content}
Tag {Id, Name}
PostTag {PostId, TagId}
Instead, I'm getting:
Post {Id, Title, SubmitTime, Content}
Tag {Id, Name, PostID (FK)}
I'm using sharp architecture, and may classes look as follows (more or less):
public class Post : Entity
{
[DomainSignature]
private DateTime _submittime;
[DomainSignature]
private String _posttitle;
private IList<Tag> _taglist;
private String _content;
public Post() { }
public Post(String postTitle)
{
_submittime = DateTime.Now;
_posttitle = postTitle;
this._taglist = new List<Tag>();
}
public virtual DateTime SubmitTime { get { return _submittime; } private set { _submittime = value; } }
public virtual string PostTitle { get { return _posttitle; } private set { _posttitle = value; } }
public virtual string Content { get { return _content; } set { _content = value; } }
public virtual IList<Tag> TagList { get { return _taglist; } set { _taglist = value; } }
public class Tag : Entity
{
[DomainSignature]
private String _name;
public Tag() { }
public Tag(String name)
{
this._name = name;
}
public virtual String Name
{
get { return _name; }
private set { _name = value; }
}
public virtual void EditTagName(String name)
{
this.Name = name;
}
}
I can see why it's gone for the DB schema set up that it has, as there will be times when an object can only exist as part of another. But a Tag can exist separately.
How would I go about achieving this? I'm quite new to MVC, Nhibernate, and SHarp architecture, etc, so any help would be much appreciated!
EDIT*
OK, I have now adjusted my classes slightly. My issue was that I was expecting the intermediate table to be inferred. Instead, I realise that I have to create it.
So I now have (I've simplified the classes a bit for readability's sake.:
class Post : Entity
{
[DomainSignature]
String Title
[DomainSignature]
DateTime SubmitTime
IList<PostTag> tagList
}
class Tag : Entity
{
[DomainSignature]
string name
}
class PostTag : Entity
{
[DomainSignature]
Post post
[DomainSignature]
Tag tag
}
This gives me the schema for the intermediate entity along with the usual Post and Tag tables:
PostTag{id, name, PostId(FK)}
The problem with the above is that it still does not include The foreign key for Tag. Also, should it really have an ID column, as it is a relational table? I would think that it should really be a composite key consisting of the PK from both Post and Tag tables.
I'm sure that by adding to the Tag class
IList<PostTag> postList
I will get another FK added to the PostTag schema, but I don't want to add the above, as the postList could be huge. I don't need it every time I bring a post into the system. I would have a separate query to calculate that sort of info.
Can anyone help me solve this last part? Thanks for your time.
Ok, I'd been led to believe that modelling the composite class in the domain was the way forward, but I finally come across a bit of automapper override code which creates the composite table without me needing to create the class for it, which was what I was expecting in the first place:
public class PostMappingOverride
: IAutoMappingOverride
{
public void Override(AutoMapping map)
{
map.HasManyToMany(e => e.TagList)
.Inverse()
.Cascade.SaveUpdate();
}
}
This will now give me my schema (following schema non simplified):
create table Posts (
Id INT not null,
PublishTime DATETIME null,
SubmitTime DATETIME null,
PostTitle NVARCHAR(255) null,
Content NVARCHAR(255) null,
primary key (Id)
)
create table Posts_Tags (
PostFk INT not null,
TagFk INT not null
)
create table Tags (
Id INT not null,
Name NVARCHAR(255) null,
primary key (Id)
)
alter table Posts_Tags
add constraint FK864F92C27E2C4FCD
foreign key (TagFk)
references Tags
alter table Posts_Tags
add constraint FK864F92C2EC575AE6
foreign key (PostFk)
references Posts
I think the thrower is that I've been looking for a one-to-many relationship, which it is, but it is called HasManytoMAny here...