EF Core Fluent Api chaining configuration - entity-framework

How can I chain this in EF Core Fluent API, instead of repeating line by line for each property of table:
builder.Entity<FoodWeight>().HasIndex(x => x.NutrientDatabankNumber);
builder.Entity<FoodWeight>().Property(x => x.NutrientDatabankNumber).HasColumnName("NDB_No");
builder.Entity<FoodWeight>().Property(x => x.SequenceNumber).HasColumnName("Seq");
builder.Entity<FoodWeight>().Property(x => x.Amount).HasColumnName("Amount");
builder.Entity<FoodWeight>().Property(x => x.Description).HasColumnName("Msre_Desc");
builder.Entity<FoodWeight>().Property(x => x.GramWeight).HasColumnName("Gm_Wgt");
builder.Entity<FoodWeight>().Property(x => x.GramWeight).HasColumnName("Gm_Wgt");
builder.Entity<FoodWeight>().Property(x => x.NumberOfDataPoints).HasColumnName("Num_Data_Pts");
builder.Entity<FoodWeight>().Property(x => x.StandardDeviation).HasColumnName("Std_Dev");

You can always add an extension method to EntityTypeBuilder, but this doesn't reduce the verbosity greatly:
modelBuilder
.Entity<FoodWeight>()
.Configure(
entity => entity.HasIndex(x => x.NutrientDatabankNumber),
entity => entity.Property(x => x.NutrientDatabankNumber).HasColumnName("NDB_No"),
entity => entity.Property(x => x.SequenceNumber).HasColumnName("Seq")
);
And the extension method:
public static class EntityTypeBuilderExtensions
{
public static void Configure<T>(this EntityTypeBuilder<T> modelBuilder, params Action<EntityTypeBuilder<T>>[] builders) where T : class
{
builders
.ToList()
.ForEach(builder => builder(modelBuilder));
}
}

Related

Entity Framework Linq2Db Translation

