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?
Related
This is my first time posting here so please pardon my errors:
I have a search functionality whose route is:
Route::get('/search', 'SearchController#index');
Currently, I have an eloquent relationship where products has many deals. is it possible to return a single level deep array doing the following:
If the product has an active deal, return the deal only;
Otherwise, return the product itself.
here's what I earlier implemented in my Product.php:
public function deals()
{
return $this->hasMany(Deal::class, 'product_id');
}
Deal.php
public function product()
{
return $this->hasOne(Product::class, 'id', 'product_id');
}
SearchController:
public function index(Request $request)
{
$per_page = $request->per_page ?? 10;
$products = Product::query()->latest()
->when($request->query('filter'), function ($query) use ($request) {
$query->with('deals')->where('title', 'LIKE', "%$request->filter%");
})
->when($request->query('category'), function ($query) use ($request) {
$query->with('deals')->whereHas('categories', function ($q) use ($request) {
$q->where('title', 'LIKE', "%$request->category%");
});
})
->paginate($per_page);
return new PaginatedCollection($products, ProductResource::class);
}
and in my ProductResource:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
public function toArray($request)
{
$details = array_filter($this->details ?: [], function ($d) {
return $d != "";
});
$personalizedOptions = array_filter($this->personalized_options ?: [], function ($o) {
return $o != "";
});
return [
'id' => $this->id,
'createdAt' => $this->created_at,
'updatedAt' => $this->updated_at,
'title' => $this->title,
'sellerId' => $this->sellerId,
'description' => $this->description,
'categories' => CategoryResource::collection($this->categories),
'details' => $details,
'active' => (bool) $this->active,
'defaultPreviewImageId' => $this->default_preview_image_id,
'originalPrice' => $this->originalPrice,
'shippingPrice' => $this->shippingPrice,
'shippingWeightLbs' => $this->shippingWeightLbs,
'shippingWeightOz' => $this->shippingWeightOz,
'shippingMaxDays' => $this->shipping_max_days,
'shippingMinDays' => $this->shipping_min_days,
'personalized' => (bool) $this->personalized,
'personalizedOptions' => $personalizedOptions,
'deals' => $this->deals ?? null,
'options' => ProductOptionResource::collection($this->productOptions),
'images' => ImageResource::collection($this->images->whereNull('meta')),
'preview' => new ImageResource($this->images->where('meta', '=', 'preview')->first()),
];
}
}
Now, I have refactored the ProductResource to this but it's all returning null response
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
public function toArray($request)
{
$details = array_filter($this->details ?: [], function ($d) {
return $d != "";
});
$personalizedOptions = array_filter($this->personalized_options ?: [], function ($o) {
return $o != "";
});
if($this->deals){
DealResource::collection($this->deals);
}else{
return [
'id' => $this->id,
'createdAt' => $this->created_at,
'updatedAt' => $this->updated_at,
'title' => $this->title,
'sellerId' => $this->sellerId,
'description' => $this->description,
'categories' => CategoryResource::collection($this->categories),
'details' => $details,
'active' => (bool) $this->active,
'defaultPreviewImageId' => $this->default_preview_image_id,
'originalPrice' => $this->originalPrice,
'shippingPrice' => $this->shippingPrice,
'shippingWeightLbs' => $this->shippingWeightLbs,
'shippingWeightOz' => $this->shippingWeightOz,
'shippingMaxDays' => $this->shipping_max_days,
'shippingMinDays' => $this->shipping_min_days,
'personalized' => (bool) $this->personalized,
'personalizedOptions' => $personalizedOptions,
// 'deals' => $this->deals ?? null,
'options' => ProductOptionResource::collection($this->productOptions),
'images' => ImageResource::collection($this->images->whereNull('meta')),
'preview' => new ImageResource($this->images->where('meta', '=', 'preview')->first()),
];
}
}
}
The reason why it may be giving the null result because of the condition check. it is returning an array you need to update it to this.
if(count($this->deals))
this will check if the deal array contains an element in the array. if not it will return products.
Given the following code
class Program
{
static void AutoMap()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<PERSON, Pessoa>()
.ForMember(x => x.PessoaId, y => y.MapFrom(z => z.PERSON_ID))
.ForMember(x => x.PessoaName, y => y.MapFrom(z => z.PERSON_NAME))
.ForMember(x => x.Coisas, y => { y.MapFrom(z => z.ITEMs); y.ExplicitExpansion(); })
.ReverseMap()
.ForMember(x => x.ITEMs, y => { y.MapFrom(z => z.Coisas); y.ExplicitExpansion(); });
cfg.CreateMap<ITEM, Coisa>()
.ForMember(x => x.CoisaId, y => y.MapFrom(z => z.ITEM_ID))
.ForMember(x => x.CoisaName, y => y.MapFrom(z => z.ITEM_NAME))
.ForMember(x => x.Pessoa, y => { y.MapFrom(z => z.PERSON); y.ExplicitExpansion(); })
.ForMember(x => x.Propriedades, y => { y.MapFrom(z => z.PROPERTies); y.ExplicitExpansion(); })
.ReverseMap()
.ForMember(x => x.PERSON, y => { y.MapFrom(z => z.Pessoa); y.ExplicitExpansion(); })
.ForMember(x => x.PROPERTies, y => { y.MapFrom(z => z.Propriedades); y.ExplicitExpansion(); });
cfg.CreateMap<PROPERTY, Propriedade>()
.ForMember(x => x.PropriedadeId, y => y.MapFrom(z => z.PROPERTY_ID))
.ForMember(x => x.PropriedadeName, y => y.MapFrom(z => z.PROPERTY_NAME))
.ForMember(x => x.Coisa, y => { y.MapFrom(z => z.ITEM); y.ExplicitExpansion(); })
.ReverseMap()
.ForMember(x => x.ITEM, y => { y.MapFrom(z => z.Coisa); y.ExplicitExpansion(); });
});
}
static void Main(string[] args)
{
AutoMap();
RicardoDataContext context = new RicardoDataContext();
IQueryable<Pessoa> pessoas = context.PERSONs.ProjectTo<Pessoa>(x => x.Coisas);
foreach (Pessoa pessoa in pessoas)
{
Console.WriteLine(pessoa.PessoaId + ": " + pessoa.PessoaName);
if (pessoa.Coisas != null)
{
foreach (Coisa coisa in pessoa.Coisas)
{
Console.WriteLine("\t" + coisa.CoisaId + ": " + coisa.CoisaName);
if (coisa.Propriedades != null)
{
foreach (Propriedade propriedade in coisa.Propriedades)
{
Console.WriteLine("\t\t" + propriedade.PropriedadeId + ": " + propriedade.PropriedadeName);
}
}
}
}
}
return;
}
}
How can I invoke AutoMapper's ProjectTo() so that Propriedades (children of Coisas who in turn are the children of Pessoa) so that they are also expanded (and I will get them in the same SQL query such as right now with PERSON left outer join ITEM - would expect another left outer join on ITEM->PROPERTY)?
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));
}
}
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']);
}
I make a sample around the city, the city has areas, they have complexes, and apartment complexes. In the end, I need to get an apartment for a certain city, indicating the associated filters (district, complex, etc.). At the moment I did this:
public function actionIndex()
{
$cities = Cities::find()->where(['id' => Yii::$app->request->get('city_id')])->with([
'districts' => function ($query){
$query->filterWhere([
'id' => Yii::$app->request->get('district_id'),
]);
},
'districts.complexes' => function ($query) {
$query->filterWhere([
'id' => Yii::$app->request->get('complex_id'),
'type_id' => Yii::$app->request->get('complex_type_id'),
'developer_id' => Yii::$app->request->get('developer_id'),
]);
},
'districts.complexes.apartments' => function ($query) {
$query->filterWhere([
'amount_room' => Yii::$app->request->get('amount_room'),
'yardage' => Yii::$app->request->get('yardage'),
'level' => Yii::$app->request->get('level'),
'price' => Yii::$app->request->get('price'),
]);
},
])->all();
$query = [];
foreach ($cities as $city) {
foreach ($city->districts as $district) {
foreach ($district->complexes as $complex) {
foreach ($complex->apartments as $apartment) {
$query[] = $apartment;
}
}
}
}
return new ArrayDataProvider([
'allModels' => $query,
]);
}
But it looks kind of crooked, maybe I went the wrong way, and can I do it better?
UPD: I did almost like Yasin Patel.
$cities = Cities::find()
//->select('cities.id') // list your attributes comma saperated
->leftJoin('districts','cities.id=districts.city_id') // join districts table
->leftJoin('complex','districts.id=complex.district_id') // join complex table
->leftJoin('apartment','complex.id=apartment.complex_id') // join apartment table
->where(['cities.id' => Yii::$app->request->get('city_id')])
->andWhere(['cities.id' => Yii::$app->request->get('city_id')])
->filterWhere(['districts.id' => Yii::$app->request->get('district_id')])
->filterWhere(['complex.id' => Yii::$app->request->get('complex_id')])
->filterWhere(['complex.type_id' => Yii::$app->request->get('complex_type_id')])
->filterWhere(['complex.developer_id' => Yii::$app->request->get('developer_id')])
->filterWhere(['apartment.amount_room' => Yii::$app->request->get('amount_room')])
->filterWhere(['apartment.yardage' => Yii::$app->request->get('yardage')])
->filterWhere(['apartment.level' => Yii::$app->request->get('level')])
->filterWhere(['apartment.price' => Yii::$app->request->get('price')]);
return new ActiveDataProvider([
'query' => $cities,
]);
Returns:
[
{
"name":"City1",
"region":{
"id":7,
"name":"Region city1."
}
}
]
But how now to choose all the apartments found?
Try this query.
$cities = Cities::find()
->select('city.id') // list your attributes comma saperated
->leftJoin('districts','city.id=districts.city_id') // join districts table
->leftJoin('complexes','districts.id=complexes.districts_id') // join complexes table
->leftJoin('apartments','complexes.id=apartments.complexe_id') // join apartments table
->where(['id' => Yii::$app->request->get('city_id')])
->andWhere(['city.id' => Yii::$app->request->get('district_id')])
->andWhere(['districts.id' => Yii::$app->request->get('district_id')])
->andWhere(['complexes.id' => Yii::$app->request->get('complex_id')])
->andWhere(['complexes.type_id' => Yii::$app->request->get('complex_type_id')])
->andWhere(['complexes.developer_id' => Yii::$app->request->get('developer_id')])
->andWhere(['apartments.amount_room' => Yii::$app->request->get('amount_room')])
->andWhere(['apartments.yardage' => Yii::$app->request->get('yardage')])
->andWhere(['apartments.level' => Yii::$app->request->get('level')])
->andWhere(['apartments.price' => Yii::$app->request->get('price')])
->asArray();
Use your table name and attributes names as needed.
Than use this query in ArrayDataProvider.
return new ArrayDataProvider([
'allModels' => $query,
]);
This will return you records as array.
It turned out to optimize the code in this way::
public function actionIndex()
{
$query = Apartment::find()
->joinWith('complex')
->joinWith('complex.district')
->joinWith('complex.district.city')
->where(['cities.id' => Yii::$app->request->get('city_id')])
->filterWhere(['districts.id' => Yii::$app->request->get('district_id')])
->filterWhere(['complex.id' => Yii::$app->request->get('complex_id')])
->filterWhere(['complex.type_id' => Yii::$app->request->get('complex_type_id')])
->filterWhere(['complex.developer_id' => Yii::$app->request->get('developer_id')])
->filterWhere(['apartment.amount_room' => Yii::$app->request->get('amount_room')])
->filterWhere(['apartment.yardage' => Yii::$app->request->get('yardage')])
->filterWhere(['apartment.level' => Yii::$app->request->get('level')])
->filterWhere(['apartment.price' => Yii::$app->request->get('price')]);
return new ActiveDataProvider([
'query' => $query,
]);
}
Thanks to everyone for their help.