Replacing object id with coresponding name from other object - mysql

Im very new to angular so ill try to describe the problem as cleary as i can.
Im tring to make and single page app with some information about trading between people. AS for backend im using MySQL database + nodejs as a backed server and angular as frontend.
The problem is i have a person table with ID and a Name, Balance for each person.
Then i have a table where i store all the transactions between the people ( Id, Giver ID , Taker ID , Amount ).
At the frontend when i get the information about the transactions i get IDS of the giver and taker, but i want to replace them with the coresponding name from persons table / object.
I have clearly no idea how to manag this. I thought about looping trought the transactions objects and replace each ID in the array with a name.
Something like in this post
The Transaction object:
[Object]0: id: 1 giver_id: 1 taker_id: 5 amount: 50
Persons object:
[Object]0: balance:"-50" id:1 name:"Edgars"[Object]1: balance:"0" id:2 name:"Jānis"
So i want to replace the giver_id 1 with the name Edgars because as FK for giver id maches the persons id.
I dont want a clear answear but atleast a way to dig in.

My suggestion would be to handle the join between the two tables on the server side.
The UI will make one webservice call to get the transactions. The response should be an array of transactions and each transaction object should have the name of the giver and the taker.
You will need a SQL query to join the two tables. A simple join SQL would look like this.
select t.id as TRANS_ID, gp.name as GIVER, tp.name as TAKER, t.amount
from transaction t
join person gp on t.giver_id = gp.id
join person tp on t.taker_id = tp.id;
The JSON response to the UI would look like this:
[
{
"trans_id": 1,
"giver_name": "James",
"taker_name": "Michael",
"amount": 50
},
{
"trans_id": 2,
"giver_name": "Jim",
"taker_name": "Mike",
"amount": 100
}
]
This way, all of your logic would be on the server side and your UI only has to display the data.

You could map a new list from both lists:
var newList = transactionsList.map(function(t) {
var giver,taker;
giver = personList.find(function(p) {
return p.id == t.giver_id;
});
taker = personList.find(function(p) {
return p.id == t.taker_id;
});
if(giver && taker) {
t.giver_name = giver.name;
t.taker_name = taker.name;
return t;
}
else {
return undefined;
}
});
Or if you only need to this on one object:
function transformTransaction(t) {
var giver,taker;
var newTransaction = angular.copy(t);
giver = personList.find(function(p) {
return p.id == t.giver_id;
});
taker = personList.find(function(p) {
return p.id == t.taker_id;
});
if( giver && taker ) {
newTransaction.giver_name = giver.name;
newTransaction.taker_name = taker.name;
return newTransaction;
}
else {
return undefined;
}
}

Related

Query in asp.net core

