Dynamic Linq Library can’t handling duplicate alias column names - linq

I am trying to collect the data from database by using Dynamic Linq Library NeGet. When I loop through it showing this error ‘The item with identity 'FirstName' already exists in the metadata collection’
Seems like Dynamic Linq Library NuGet is can’t handle duplicate alias column names.
I have two tables and it has One-On-Many relationship as follow, containing the same Columns names in Lead table and CoBorrower table.
Table1: Lead
Columns: LeadID, FirstName,DateCreated
Table2: CoBorrower
Columns: LeadID, CoBorrowerID,FirstName,Tax,DateCreated
Here is my code snippet
var res = (from l in db.Leads
join db.CoBorrower.GetAll()
on l.LeadID equals cb.LeadID
select new { l, cb }).AsQueryable();
string myCustomCondition="FistName=myname";
IQueryable iq = res.Where(myCustomCondition)
.OrderBy(reportBulder.Group1)
.Select("new(l.LeadID,l.FirstName,cb.FistName)")
.GroupBy("LeadID", "it")
.Select("new (it.Key as Key, it as Value)");
foreach (dynamic group in iq)
{
string Key = group.Key.ToString();
List<dynamic> items = new List<dynamic>();
foreach (dynamic album in group.Value)
{
items.Add(album);
}
dataList.Add(Key, items);
}
I will appreciate your help in advance.

This is logical. The .Select("new(l.LeadID,l.FirstName,cb.FistName)") will create an anonymous object like:
new
{
LeadID = ....,
FirstName = ....,
FirstName = ....,
}
that is illegal (two properties with the same name)
Use the as
.Select("new(l.LeadID,l.FirstName,cb.FistName as FirstName2)")
so that the anonymous object created is
new
{
LeadID = ....,
FirstName = ....,
FirstName2 = ....,
}
as you do in the second .Select.

Related

Having trouble grouping columns in Linq query with multiple joins

