with list of objects updating wrongly - c#

Here is the class
public class CartManage
{
public int prodId { get; set; }
// public string prodId { get; set; }
public int qty { get; set; }
public string color { get; set; }
public string size { get; set; }
public string Name { get; set; }
public string ShortDescription { get; set; }
public string Specification { get; set; }
public double Price { get; set; }
public string skew { get; set; }
public string weight { get; set; }
public string maxqty { get; set; }
public string productimage { get; set; }
public string prd_vendor_id { get; set; }
public string prdDeliveryDays { get; set; }
public bool GiftingEnabled { get; set; }
public int GiftingId { get; set; }
}
I use this to manage cart in my website i.e List < CartManage > prodList_temp. Now when a person increase the quantity of an item in cart. I add another object in the list(I used to just increase the quantity of the object but due to some functionality i have to implement i need separate objects). I did this by doing a linq query on the list and just adding the result to cart.
var session_updating_data = prodList_temp.Where(p => p.skew == reqired_skew);
prodList_temp.Add(session_updating_data.FirstOrDefault());
The problem im having is that after inserting when ever change anyting in one of the copies the changes are reflected in all the copies. for example i have two quantity of item A, i.e the cart contains two objects containing details of item a created as shown above. Now if I change the giftingEnabled property of any one of the objects it gets reflected in both. Now i found a work around for this by creating a new object. but i would like to know why this weird phenomenon is happening for future reference.

var session_updating_data = prodList_temp.Where(p => p.skew == reqired_skew);
prodList_temp.Add(session_updating_data.FirstOrDefault());
You are passing a reference to that object to your list, so any change in the object will be reflected everywhere. Where as when you create a new object, it's a separate instance.

Related

Entity Framework Core with undefined/dynamic columns

I have a db with some tables in which items contains some localized string. The plan is to have an ID to a dedicated "Localization" table.
public class User
{
public int Id {get; set; }
public string Name { get; set; }
public Localization Signature { get; set; }
}
public class Item
{
public int Id {get; set; }
...
public Localization Title { get; set; }
}
public class Localization
{
public int Id { get; set; }
public string En { get; set; }
public string Fr { get; set; }
public string De { get; set; }
}
This works. But the goal is now to have a "dynamic" list of languages, so we could easy extend the localization to other languages.
I can solve this with a JSON field in which I serialize the languages string, but it has the disadvantage to lose the readability in any DB Viewer. So if possible, I would like to have real columns.
Is there any way to solve this use case with EF Core ?
I'd approach this not by adding columns to the database (which requires a change to the DB structure) but by adding rows:
public class Item
{
public int Id {get; set; }
...
public string Title { get; set; }
}
public class Localization
{
public int Id { get; set; }
public int ItemId { get; set; }
public string LanguageCode { get; set; }
public string Text { get; set; }
}
Then load item's title along the lines of:
item.Title = context.Localizations
.Where(l => l.ItemId == item.Id && l.LanguageCode == "en")
.FirstOrDefault();
(You can also load Title in the same query where you load Item... that query is meant to be illustrative of the concept).

Automapper executes without error, but no data being copied from source to destination