I am upgrading a website that used Entity Framework and now uses Linq2Db. I notice Linq2Db has no navigation properties. How would I translate this code from Entity Framework? I need to return an order with a list of order items, shipments, and other related objects. I am unable to query order items, shipments, and the other objects one by one.
IQueryable<Order> query = GetExpandedOrderTable();
DateTime beginTime = settings.LastDownloadUtc;
DateTime endTime = settings.LastDownloadUtcEnd;
query = query.Where(a => a.CreatedOnUtc >= beginTime);
query = query.Where(a => a.CreatedOnUtc <= endTime);
List<int> storeIds = GetStoreIds();
if (storeIds.Count() > 0)
query = query.Where(a => storeIds.Contains(a.StoreId));
return new PagedList<Order>(query, 0, 1000).ToList();
/// <summary>
/// Expands order items and other sub properties.
/// Increases performance.
/// </summary>
/// <returns></returns>
private IQueryable<Order> GetExpandedOrderTable()
{
return orderRepository.Table
.Include(a => a.OrderItems)
.Include("OrderItems.Product")
.Include(a => a.OrderNotes)
.Include(a => a.GiftCardUsageHistory)
.Include(a => a.BillingAddress)
.Include(a => a.BillingAddress.StateProvince)
.Include(a => a.BillingAddress.Country)
.Include(a => a.ShippingAddress)
.Include(a => a.ShippingAddress.StateProvince)
.Include(a => a.ShippingAddress.Country)
.Include(a => a.Customer)
.Include(a => a.DiscountUsageHistory)
.Include(a => a.Shipments);
}`
EF Navigation Property => linq2db Association
EF Eager Loading Include() => linq2db LoadWith()

SubQuery in ActiveRecord

i have following models in yii2:
use frontend\modules\bewerber\models\Bewerber;
use common\modules\basis\models\base\Person;
use common\modules\lookup\models\LAnrede;
How to create following query using methods of ActiveRecord?
SELECT anrede FROM L_anrede JOIN Person ON L_anrede.id=Person.id_anrede WHERE Person.id IN
(SELECT id_person FROM Bewerber WHERE Bewerber.id_person=1);
P.S.: The last WHERE clause should be not fix but variable like this:
var_dump(LAnrede::findOne([$model->id_person])->anrede)
which will put out following result:Mister or Miss
................................................................
Hint for Fabrizio Caldarelli
................................................................
Ur solution won't help me:=(
This is ur code:
$idPerson = 1;
$show=LAnrede::find()->joinWith(['Person' => function($q) use($idPerson) {
$q->andWhere([
'Person.id' => (new \yii\db\Query())->from('Bewerber')->where(['Bewerber.id_person' => $idPerson])
])->anrede;
}]);
and this is var_dump($show);
E:\xampp\htdocs\yii2_perswitch\frontend\modules\bewerber\views\bewerber\index.php:48:
object(common\modules\lookup\models\LAnredeQuery)[207]
public 'sql' => null
public 'on' => null
public 'joinWith' =>
array (size=1)
0 =>
array (size=3)
0 =>
array (size=1)
...
1 => boolean true
2 => string 'LEFT JOIN' (length=9)
public 'select' => null
public 'selectOption' => null
public 'distinct' => null
public 'from' => null
public 'groupBy' => null
public 'join' => null
public 'having' => null
public 'union' => null
public 'params' =>
array (size=0)
empty
private '_events' (yii\base\Component) =>
array (size=0)
empty
private '_behaviors' (yii\base\Component) =>
array (size=0)
empty
public 'where' => null
public 'limit' => null
public 'offset' => null
public 'orderBy' => null
public 'indexBy' => null
public 'emulateExecution' => boolean false
public 'modelClass' => string 'common\modules\lookup\models\LAnrede' (length=36)
public 'with' => null
public 'asArray' => null
public 'multiple' => null
public 'primaryModel' => null
public 'link' => null
public 'via' => null
public 'inverseOf' => null
I use Gridview like this
$gridColumn = [
[
'attribute' => '',
'label' => Yii::t('app', 'Anrede'),
'format' => 'html',
'value' => function($model) {
return "<p><font color='green'>" . LAnrede::findOne([$model->id_person])->anrede . "</p>";
}
],
];
Colud u show me up how to use ur solution in this context?
This should work:
$idPerson = 1;
LAnrede::find()->joinWith(['Person' => function($q) use($idPerson) {
$q->andWhere([
'Person.id' => (new \yii\db\Query())->from('Bewerber')->where(['Bewerber.id_person' => $idPerson])
]);
}])
->all();
'Person' is a relation in LAnrede model (one or many relation?)
public function getPerson()
{
return $this->hasMany(Person::className(), ['id_anrede' => 'id']);
}

Symfony Form Querybuilder with parameters

I have the need to create a dropdown field with grouped data:
My form:
class RetailerDetailFilterType extends AbstractType
{
public function getActiveRetailerMetrics(): array
{
return range(25,36);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('month', EntityType::class,
[
'class' => 'AppBundle:ConsolidatedOperatorCategoryLowData',
'query_builder' => function(ConsolidatedOperatorCategoryLowDataRepository $er){
return $er->getMinMaxByMetricQueryBuilder($this->getActiveRetailerMetrics());
}
]);
}
public function getBlockPrefix()
{
return 'key_metric';
}
}
My Repository:
class ConsolidatedOperatorCategoryLowDataRepository extends \Doctrine\ORM\EntityRepository
{
public function getMinMaxByMetricQueryBuilder($metricRange)
{
$qb = $this->getEntityManager()
->createQueryBuilder('d');
$qb
->select('d.id, YEAR(d.date) as dyear, MONTH(d.date) as dmonth')
->from('AppBundle:ConsolidatedOperatorCategoryLowData','d')
->where($qb->expr()->in('d.metric_id', $metricRange))
->groupBy('dyear')
->addGroupBy('dmonth')
->setMaxResults(10)
;
return $qb;
}
I'm getting
Warning: spl_object_hash() expects parameter 1 to be object, integer given
at UnitOfWork ->isScheduledForInsert (3182005)
in vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php at line 710 +
at EntityManager ->contains (3182005)
in vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php at line 116 +
at IdReader ->getIdValue (3182005)
at call_user_func (array(object(IdReader), 'getIdValue'), 3182005)
in vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php at line 205 +
at ArrayChoiceList ->flatten (array('id' => 3182005, 'dyear' => '2016', 'dmonth' => '12'), array(object(IdReader), 'getIdValue'), array(), array(), null)
in vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php at line 200 +
at ArrayChoiceList ->flatten (array(array('id' => 3182005, 'dyear' => '2016', 'dmonth' => '12'), array('id' => 3186685, 'dyear' => '2017', 'dmonth' => '1'), array('id' => 3191365, 'dyear' => '2017', 'dmonth' => '2'), array('id' => 3195595, 'dyear' => '2017', 'dmonth' => '3'), array('id' => 3200275, 'dyear' => '2017', 'dmonth' => '4')), array(object(IdReader), 'getIdValue'), array(), array(), array(null))
in vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php at line 91
I think it has to do with how Doctrine ORM deals with relationships. When you want to retrieve an entity by a referenced object's id, say find all posts by a user id, then you still have to pass the User-object to the QueryBuilder, not just the id. This is because Doctrine will resolve how those entities are connected itself.
It seems that metric_id actually is a reference to some kind of Metric-entity and just passing an array of int instead of the actual objects seems to trip up Doctrine's QueryBuilder.
You could try mapping the id's to a new instance of Metric and then pass that array instead.
Another solution - the one I would prefer - is to use Native SQL for this.

EF CodeFirst Mapping relationship between derived classes to the same table

I need to do the following mapping
OrderItem will map to tbl_order_item
OrderItemCustomization will map to tbl_order_item_customization
I have a column [cd_order_item] in tbl_order_item_customization which is the foreign key
The problem is how I map the relationship between
CardOrderItem -> CardOrderItemCustomization
CustomCardOrderItem -> CustomCardOrderItemCustomization
I tried this
public class OrderItemConfiguration : EntityTypeConfiguration<OrderItem>
{
public OrderItemConfiguration()
{
ToTable("tbl_order_item");
HasKey(i => i.Id);
Property(i => i.Id).HasColumnName("cd_order_items");
HasRequired(i => i.Order).WithMany(o => o.Items).Map(m => m.MapKey("cd_order"));
HasRequired(i => i.Product).WithMany().Map(m => m.MapKey("cd_product"));
Property(i => i.Quantity).HasColumnName("cd_quantity");
Property(i => i.UnitAmount).HasColumnName("vl_item").HasColumnType("money");
Property(i => i.TotalAmount).HasColumnName("vl_total").HasColumnType("money");
Property(i => i.DiscountAmount).HasColumnName("vl_discount");
Property(i => i.CostAmount).HasColumnName("vl_cost_price");
Property(i => i.NetAmount).HasColumnName("vl_net");
HasRequired(i => i.Status).WithMany().Map(m => m.MapKey("cd_status"));
Property(i => i.IsActive).HasColumnName("fl_active");
}
}
public class AbstractCardOrderItemConfiguration : EntityTypeConfiguration<AbstractCardOrderItem>
{
public AbstractCardOrderItemConfiguration()
{
Property(i => i.IsVirtual).HasColumnName("fl_virtual");
Property(i => i.CardType).HasColumnName("cd_card_type").IsOptional();
Property(i => i.Document).HasColumnName("nr_document");
HasRequired(i => i.Package).WithRequiredPrincipal().Map(m => m.MapKey("cd_order_item_base"));
}
}
public class CardOrderItemConfiguration : EntityTypeConfiguration<CardOrderItem>
{
public CardOrderItemConfiguration()
{
HasRequired(i => i.CardOrderItemCustomization).WithRequiredPrincipal().Map(m => m.MapKey("cd_order_items"));
}
}
public class CustomCardOrderItemConfiguration : EntityTypeConfiguration<CustomCardOrderItem>
{
public CustomCardOrderItemConfiguration()
{
HasRequired(i => i.CardWithCustomPhotoOrderItemCustomization).WithRequiredPrincipal().Map(m => m.MapKey("cd_order_items"));
}
}
But this gives me an error:
One or more validation errors were detected during model generation:
cd_order_items: Name: Each property name in a type must be unique.
Property name 'cd_order_items' is already defined.
There is any way that can I achieve the desired mapping?

ZF2 populate form collections element with child objects

Based on the Zend Framework 2 manual (here) I made a form like this:
class ParentForm extends Form
{
public function init()
{
$this->setName('parent_form')
->setAttribute('method', 'post')
->setHydrator(new ClassMethods(true))
->setInputFilter(new InputFilter());
$this->add(array(
'type' => 'Application\Form\Fieldset\Parent',
'name' => 'parent',
'options' => array(
'label' => 'Parent',
'use_as_base_fieldset' => true
)
));
$this->add(array(
'type' => 'Zend\Form\Element\Csrf',
'name' => 'csrf'
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Send'
)
));
}
}
And the 'parent' fieldset:
class ParentFieldset extends Fieldset
{
protected $count = 2;
public function init()
{
$this->setName('parent_fieldset')
->setHydrator(new ClassMethodsHydrator(false))
->setObject(new Model\Parent());
$this->add(array('type' => 'Element\MyField'));
$this->add(array(
'type' => 'collection',
'name' => 'children',
'options' => array(
'label' => 'Children',
'count' => $this->count,
'should_create_template' => true,
'allow_add' => true,
'target_element' => array(
'type' => 'Application\Form\Fieldset\Child',
'name' => 'child',
'options' => array(
'label' => child',
),
),
)
));
}
public function setCount($count)
{
$this->count = max($count, 2);
}
}
This works great to hydrate my Parent object with data obtained from my form. A var_dump of the resuting object will look like:
object(Parent)
public myField => foo
public children =>
array =>
0 => object(Child)
public field1 => value1
public field2 => value2
....
1 => object(Child)
.....
2 => object(Child)
.....
But I cannot figure out how to populate this multi-dimensional form with the above object if hydrated from the database (for editing purposes). How can I do that?
Note: the count property in the form is set to the same number of children as in the object.