I have an MVC ViewModel that I'd like to pass through to a Razor view. In the controller, I've created a database context and joined tables together using Linq. Once summed and grouped, I'm getting an error:
Error CS1061 'decimal' does not contain a definition for 'GroupBy' and no accessible extension method 'GroupBy' accepting a first argument of type 'decimal' could be found (are you missing a using directive or an assembly reference?
I've gone through almost every example on stack overflow and google and couldn't find an example that matched the structure of my query. Also, the MS examples are very trivial and are not of much use.
Here is the action in the controller:
public IHttpActionResult GetEmployeeReleasedAllocatedBonus(int eid)
{
var employeeReleasedAllocatedBonus =
(from br in _context.BonusReleases
join emp in _context.Employees
on new
{
br.EmployeeID,
empID = br.EmployeeID
} equals new
{
emp.EmployeeID,
empID = eid
}
join job in _context.Jobs on br.JobID equals job.JobID
join bonus in _context.Bonus
on new
{
br.JobID,
empID = br.EmployeeID
}
equals new
{
bonus.JobID,
empID = bonus.EmployeeID
}
select new EmployeeAllocatedReleasedBonusViewModel()
{
AllocatedToEmployee = br.Amount, AllocatedPercentage = bonus.Amount * 100
,
JobNumber = job.JobNumber, JobDescription = job.JobDescription
})
.ToList()
.Sum(s => s.AllocatedToEmployee)
.GroupBy(g => new {g.JobNumber, g.JobDescription, g.AllocatedPercentage});
return Ok(employeeReleasedAllocatedBonus);
}
It's worth mentioning that the AllocatedPercentage datatype is a decimal. However, I've tried changing it to string but the error message stays.
Also tried using the group functionality right before .ToList() but that didn't work either.
After ToList() you have a List<EmployeeAllocatedReleasedBonusViewModel>.
In Sum(s => s.AllocatedToEmployee), every s is one EmployeeAllocatedReleasedBonusViewModel. Apparently a EmployeeAllocatedReleasedBonusViewModel has a property AllocatedToEmployee which is probably of type decimal. This can be summed into one decimal.
The result of the Sum (a decimal) is the input of your GroupBy. Does type decimal have a method GroupBy? Of course it doesn't!
Alas you forgot to tell us your requirements. It is difficult to extract them from code that doesn't do what you want.
It seems to me that you have two one-to-many relations:
Employees have zero or more BonusReleases. Every BonusRelease belongs to exactly one Employee using foreign key
Jobs have zero or more BonusReleases. Every BonusRelease belongs to exactly one Job.
Now what do you want: do you want all JobNumbers and JobDescriptions of all Jobs with the total of their AllocatedPercentage? I'm not sure what the Employees do within this query.
Whenever you want items with their sub-items, like Schools with their Students, Customers with their Orders, Orders with their OrderLines, use GroupJoin. If you want it the other way round: Student with the School that he attends, Order with the Customer who placed the Order, use Join.
var result = dbContext.Jobs.GroupJoin(dbContext.BonusReleases,
job => job.Id, // from every Job take the primary key
bonusRelease => bonusReleas.JobId, // from every BonusRelease take the foreign key
// parameter ResultSelector: take every Job with all its BonusReleases to make a new:
(job, bonusReleasesOfThisJob) => new
{
JobNumber = job.JobNumber,
JobDescription = job.JobDescription
// do you want the total of all allocated percentages?
TotalAllocatedPercentages = bonusReleasesOfThisJob
.Select(bonus => bonus.Amount)
.Sum(),
// do something to make it a percentage
// or do you want a sequence of allocated percentages?
TotalAllocatedPercentages = bonusReleasesOfThisJob
.Select(bonus => bonus.Amount)
.ToList(),
});
Or do you want the JobNumber / JobDescription / Total allocated bonus per Employee?
var result = dbContext.Employees.GroupJoin(dbContext.BonusReleases,
employee => employee.Id, // from every Employee take the primary key
bonus => bonus.EmployeeId, // from every BonusRelease take the foreign key
(employee, bonusesOfThisEmployee) => new
{
// Employee properties:
EmployeeId = employee.Id,
EmpoyeeName = employee.Name,
// for the jobs: Join the bonusesOfThisEmployee with the Jobs:
Jobs = dbContext.Jobs.GroupJoin(bonusOfThisEmployee,
job => job.Id,
bonusOfThisEmployee => bonusOfThisEmployee.JobId,
(job, bonusesOfThisJob) => new
{
Number = job.Id,
Description = job.Description,
TotalBonus = bonusOfThisJob.Select(bonus => bonus.Amount).Sum(),
}),
});
Harald's comment was key - after ToList(), I had a list of . Therefore I took a step back and said what if I put the results into an anonymous object first. Then do the group by and then the sum, putting the final result into the view model. It worked. Here is the answer.
var employeeReleasedAllocatedBonus =
(from br in _context.BonusReleases
join emp in _context.Employees
on new
{
br.EmployeeID,
empID = br.EmployeeID
} equals new
{
emp.EmployeeID,
empID = eid
}
join job in _context.Jobs on br.JobID equals job.JobID
join bonus in _context.Bonus
on new
{
br.JobID,
empID = br.EmployeeID
}
equals new
{
bonus.JobID,
empID = bonus.EmployeeID
}
select new
{
AllocatedToEmployee = br.Amount
,AllocatedPercentage = bonus.Amount * 100
,JobNumber = job.JobNumber
,JobDescription = job.JobDescription
})
.GroupBy(g => new {g.JobNumber, g.JobDescription, g.AllocatedPercentage})
.Select(t => new EmployeeAllocatedReleasedBonusViewModel
{
JobNumber = t.Key.JobNumber,
JobDescription = t.Key.JobDescription,
AllocatedPercentage = t.Key.AllocatedPercentage,
AllocatedToEmployee = t.Sum(ae => ae.AllocatedToEmployee)
});

linq query with many-to-many relationship

Let’s assume I have three tables in my database:
Authors(PK Id, AuthorName)
Books(PK Id, BookName)
Authors_Books(FK BookId, FK AuthorId)
I need to write a method which passes in a parameter int[] authorsIds and returns all books (Id, BookName, list of authors of this book) if it was written by any author whose Id contains in int[] authorsIds parameter.
I need LINQ query (query method).
I really need a help. Appreciate your help very much.
var int[] authors = { 1, 2, 3 };
var books = from book in books
where book.Authors.Any(x => authors.Contains(x.AuthorId))
select book;
PS: I assume book.Authors is your reference to Authors_Books table (or maybe has a different name).
this answer is based on the exact structure without considering that A obj has B in its structure
var book = from b in books
where book.Id in ( from ab in AuthersBooks
where selectedAuthers.contains(ab.AutherId)
select ab.bookId ) //now we have books that are authered by one of the selected authers
select new { BookId = b.Id, // now we create an anonymos object to contain any info we need
BookName = b.Name,
BookAuthers = (from a in authers
join ab in AuthersBooks
on a.Id == ab.AuthersId
where ab.bookid == b.Id
select a)
this will propably have syntax errors and after correcting you may get an error about multiple threads which already has an answer here

Selecting last record by linq fails with "method not recognised"

i have following query to select the last record in the database
using (Entities ent = new Entities())
{
Loaction last = (from x in ent.Locations select x).Last();
Location add = new Location();
add.id = last.id+1;
//some more stuff
}
the following error is returned when calling the method containing these lines via "Direct event" on ext.net:
LINQ to Entities does not recognize the method 'Prototype.DataAccess.Location Last[Location]
(System.Linq.IQueryable`1[Prototype.DataAccess.Location])' method,
and this method cannot be translated into a store expression.
table structure is following:
int ident IDENTITY NOT NULL,
int id NOT NULL,
varchar(50) name NULL,
//some other varchar fields
Last is not supported by Linq to Entities. Do OrderByDescending (usually by ID or some date column) and select first. Something like:
Location last = (from l in ent.Locations
orderby l.ID descending
select l).First();
Or
Location last = ent.Locations.OrderByDescending(l => l.ID).First();
See MSDN article Supported and Unsupported LINQ Methods (LINQ to Entities) for reference.

Grouping in LINQ to Entity Model

I have following fields in entity model object
MONTH_CHAR char(1)
AVG_BALANCE int
PROD_CAT_ID int
FLG_PERS_COMM chat(1)
ACCOUNT_COUNT int
I want group by MONTH_CHAR column, I 'll write following SQL Query for this
SELECT MONTH_CHAR,
SUM(AVG_BALANCE) AS AVG_BALANCE,
MAX(PROD_CAT_ID) AS PROD_CAT_ID,
MAX(ACCOUNT_COUNT) AS ACCOUNT_COUNT,
FROM contactSummary
WHERE PROD_CAT_ID = 1
GROUP BY MONTH_CHAR
I want this query to be converted to LINQ Query.
Thanks in advance
from contact in context.Contacts
group contact by contact.Month_Char into g
select new
{
MonthChar = g.Key,
AvgBalance = g.Average(x=>x.Avg_Balance)
CatID = g.Max(x=>x.Prod_Cat_ID)
AccountCount = g.Max(x=>x.Account_Count)
}

Writing Group By on Anonymous Types

I am writting a group by clause on two tables which are joined and being accessed via Entity Data Model. I am not able to iterate over the anonymous type, can somebody help me out.
public string GetProductNameByProductId(int productId)
{
string prodName=string.Empty;
using (VODConnection vodObjectContext = new VODConnection())
{
var products = from bp in vodObjectContext.BFProducts
join bpf in vodObjectContext.BFProductMasters on bp.ProductMasterId equals bpf.ProductMasterId
where bp.ProductId == productId
group bp by new { ProductId = bp.ProductId, ProductName = bp.ProductName, ProductMasterName=bpf.ProductMasterName} into newInfo
select newInfo;
//Want to iterate over products or in fact need to get all the results. How can I do that? Want productmastername property to be set in prodName variable by iterating
return (prodName);
}
}
One problem is that you've used a query continuation for no reason. That still shouldn't have prevented you from using the Key property, mind you. Try this as a slightly cleaner approach:
var products = from bp in vodObjectContext.BFProducts
join bpf in vodObjectContext.BFProductMasters
on bp.ProductMasterId equals bpf.ProductMasterId
where bp.ProductId == productId
group bp by new { bp.ProductId,
bp.ProductName,
bpf.ProductMasterName};
foreach (var group in products)
{
var key = group.Key;
// Can now use key.ProductName, key.ProductMasterName etc.
}
As for what you set your prodName variable to - it's unclear exactly what you want. The first ProductName value? The last? A concatenation of all of them? Why do you need a grouping at all?
foreach(var prod in products)
{
prodName += prod.Key.ProductMasterName;
}

Resources