I have a class like this
public class ListOfBMTTeamMapping
{
public class TeamMapping
{
public List<TeamMappings> results { get; set; }
}
public class TeamMappings
{
public int id { get; set; }
public string areaPath { get; set; }
public string agileReleaseTrainName { get; set; }
public string deliveryTeamName { get; set; }
public string keyedInTeamCode { get; set; }
public string deliveryTeamId { get; set; }
public bool isDeleted { get; set; }
public string modified { get; set; }
public string modifiedBy { get; set; }
}
}
And here is my model class to which I need the above API class to get copied
public class JsonBmtAdoMapping
{
public int? Id { get; set; }
public string AreaPath { get; set; }
public string AgileReleaseTrainName { get; set; }
public string DeliveryTeamName { get; set; }
public string KeyedInTeamCode { get; set; }
public string DeliveryTeamId { get; set; }
public string IsDeleted { get; set; }
public DateTime? Modified { get; set; }
public string ModifiedBy { get; set; }
}
So here is my code I tried
var format = "dd/MM/yyyy";
var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = format };
ListOfBMTTeamMapping.TeamMapping Results = new ListOfBMTTeamMapping.TeamMapping();
Results = JsonConvert.DeserializeObject<ListOfBMTTeamMapping.TeamMapping>(responseBody);
List<JsonBmtAdoMapping> jM = new List<JsonBmtAdoMapping>();
jM = _mapper.Map<ListOfBMTTeamMapping.TeamMapping,List<JsonBmtAdoMapping>>(Results);
int n = 10;
And here is my automapper profile
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>();
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
But when the code executes, Ofcourse I am getting the data in results variable without any trouble
But when the mapper code fires, it execute the line without any error, but no data being copied from source to my model class which is the destination
jM.count is always 0 when Results hold 124 rows of data
What I did wrong
Your mapping from TeamMapping to List<JsonBmtAdoMapping> can't be done out of the box by AutoMapper, because your source is an object with a property that contains the list and the destination is a list on itself.
So you have to tell him, how this conversion from a single object to a list can be done. Due to the fact, that you already have a mapping for each individual item, we can use that recursively within our mapping method.
By using this mapping, it should work:
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => src.results.Select(context.Mapper.Map<JsonBmtAdoMapping>).ToList());
Update
Cause a mapper is already defined for the individual items and lists are handled automatically by AutoMapper we can even make it shorter (thanks for Lucian for the hint in the comments):
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => context.Mapper.Map<List<JsonBmtAdoMapping>>(src.results));

How Do I Select an Object by Embedded Object Value 2 Levels Deep in C#?

I have an object that has an embedded list of objects, which itself has an embedded list of object, like so
namespace AppName.Models
{
[BindProperties]
public class WorkOrder
{
public string OrderNumber { get; set; }
public int FinishedGoodsToMake { get; set; }
public int Quantity { get; set; }
public List<FinishedGood> FinishedGoods { get; set; } = new List<FinishedGood>();
}
[BindProperties]
public class FinishedGood
{
public int ID { get; set; }
public string ProductCode { get; set; }
public List<RawMaterial> RawMaterials{ get; set; } = new List<RawMaterial>();
}
[BindProperties]
public class RawMaterial
{
public string ProductCode { get; set; }
public int Status { get; set; }
public string Description { get; set; }
}
}
In the RawMaterial object, the Status can have a value of 0, 1, 2 or 3. I need to process them grouped by this status. I think it would be easiest if I could just loop through statuses and select the object I need. So, let's say the work order has three FinishedGoods and each FinishedGood has four RawMaterials. I need to get a full WorkOrder object, with FinishedGoods and RawMaterials, only where RawMaterial.Status == 0. Is there any way to do this easily?
I could optionally map the object to iterate through each status also. Just looking for the easiest/ most elegant solution here. Thanks!

Accessing a single field in a foreach using Linq Dapper

