Unable to create multiple primary attributes - eloquent

How to define this relationship in Laravel ? I tried to develop three primary keys in Laravel. but it doesn't work. how could i resolve this ?

Those Keys may symbolise primary keys, foreign keys, unique columns or indexes.
You cannot have more than one primary key on a table.
Here is what I tried:
Diagram
php .\artisan make:model Employee -m
php .\artisan make:model Title -m
php .\artisan make:model Salary -m
class CreateEmployeesTable extends Migration
{
public function up(): void
{
Schema::create('employees', function (Blueprint $table) {
$table->bigIncrements('emp_no');
$table->string('first_name', 14);
$table->string('last_name', 16);
$table->date('birth_date');
$table->date('hire_date');
});
}
};
class CreateTitlesTable extends Migration
{
public function up(): void
{
Schema::create('titles', function (Blueprint $table) {
$table->unsignedBigInteger('emp_no');
$table->string('title', 50)->index();
$table->date('from_date')->index();
$table->foreign('emp_no')->references('emp_no')->on('employees');
});
}
};
class CreateSalariesTable extends Migration
{
public function up(): void
{
Schema::create('salaries', function (Blueprint $table) {
$table->unsignedBigInteger('emp_no');
$table->integer('salary');
$table->date('from_date')->index();
$table->foreign('emp_no')->references('emp_no')->on('employees');
});
}
};
Edit
Assuming that multiple key icons mean a composite key
class CreateEmployeesTable extends Migration
{
public function up(): void
{
Schema::create('employees', function (Blueprint $table) {
$table->bigIncrements('emp_no');
$table->string('first_name', 14);
$table->string('last_name', 16);
$table->date('birth_date');
$table->date('hire_date');
});
}
};
class CreateTitlesTable extends Migration
{
public function up(): void
{
Schema::create('titles', function (Blueprint $table) {
$table->unsignedBigInteger('emp_no');
$table->string('title', 50);
$table->date('from_date');
$table->foreign('emp_no')->references('emp_no')->on('employees');
$table->primary(['emp_no', 'title', 'from_date']);
});
}
};
class CreateSalariesTable extends Migration
{
public function up(): void
{
Schema::create('salaries', function (Blueprint $table) {
$table->unsignedBigInteger('emp_no');
$table->integer('salary');
$table->date('from_date');
$table->foreign('emp_no')->references('emp_no')->on('employees');
$table->primary(['emp_no', 'from_date']);
});
}
};

Related

Generic build adding fields

Consider this code:
http://try.haxe.org/#5AD6e
class Test
{
public static function main()
{
var foo = new FluentFoo(null, { bar: 1 }).hello();
}
}
class Foo
{
public function new(options:{ bar:Int }) {}
public function hello()
{
trace("Hi there");
}
}
class Fluent
{
private var parent:Null<Fluent>;
public function new(parent:Null<Fluent>)
{
this.parent = parent;
}
public function end()
{
if(parent != null) {
return parent;
}
throw 'Top level already reached';
}
}
class FluentFoo extends Fluent
{
public var base:Foo;
public function new(parent:Null<Fluent>, options:{ bar:Int })
{
super(parent);
base = new Foo(options);
}
public function hello()
{
base.hello();
return this;
}
}
I want to generate classes such as FluentFoo automatically.
In pseudohaxe code:
import haxe.Constraints.Constructible;
class Test
{
public static function main()
{
var foo = new Fluent<Foo>(null, { bar: 1 }).hello();
}
}
class Foo
{
public function new(options:{ bar:Int }) {}
public function hello()
{
trace("Hi there");
}
}
#:generic
#:genericBuild(FluentMacro.build())
class Fluent<T:Constructible<Dynamic -> Void>>
{
private var parent:Null<Fluent>;
private var base:T;
public function new(parent:Null<Fluent>, options:Dynamic)
{
this.parent = parent;
this.base = new T(options);
}
public function end()
{
if(parent != null) {
return parent;
}
throw 'Top level already reached';
}
}
class FluentMacro
{
public static function build()
{
//Get "T" public methods
//Add them to class calling this genericBuild method (in this example to Fluent_Foo)
//Modify them so they return "this"
}
}
I know that I can't use #:build as all I'd get from Context.getLocalType would be TInst(Fluent,[TInst(Fluent.T,[])]).
However, I'm not completely understanding haxe manual on generic builds - they are under the same section "Type building macros" as normal #:build, yet the build method is expected to return ComplexType, and not an array of fields. Is it possible at all to add fields in #:genericBuild?
Thank you
That was a bit more complex than I anticipated, but I did it. For other people to use: https://github.com/Misiur/Fluent