I have a query table like this, people let me ask how can I get the Positions data of the current user when I get the userid to query with the Document table.
var claimsIdentity = _httpContextAccessor.HttpContext.User.Identity as ClaimsIdentity;
var userId = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier)?.Value.ToString();
var query = from c in _context.Documents
join u in _context.Users on c.UserID equals u.Id
join p in _context.Positions on u.Id equals p.UserID
where c.UserID.ToString() == userId
select new { c, u, p };
The data you query is almost enough, but it contains duplicate entries of Document and Position. If you want the final query to be put in a single object like this:
{
User = ...,
Documents = ...,
Positions = ...
}
You just need to project it using Linq-to-object (because all the data is loaded and ready for projection on the client):
var result = (from document in _context.Documents
join user in _context.Users on document.UserID equals user.Id
join position in _context.Positions on user.Id equals position.UserID
where document.UserID.ToString() == userId
select new { document, user, position }).AsEnumerable()
.GroupBy(e => e.user.Id)
.Select(g => new {
User = g.First().user,
Documents = g.GroupBy(e => e.document.Id)
.Select(e => e.First().document),
Positions = g.GroupBy(e => e.position.Id)
.Select(e => e.First().position)
}).FirstOrDefault();
If you don't want to fetch the user info, you don't need to join that DbSet but instead join the two Document and Position directly like this:
var result = (from document in _context.Documents
join position in _context.Positions on document.UserID equals position.UserID
where document.UserID.ToString() == userId
select new { document, position }).AsEnumerable()
.GroupBy(e => e.document.UserID)
.Select(g => new {
Documents = g.GroupBy(e => e.document.Id)
.Select(e => e.First().document),
Positions = g.GroupBy(e => e.position.Id)
.Select(e => e.First().position)
}).FirstOrDefault();
Note that I suppose your Document and Position both have its own primary key property of Id (adjust that to your actual design).
Finally, usually if your User entity type exposes navigation collection properties to the Document and Position. We can have a better (but equal) query like this:
var user = _context.Users
.Include(e => e.Documents)
.Include(e => e.Positions)
.FirstOrDefault(e => e.Id.ToString() == userId);
It's much simpler because all the joining internally translated by the EFCore. The magic is embedded right into the design of navigation collection properties.
I would like to talk about the important note of the condition UserID.ToString() == userId or Id.ToString() == userId. You should avoid that because it would be translated into a query that breaks the using of index for filtering. Instead try parsing for an int userId first (looks like it's a string in your case) and use that parsed int directly for comparison in the query, like this:
if(!int.TryParse(userId, out var intUserId)){
//return or throw exception
}
//here we have an user id of int, use it directly in your query
var user = _context.Users
.Include(e => e.Documents)
.Include(e => e.Positions)
.FirstOrDefault(e => e.Id == intUserId);
That applies similarly to other queries as well.

Convert complex nested selects in Entity Framework query

I need to create a table in View by this View Model:
public class ApplicationContentViewModel
{
public BPMSPARS.Models.MySql.application application {get; set;}
public BPMSPARS.Models.MySql.content content { get; set; }
public BPMSPARS.Models.MySql.app_delegation app_delegation { get; set; }
}
But the query for creating new Table is very complex.
I use this query in MySQL, and I can get correct results by using it.
SELECT APP_UID, (SELECT CON_VALUE FROM content WHERE CON_CATEGORY = 'PRO_TITLE' AND CON_ID =
(SELECT PRO_UID from app_delegation WHERE del_thread_status='open' and USR_UID = '00000000000000000000000000000001' AND APP_UID = '9134216305aaaea1b67c4e2096663219')) AS TASK_NAME,
(SELECT CON_VALUE FROM content WHERE CON_CATEGORY = 'TAS_TITLE' AND CON_ID =
(SELECT TAS_UID from app_delegation WHERE del_thread_status='open' and USR_UID = '00000000000000000000000000000001' AND APP_UID = '9134216305aaaea1b67c4e2096663219')) AS PROCESS_NAME FROM app_delegation
WHERE del_thread_status='open' and USR_UID = '00000000000000000000000000000001' AND APP_UID = '9134216305aaaea1b67c4e2096663219'
But, I have to convert this query in linq or EF in MVC.
How Can I write This Query in Entity Framework query?
And How Can I display results in View?
Your SQL query seems (very) peculiar to me, as it is quite redundant. I am going to assume the sub-queries return a single value and enforce it with LINQ.
First I pulled out the common sub-query over app_delegation:
var USR_APP_Delegation = from a in app_delegation
where a.del_thread_status == "open" &&
a.USR_UID == "00000000000000000000000000000001" &&
a.APP_UID == "9134216305aaaea1b67c4e2096663219"
select a;
In LINQ it is easy to combine the two UID queries into one query:
var UIDs = (from a in USR_APP_Delegation
select new { a.PRO_UID, a.TAS_UID })
.Single();
Now you can do the name subqueries:
var TASK_NAME = (from c in content
where c.CON_CATEGORY == "PRO_TITLE" &&
c.CON_ID == UIDs.PRO_UID
select c.CON_VALUE)
.Single();
var PROCESS_NAME = (from c in content
where c.CON_CATEGORY == "TAS_TITLE" &&
c.CON_ID == UIDs.TAS_UID
select c.CON_VALUE)
.Single();
Then you can put all the queries together for the final result:
var ans = (from a in USR_APP_Delegation
select new {
a.APP_UID,
TASK_NAME,
PROCESS_NAME
})
.Single();
Again, this makes it obvious that your e.g. returning APP_UID when you know exactly what it is, and you are combining TASK_NAME and PROCESS_NAME into a query for no real advantage.
I would suggest using join against content makes a much more understandable query (even in SQL) and makes it clearer what is being returned:
var names = from a in app_delegation
join cpro in content on new { CON_ID = a.PRO_UID, CON_CATEGORY = "PRO_TITLE" } equals new { cpro.CON_ID, cpro.CON_CATEGORY }
join ctas in content on new { CON_ID = a.PRO_UID, CON_CATEGORY = "TAS_TITLE" } equals new { ctas.CON_ID, ctas.CON_CATEGORY }
where a.del_thread_status == "open" &&
a.USR_UID == "00000000000000000000000000000001" &&
a.APP_UID == "9134216305aaaea1b67c4e2096663219"
select new {
a.APP_UID,
Task_Name = ctas.CON_VALUE,
Process_Name = cpro.CON_VALUE
};

(Laravel) Join 3 or more tables using "Eloquent Relationships"

I'm trying to join 3 tables using eloquent relationships, but it doesn't give the expected results.
Shipment model
class Shipment extends Model
{
protected $table = 'ccctadm.Shipment';
public function customergroupcode()
{
return $this->hasMany(DocumentRuleSet::class,'customergroupcode','customergroupcode');
}
public function shipmentcategory()
{
return $this->hasMany(DocumentRuleSet::class,'shipmentcategory','shipmentcategory');
}
public function status()
{
return $this->hasMany(DocumentRuleSet::class,'status','status');
}
}
to get the data i'm using this code
$shipment_data = Shipment::With(['customergroupcode' , 'shipmentcategory','status'])->
Where('shipment_cycle','!=','closed')->get();
I'm trying to make it equivalent to this query
select B.rulesetname,B.icon ,COUNT(*)As Total from
[ccct].[ccctadm]. [Shipment] A INNER JOIN
[ccct].[ccctadm].[documentruleset] B
ON
A.customergroupcode = B.customergroupcode AND A.shipmentcategory =
B.shipmentcategory AND A.status = B.status INNER
JOIN [ccctadm].[shipassign] S ON A.id = S.shipmentid AND
A.shipment_cycle != 'closed' GROUP BY rulesetname,B.icon
The first query returns all the data in 3 tables, but when the second one returns Release only and this what I want
I only want the data that has relation among these three tables not everything
What I'm doing wrong ?
Use has() method. It limits the records based on existence of the relationship.
$shipment_data = Shipment::has('customergroupcode' , 'shipmentcategory','status')->
Where('shipment_cycle','!=','closed')->get();

How to retrieve data from two tables using join in Simple OData Client?

I'm using mvc application and simple OData to retrieve values from two tables.
created object of ODataClient
ODataClient client = new ODataClient("http://localhost:65556/Dev");
Want to retrieve value from two table like in Sql we simply do like following
select * from [Table1] t1 join [Table2] t2
on t1.Id = t2.Id
where t1.[Title] = 'US'
Now In SimpleOdata I do not know about two table operation for one table we can simply do something like following
ODataClient client = new ODataClient("http://localhost:64576/Dev");
var packages = await client
.For<Table1>()
.Filter(x => x.Title == "US")
.FindEntriesAsync();
foreach (var package in packages)
{
return package.Title;
}
return "test";
How can I correct above expression for two tables?
I suppose you should use expand function. Look here http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/using-$select,-$expand,-and-$value
ODataClient client = new ODataClient("http://localhost:64576/Dev");
var packages = await client
.For<Table1>()
.Expand(x => x. Table2)
.Filter(x => x.Title == "US")
.FindEntriesAsync();
foreach (var package in packages)
{
return package.Title;
}
return "test";

Join and Union with Entity Framework

I have two tables (clients and emails), one with customer's data, including a main email address, and another one with additional email addresses.
I need to validate the user from one of their many email addresses, no matter if it is on clients or emails table. I've come up with this SQL sentence which works fine:
set #email = 'client#domain.com';
select c1.credits > 0 as Allowed, c1.Email as MainEmail from
customers c1 inner join (select ClientId, Email FROM customers WHERE
Email=#email union all select ClientId, Email FROM emails WHERE Email=#email) e1
on c1.ClientId = e1.ClientId;
How to write this query in LINQ to Entities with method-based syntax?
If i understand correctly,
Customer may or may not have the email (Additional) in emails table.
Also, Customer have more than one additional emails entry in emails table. Like below
List<Customer> customers = new List<Customer>
{
new Customer { ClientId = 1, Email = "client1#domain.com", Credits = 2 },
new Customer { ClientId = 2, Email = "client2#domain.com", Credits = 1 },
new Customer { ClientId = 3, Email = "client3#domain.com", Credits = 1 },
};
List<Emails> emails = new List<Emails>
{
new Emails { ClientId = 1, Email = "client1-2#domain.com" },
new Emails { ClientId = 1, Email = "client1-3#domain.com" },
new Emails { ClientId = 2, Email = "client2-1#domain.com" },
};
In that case, Use the below query to get it done,
var result = from c in customers
let _emails = emails.Where(e => c.ClientId == e.ClientId).Select(t => t.Email)
where c.Email == "client3#domain.com" || _emails.Contains("client3#domain.com")
select new
{
Allowed = c.Credits > 0,
MainEmail = c.Email
};
I hope it helps you.