I am using dapper and I want to use Linq to be able to update a single field called status in one table I am trying to use.
public async Task<Int32> ProcessUnprocessedTransactions(IEnumerable<BomComponentData> items)
{
IEnumerable<BomComponentData> _itemstoBeProcesed = items.Where(w => w.Status == (int)BomStatus.Scanned);
foreach (BomComponentData item in _itemstoBeProcesed)
{
item.Status = (int)BomStatus.Completed;
}
return await database.UpdateAsync(_itemstoBeProcesed);
}
My class is as follows:
public class BomComponentData
{
public int Sequence { get; set; }
public string BOMShortName { get; set; }
public string OperationName { get; set; }
public long BomId { get; set; }
public long BOMLineID { get; set; }
public long StockItemID { get; set; }
public string BomLineType { get; set; }
public int Quantity { get; set; }
public long UnitID { get; set; }
public decimal? MultipleOfBaseUnit { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
public long ProductGroupID { get; set; }
public string ProductGroupCode { get; set; }
public int Status { get; set; }
public int BinLocation { get; set; }
public string BinName { get; set; }
public string UOM { get; set; }
public int CalculatedValue { get; set; }
public int BomPickedCount { get; set; }
public int TotalLeftTopick
{
get { return Quantity - BomPickedCount; }
}
public enum BomStatus
{
Listed=1,
Scanned=2,
Confirmed=3,
Processed=4,
Completed=4,
InVisible=5
}
public override string ToString()
{
return Code;
}
}
But it does not work if I use a foreach like above. I am sure it should update the items properly but I think that because I'm going through singular items in my foreach and my list in the update it's not updating correct.
All I want to do is mark the items as completed and ready for transfer, I am doing so by the status column and an int enum.
Maybe I am missing a declaration of what is my primary key?
Edit 2
When I use a key declaration of the primary key I get the following:
Unhandled Exception: System.AggregateException: One or more errors occurred. (Constraint
Edit 3
I have set key of my class but as you see I have auotincrement on my db and it still crashes. How should insert be handled?
Edit 4
For example I am inserting into the database as follows. Shouldn't this work?
List<BomComponentData> _bomList = new List<BomComponentData>();
_bomList.Add(new BomComponentData { Sequence = 1, Barcode = "0000000001498", BinLocation = 23, BinName = "A", BOMShortName = "GYNE-TXX", OperationName = "Example Product", Code = "TB9175CEA", Name = "Tiburon Peri/Gynae Pack-10", Quantity = 1, UOM = "Each" });
await database.InsertAllAsync(_bomList,true);
I have placed the tag key for the update that works ok but when I attempt to do an insert with the key it doesn't it says constraint error but the update works. Does anybody no how i can solve both the insert and update in Dapper contrib.
You are using Dapper.Contrib and this extension requires that you decorate your class with some attributes to help in the automatic handling of your data.
In particular for an Update method you need to define the Table attribute and the Key attribute to identify the primary key
[Table ("BomComps")]
public class BomComponentData
{
// [ExplictKey]
[Key]
public int Sequence { get; set; }
....
Here, for example, I have added the attribute Table to set a possible table name on the database, but if the name of the physical table matches the name of the class then you can omit the attribute. Also I have added the Key attribute to set the property that contains the primary key of your table (so the statement that updates your records could be formed with the proper WHERE condition).
Notice that the Key attribute should be used if the column has an Identity property set to yes while, if not, you use the ExplicitKey attribute to signal that the primary key is defined by your code.
This was actually the issue I had to decoate my class with the following Leaving this here so that anyone else has issue I was using the pcl libary but for some reason dapper contribe did not detect the key element it had to be declared as follows.
[SQLite.PrimaryKey, SQLite.AutoIncrement]
public class StockTransferArgs
{
[SQLite.PrimaryKey, SQLite.AutoIncrement]
public int StockTransferArgsId { get; set; }
public long StockItemID { get; set; }
public string Code { get; set; }
public string OperationName { get; set; }
public string Description { get; set; }
public decimal Quantity { get; set; }
public long SourceWarehouseID { get; set; }
public string SourceBinName { get; set; }
public long TargetWarehouseID { get; set; }
public string TargetBinName { get; set; }
public string Reference { get; set; }
public string SecondReference { get; set; }
public string BarCode { get; set; }
public int Status { get; set; }
}

Assign item to list if CONTAINS

I have a list
public List<OrderLineItemQuestionPrice> QuestionPriceList { get; set; }
public class OrderLineItemQuestionPrice
{
public string DisplayName { get; set; }
public Price Price { get; set; }
public string QuestionCode { get; set; }
}
I have another list
List<OrderLineItemQuestionPrice> promotionItem;
and I want to assign items of QuestionPriceList to promotionItem if QuestionCode contains 'Promotion'.
List<OrderLineItemQuestionPrice> promotionItem = orderLineItemList.QuestionPriceList.Where(p=>p.QuestionCode.Contains("Promotion"))
One problem which I can see is that you don't calling ToList(); at the end. Also if you don't want to check for exact string Promotion you should call ToLower()
List<OrderLineItemQuestionPrice> promotionItem =
orderLineItemList.QuestionPriceList
.Where(p=>p.QuestionCode.ToLower().Contains("Promotion".ToLower()))
.ToList()

Categories

Resources