Accessing a single field in a foreach using Linq Dapper - c#

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; }
}

Related

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!

list<T> - sql like statements for retrieving data

I have the following table
public class QTable
{
public string QID { get; set; }
public string QNO { get; set; }
public string Q1 { get; set; }
public string Q2 { get; set; }
public string opt1 { get; set; }
public string opt2 { get; set; }
public string opt3 { get; set; }
public string opt4 { get; set; }
public string Answer { get; set; }
public string Remarks { get; set; }
public string KnowledgeArea { get; set; }
public string Hints { get; set; }
public string Section { get; set; }
public string ToughLevel { get; set; }
public string DateCreated { get; set; }
public string Category { get; set; }
public string DeleteMe { get; set; }
}
QID is my primary key.
I have the
List<Qtable> qtableList = <list of all values of qtable from a query>
I need to find a particular QID and take other fields for manipulation.
Is there a SQL statement like structure to manipulate these things for a list?
You can use to get the item you want
Qtable item = qtableList.FirstOrDefault(x=>x.QID == id);
Just be aware that if the QID dont exists on the list and you try to access one of its properties, an 'Object reference is not an instance of an object exception' will be thrown, since you are trying to access a null object.
To prevent that, check if the return is differente of null prior to access and modify the properties you want.
In C# the best sql ike approach is just simply use linq, it's maded to handle this kind of request.
The basic syntax is:
var query = from qt in qtableList
where qt.QID == "1"
select qt;
This is basically returning the first pk element of your data.
Insert, update and other basic sql operations working as well.
More about on this:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/basic-linq-query-operations

Multiplicity constraint violated - Entity Framework

I'm having an issue when trying to save some data. What I'm trying to do is, I have Orders and I have an Order that has already been fulfilled and Paid. However, the Order Type is wrong and needs changed but in doing this it may mean VAT doesn't get added to the Order so an adjustment needs to be calculated to either give money to the Customer or have the Customer pay. So my idea was, when an Order Type is changed on an existing Paid Order, I create a copy of the Order, so another row in the SQL database (Orders table) with the same details, create copies of the Items (Items table) that were in the Order. However, the Order Type in the Orders table will be different. However, when I try to do this I'm getting the error
multiplicity constraint violated the role '_ target of the relationship has multiplicity 1 or 0..1
What happens is, the user opens the Order on screen, the Order details are retrieved from the Session and stored...
public void Save()
{
App_Order form;
List<App_Items> itemsInSession;
...
try
{
form = (App_Order)Session["Form" + id];
itemsInSession = (List<App_Items>)Session["FormDrugItems" + id];
}
// some validation is done
if(orderTypeChanged == true)
{
App_Order duplicateOrder = new App_Order();
duplicateOrder = CreateDuplicateOrderForm(form);
_orderService.SaveForm(duplicateOrder);
}
}
..
public App_Order CreateDuplicateOrderForm(App_Order form)
{
App_Order newForm = new App_Order()
{
OrderType = form.orderType,
OrderDate = form.orderDate,
CustomerId = form.customerId,
}
newForm.App_Items = new List<App_Items>();
foreach(App_Items orderItem in form.App_Item)
{
App_Items item = new App_Items()
{
ItemCode = orderItem.itemCode,
Quantity = orderItem.quantity,
Cost = orderItem.cost
};
newForm.App_Items.Add(item);
}
}
The Multiplicity Constraint Violation mentions App_Customer has a multiplicity. It would be a CustomerId from App_Customer that is stored in App_Order table in column CustomerId.
Any suggestions on what I'm doing wrong or what I can do to fix it?
Thanks in advance :)
App_Order:
public partial class App_Order
{
[ExcludeFromCodeCoverage]
public App_Order()
{
this.App_PharmacyFormDrugItem = new HashSet<App_PharmacyFormDrugItem>();
}
public int OrderId { get; set; }
public short OrderTypeId { get; set; }
public short OrderDate { get; set; }
public int CustomerId { get; set; }
public Nullable<int> CustomerId_Initial { get; set; }
public virtual Ref_OrderType Ref_OrderType { get; set; }
public virtual Ref_PaymentMonth Ref_PaymentMonth { get; set; }
public virtual App_Customer App_Customer { get; set; }
public virtual App_Customer App_Customer_Initial { get; set; }
public virtual ICollection<App_Item> App_Item { get; set; }
}
App_Customer:
public partial class App_Contract
{
public App_Contract()
{
this.App_CustomerAddress = new HashSet<App_CustomerAddress>();
this.App_CustomerContact = new HashSet<App_CustomerContact>();
}
public int CustomerId { get; set; }
public short CustomerTypeId { get; set; }
public short CustomerSubTypeId { get; set; }
public string Name { get; set; }
public virtual ICollection<App_CustomerAddress> App_CustomerAddress { get; set; }
public virtual ICollection<App_CustomerContact> App_CustomerContact{ get; set; }
public virtual Ref_CustomertSubType Ref_CustomerSubType { get; set; }
public virtual Ref_CustomerType Ref_CustomerType { get; set; }
public virtual ICollection<App_Order> App_Order{ get; set; }
public virtual ICollection<App_Order> App_Order1 { get; set; }
public virtual ICollection<App_Order> App_Order2 { get; set; }
}

Updating List<T> in DbContext

I have a Model like this
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<string> SolvedBy { get; set; }
}
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
}
and then Controller like this. But I cannot update the List "SolvedBy", the next time I step through with the debugger, the list is still empty.
[HttpPost]
public string Index(string flag = "", int id=0)
{
Challenge challenge = db.Challenges.Find(id);
if (flag == challenge.Flag)
{
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<string>();
}
chall.SolvedBy.Add(User.Identity.Name);
db.Entry(chall).State = EntityState.Modified;
db.SaveChanges();
//congrats, you solved the puzzle
return "got it";
}
else
{
return "fail";
}
}
is there any way around it to make a list of strings kept in the database?
EF don't know how to store an array in database table so it just ignore it. You can create another table/entity or use XML/JSON to store the list. You can serialize the list before saving and deserialize it after loading from database
A List<T> in a model would normally map to a second table, but in your DbContext you only have a single table. Try adding a second table.
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
public DbSet<Solution> Solutions {get; set;}
}
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<Solution> SolvedBy { get; set; }
}
public class Solution
{
public int ID { get; set; }
public string Name { get; set; }
}
Then your controller can use code along the lines of...
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<Solution>();
}
chall.SolvedBy.Add(new Solution {Name=User.Identity.Name});
None of the above has been tested and I may have made some mistakes there, but the general principle I want to illustrate is the fact that you need another table. The List<T> represents a JOIN in SQL.

Categories

Resources