How to change database schema on runtime in EF7 or EF core

My database have different schema depending on user selections on runtime.
My code is below:
public partial class FashionContext : DbContext
{
private string _schema;
public FashionContext(string schema) : base()
{
_schema = schema;
}
public virtual DbSet<Style> Styles { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(#"Server=.\sqlexpress;Database=inforfashionplm;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Style>()
.ToTable("Style", schema: _schema);
}
}
Upon testing. I created a context instance with 'schema1'.
So far so good.
But when I create another context instance with different schema 'schema2', the resulting data in which the schema is still on 'schema1'.
Here is the implementation:
using (var db = new FashionContext("schema1"))
{
foreach (var style in db.Styles)
{
Console.WriteLine(style.Name);
}
}
Console.ReadLine();
Console.Clear();
using (var db = new FashionContext("schema2"))
{
foreach (var style in db.Styles)
{
Console.WriteLine(style.Name);
}
}
Console.ReadLine();
Later I noticed that the OnModelCreating is called only one time, so it is never called again when you create a new context instance of the same connection string.
Is it possible to have dynamic schema on runtime? Note: this is possible in EF6
One of possible way was mentioned above, but briefly, so I will try to explain with examples.
You ought to override default ModelCacheKeyFactory and ModelCacheKey.
ModelCachekeyFactory.cs
internal sealed class CustomModelCacheKeyFactory<TContext> : ModelCacheKeyFactory
where TContext : TenantDbContext<TContext>
{
public override object Create(DbContext context)
{
return new CustomModelCacheKey<TContext>(context);
}
public CustomModelCacheKeyFactory([NotNull] ModelCacheKeyFactoryDependencies dependencies) : base(dependencies)
{
}
}
ModelCacheKey.cs, please review Equals and GetHashCode overridden methods, they are not best one and should be improved.
internal sealed class ModelCacheKey<TContext> : ModelCacheKey where TContext : TenantDbContext<TContext>
{
private readonly string _schema;
public ModelCacheKey(DbContext context) : base(context)
{
_schema = (context as TContext)?.Schema;
}
protected override bool Equals(ModelCacheKey other)
{
return base.Equals(other) && (other as ModelCacheKey<TContext>)?._schema == _schema;
}
public override int GetHashCode()
{
var hashCode = base.GetHashCode();
if (_schema != null)
{
hashCode ^= _schema.GetHashCode();
}
return hashCode;
}
}
Register in DI.
builder.UseSqlServer(dbConfiguration.Connection)
.ReplaceService<IModelCacheKeyFactory, CustomModelCacheKeyFactory<CustomContext>>();
Context sample.
public sealed class CustomContext : TenantDbContext<CustomContext>
{
public CustomContext(DbContextOptions<CustomContext> options, string schema) : base(options, schema)
{
}
}
You can build the model externally and pass it into the DbContext using DbContextOptionsBuilder.UseModel()
Another (more advanced) alternative is to replace the IModelCacheKeyFactory to take schema into account.
I found a way to recreate the compiled model on each context creation.
public partial class MyModel : DbContext {
private static DbConnection _connection
{
get
{
//return a new db connection
}
}
private static DbCompiledModel _model
{
get
{
return CreateModel("schema name");
}
}
public MyModel()
: base(_connection, _model, false)
{
}
private static DbCompiledModel CreateModel(string schema)
{
var modelBuilder = new DbModelBuilder();
modelBuilder.HasDefaultSchema(schema);
modelBuilder.Entity<entity1>().ToTable(schema + ".entity1");
var builtModel = modelBuilder.Build(_connection);
return builtModel.Compile();
}
}

Entity framework add-migration scaffold with custom Migration base

I need to scaffold migration with add-migration from Package Manager Console with my custom Migration base CustomMigration which is derived from DbMigration.
public partial class NewMigration: CustomMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
I can use different command if needed. I don't have any skills in powershell scripting. How can i achieve this?
I Created new class which generated my migrations:
public class AuditMigrationCodeGenerator : CSharpMigrationCodeGenerator
{
protected override void WriteClassStart(string #namespace, string className, IndentedTextWriter writer, string #base, bool designer = false, IEnumerable<string> namespaces = null)
{
#base = #base == "DbMigration" ? "AuditMigration" : #base;
var changedNamespaces = namespaces?.ToList() ?? new List<string>();
changedNamespaces.Add("Your.Custom.Namespace");
base.WriteClassStart(#namespace, className, writer, #base, designer, changedNamespaces);
}
}
In Configuration.cs :
internal sealed class Configuration : DbMigrationsConfiguration<EfDataAccess>
{
public Configuration()
{
this.AutomaticMigrationsEnabled = false;
CodeGenerator = new AuditMigrationCodeGenerator();
}
}
And it will use your Custom code generator, which generates migrations with my desired custom migration base.
For more info: https://romiller.com/2012/11/30/code-first-migrations-customizing-scaffolded-code/
run command add-migration NewMigration. It will add new migration with name "NewMigration". If there is no changes in model, the migration will be empty:
public partial class NewMigration : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
Change base class of NewMigration to CustomMigration:
public partial class NewMigration : CustomMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
modify NewMigration as you wish
run update-database to apply migration

Laravel Schema for PostgreSQL Sequence

These are my requirements:
I have a table(upload_training_files)
The fields are id, organisation_id(foreign), year_id(foreign), created_by, created_at, updated_by, updated_at, file_path.
The organisation_id field refers to id field of organisations. It should be auto_incremented and also should identify with a sequence table(upload_training_file_organisation_id_fk_seq).
I have failed to do this in Laravel after repeated attempts. This is my schema:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUploadTrainingFileTable extends Migration {
public function up()
{
Schema::create('upload_training_file', function(Blueprint $table) {
$table->bigincrements('id');
$table->biginteger('organisation_id_fk')->unsigned()->unique();
$table->foreign('organisation_id_fk')->references('organisation_id')->on('organisations');
$table->biginteger('year_id_fk')->unsigned()->unique();
$table->foreign('year_id_fk')->references('year_id')->on('year_of_performance');
$table->biginteger('created_by')->nullable();
$table->time('created_at')->nullable();
$table->biginteger('updated_by');
$table->time('updated_at')->nullable();
$table->string('file_path')->nullable();
});
}
public function down()
{
Schema::drop('upload_training_file');
}
}
Here's the snapshot of the database table
Solved it. :)
You have to drop the primary keys before assigning every new auto increment field.
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUploadTrainingFileTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('upload_training_file', function(Blueprint $table) {
$table->bigincrements('upload_training_file_id');
});
Schema::table('upload_training_file', function($table)
{
$table->dropPrimary('upload_training_file_upload_training_file_id_primary');
});
Schema::table('upload_training_file', function($table)
{
$table->bigincrements('organisation_id_fk')->unsigned()->after('id');;
$table->foreign('organisation_id_fk')->references('organisation_id')->on('organisation');
});
Schema::table('upload_training_file', function($table)
{
$table->dropPrimary('upload_training_file_organisation_id_fk_primary');
});
Schema::table('upload_training_file', function($table)
{
$table->bigincrements('year_id_fk')->unsigned()->after('organisation_id_fk');;
$table->foreign('year_id_fk')->references('year_id')->on('year_of_performance');
$table->biginteger('created_by')->nullable();
$table->time('create_date')->nullable();
$table->biginteger('updated_by')->nullable;
$table->time('update_date')->nullable();
$table->string('file_path')->nullable();
});
Schema::table('upload_training_file', function($table)
{
$table->dropPrimary('upload_training_file_year_id_fk_primary');
$table->primary('upload_training_file_id');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('upload_training_file');
}
}

how to get doctrine2 entitymanager in slmqueue job?

I'm going to use SlmQueue (https://github.com/juriansluiman/SlmQueueDoctrine).
How can I get doctrine2 entitymanager inside job class?
I've managed to make this like this:
class DistributeNewsJob extends AbstractJob implements QueueAwareInterface, ServiceLocatorAwareInterface
{
use QueueAwareTrait;
public function execute()
{
// job code
}
private $entityManager;
private function getEntityManager()
{
if (null === $this->entityManager) {
$this->entityManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
return $this->entityManager;
}
private $services;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->services = $serviceLocator->getServiceLocator();
}
public function getServiceLocator()
{
return $this->services;
}
public function dispatch(Request $request, Response $response = null)
{
}
}
We can also do this :
You can use ObjectManagerAwareInterface from doctrine module
use DoctrineModule\Persistence\ObjectManagerAwareInterface;
use DoctrineModule\Persistence\ProvidesObjectManager as ProvidesObjectManagerTrait;
class EmailJob extends AbstractJob implements ObjectManagerAwareInterface
{
use ProvidesObjectManagerTrait;
}
That way you have ObjectManager in your job.