select all related objects - linq

I have a linq query where I'm trying to return all MlaArticles that are related to all other WebObjects but I'm getting the error: The specified type member 'RelatedWebObjectIds' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
Here's the Model...
public abstract class WebObject : IValidatableObject
{
public WebObject()
{
this.Id = Guid.NewGuid();
RelatedTags = new List<Tag>();
RelatedWebObjects = new List<WebObject>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public virtual ICollection<WebObject> RelatedWebObjects { get; set; }
public IList<Guid> RelatedWebObjectIds { get; set; }
}
Thanks for your help...
List<MlaArticle> assignedWebObjects = (from e in db.MlaArticles
where
(from w in db.WebObjects
from r in w.RelatedWebObjectIds
where w.Id == id
select r).Contains(e.Id)
select e).OrderBy(x => x.Title).ToList();
New query. Produces different error: WebObject does not contain a definition for 'Contains' and the best extension method overload ... has some invalid arguments.
List<MlaArticle> assignedWebObjects = (from e in db.MlaArticles
where
(from w in db.WebObjects
from r in w.RelatedWebObjects
where w.Id == id
select r.RelatedWebObjectIds).Contains(e.Id)
select e).OrderBy(x => x.Title).ToList();

Is there a RelatedWebObjects navigation property in your MlaArticle entity? If there is, you can do that instead:
List<MlaArticle> assignedWebObjects = (from e in db.MlaArticles
where
(from w in db.WebObjects
from r in w.RelatedWebObjects
where w.Id == id
select r.Id).Contains(e.Id)
select e).OrderBy(x => x.Title).ToList();

List<MlaArticle> assignedWebObjects = (from e in db.MlaArticles
where
(from w in db.WebObjects
from r in w.RelatedWebObjects
where w.Id == id
select r.RelatedWebObjectIds).Any(i => i == e.Id)
select e).OrderBy(x => x.Title).ToList();

Related

Left Join using LAMBDA to get Result in API

How to implement this Join which is in the code below into C# using LAMBDA
Select
VD.Id
, VD.BusinessAddress
, VD.BusinessDesc
, VD.BusinessEmail
, VD.BusinessName
, VD.BusinessZip
, VD.ContactPerson
, VD.ContactNo
, VD.ProfileUrl
, L.Name
, BC.BusinessCategory
from vendorDomain VD WITH(NOLOCK)
left Join Location L WITH(NOLOCK) ON VD.City = L.Id
left join Business_Category BC WITH(NOLOCK) ON VD.BusinessCategory = BC.BusinessId
where VD.IsDeleted = 0
I have to implement the join operation in the following API:
[HttpGet]
public async Task<IActionResult> Get()
{
var VendorList =await _vendorRepository.Query().Where(x => x.IsDeleted == false).ToListAsync();
return Ok(VendorList);
}
There are alot of examples out there but are way to confusing for a novice developer..
EDIT:
This is what I have tried as of now:
var employees = from vndr in context.vendorDomain
join C in context.Location on vndr.City equals C.Id into dep
from dept in dep.DefaultIfEmpty()
select new
{
vndr.BusinessAddress,
vndr.BusinessDesc,
vndr.BusinessEmail,
vndr.BusinessName,
vndr.BusinessWebsite,
vndr.BusinessZip,
vndr.ContactNo,
vndr.ContactPerson,
vndr.Created_At,
vndr.ProfileUrl,
vndr.Url,
dept.Name
};
We will do things first: do the joins and create a view model class that you will return. Because returning anonymous object and using dynamic does get messy.
ViewModel for the joined entities:
public class EmployeesViewModel
{
public string BusinessAddress { get; set; }
public string BusinessDesc { get; set; }
public string BusinessEmail { get; set; }
/* ....all remaining properties */
}
Then we join them properly and select them as an EmployeeViewModel:
var employees = from vndr in context.vendorDomain
join loc in context.Location on vndr.City equals loc.Id
join bus in context.Business_Category on vndr.BusinessCategory = bus.BusinessId
select new EmployeeViewModel
{
BusinessAddress = vndr.BusinessAddress,
BusinessDesc = vndr.BusinessDesc,
BusinessEmail = vndr.BusinessEmail,
/* ... remaining properties here*/
};
Or, if you want the method syntax:
var employees = context.vendorDomain
.Join(context.Location,
vndr => vndr.City,
loc => loc.Id,
(vndr, loc) => new { vndr, loc,})
.Join(context.Business_Category,
vndr_loc.vndr.BusinessCategory,
bus.BusinessId,
(vndr_loc, bus) => new {vndr_loc.vndr, vndr_loc.loc, bus})
.Select(x => new EmployeeViewModel{
BusinessAddress = vndr.BusinessAddress,
BusinessDesc = vndr.BusinessDesc,
BusinessEmail = vndr.BusinessEmail,
/* ... remaining properties here*/
});
As per your comment, you need to print the vendorList after the join. Now that is pretty vague, but I assume you want to submit both to your client / view, so again, we create a ViewModel class for it:
public class EmployeeVendorListViewModel
{
public VendorList VendorList { get; set; }
public EmployeeViewModel Employees { get; set; }
}
The last thing we do is glue it all together in your ActionMethod and return it:
[HttpGet]
public async Task<IActionResult> Get()
{
//renamed using a lower case "v"
var vendorList = await _vendorRepository.Query()
.Where(x => x.IsDeleted == false)
.ToListAsync();
//the join from earlier. You should put it in a repo somewhere, so it does not clutter your controller
var employees = from vndr in context.vendorDomain
join loc in context.Location on vndr.City equals loc.Id
join bus in context.Business_Category on vndr.BusinessCategory = bus.BusinessId
select new EmployeeViewModel
{
BusinessAddress = vndr.BusinessAddress,
BusinessDesc = vndr.BusinessDesc,
BusinessEmail = vndr.BusinessEmail,
/* ... remaining properties here*/
};
//create the final view model and return it
var vm = new EmployeeVendorListViewModel
{
VendorList = vendorList,
Employees = employees
}
return Ok(vm);
}
If you want to use NOLOCK in your query, you have to wrap it in a TransactionScope. This has already been answered here on StackOverflow: NOLOCK with Linq to SQL

LINQ Lazy load or query incorrect

LINQ Query not populating
Model extract is as follows
public class ServiceBulletin
{
[Key]
public int Id { get; set; }
public virtual ICollection<ServiceBulletinProducts> ApplicableProducts { get; set; }
}
public class ServiceBulletinProducts
{
[Key]
public int Id { get; set; }
public int ServiceBulletinId { get; set; }
public virtual Product Product{ get; set; }
}
I'm using the following code at the moment to populate a collection
var x = from m in _dc.ServiceBulletins.Include(p => p.ApplicableProducts)
.Include(m => m.Manufacturer)
where m.DeleteStatus == DeleteStatus.Active
select m;
var x1 = new List<ServiceBulletin>();
foreach (var item in x)
{
var p = from m1 in _dc.ServiceBulletinsProducts.Include(p2=>p2.Product)
where m1.Product.DeleteStatus == DeleteStatus.Active &&
m1.ServiceBulletinId == item.Id
select m1;
var p99 = p.ToList();
item.ApplicableProducts = p99;
x1.Add(item);
};
So this is intended to have a Parent Child relationship and I’m trying to do a query which populates a collection of ServiceBulletins with a ApplicableProducts item with a fully populated collection of ServiceBulletinProducts for the ServiceBulletin with the values of the Product populated
The collection is populated but the ServiceBulletinProducts are always set to null and I can’t seem to add an Include such as .Include(p => p.ApplicableProducts.Products) to try and populate the product details – which is resulting in me iterating around the collection to populate the items.
Am I missing something to enable the population on the 1st query for the Include statement or do I need to do the query in a different way ?
Figured out the following should do the trick.
var x = from m in _dc.ServiceBulletins.Include(p => p.ApplicableProducts.Select(p2=>p2.Product))
.Include(m => m.Manufacturer)
where m.DeleteStatus == DeleteStatus.Active
select m;

Linq query join table

I have a User table and a group table one user can be part of many groups
[USERID]----*-[USERID GROUPID]-*-----[GROUPID]
(join table)
public partial class user
{
public int user_id { get; set; }
public string name { get; set; }
public virtual ICollection<group> groups{ get; set; }
}
public partial class group
{
public int user_id { get; set; }
public string name { get; set; }
public virtual ICollection<user> users{ get; set; }
}
1) I need to return all the users that belongs to a specific group
var queryable = (from g in db.groups
where g.group_id == id
select g.users)
.ToList()
.Select(u => new {
id = u.id, //Error does not contain definition for id
name = u.name //Error does not contain definition for name
});
2) I need to return a specific user that belongs to a specific group
Thanks for your suggestions
I need to return all the users that belongs to a specific group
Lambda syntax:
db.groups.Where(g => g.group_id == id).SelectMany(g => g.users)
Or query syntax:
from g in db.groups
where g.group_id == id
from u in g.users
select u
I need to return a specific user that belongs to a specific group
Just like query above, with one additional filter
db.groups.Where(g => g.group_id == id)
.SelectMany(g => g.users)
.Where(u => u.id == userId)
Query syntax:
from g in db.groups
where g.group_id == id
from u in g.users
where u.id == userId
select u
Try something like this:
var queryable = (from p in db.plants
join u in db.users on p.userId equals u.id
where p.plant_id == plant_id
select u)
.ToList()
.Select(u => new {
id = u.id,
name = u.name
});
where p.userId is the column which connect plants and users tables
var queryable = (from p in db.plants
join u in db.users on p.userId equals u.id
where p.plant_id == plant_id
select new { p.id, p.name, u.name}).ToList();

LINQ to SQL MAX in WHERE clause

I am new to Linq so as expected I have encountered difficulties.
What I am trying to achieve is this:
SELECT id, name, password
FROM users u
WHERE u.id = (SELECT MAX(u1.id) FROM users u1);
My Linq is:
var dbUsers = from u in context.Users
where u.Id == (context.Users.Max(u1 => u1.Id))
select u;
But I always end with the following exception:
Unable to create a constant value of type 'Bla.Users'. Only primitive
types ('such as Int32, String, and Guid') are supported in this
context.
Here is the users class:
public class Users
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
}
}
Here is my context class:
public class EFDbContext : DbContext
{
public DbSet<User> Users{ get; set; }
}
You need to select the ID property
var dbUsers = from u in context.Users
where u.Id == (context.Users.Select(u1 => u1.Id).Max())
select u;
I usually do my LINQing in lambda format...
var dbUsers = DataContext.Users
.Where(u => u.Id == (DataContext.Users.Max(u1 => u1.Id)))
.Select(u => new
{
Id = u.Id,
Name = u.Name,
Password = u.Password
});
If you want the comprehension format...
var dbUsers = from u in DataContext.Users
where u.Id == (DataContext.Users.Max(u1 => u1.Id))
select new
{
Id = u.Id,
Name = u.Name,
Password = u.Password
};
Consider using a let statement:
var dbUsers = from u in context.Users
let int maxId = context.Users.Max(u1 => u1.Id)
where u.Id == maxId
select u;
Please let me know if this one solves your problem:
var dbUser = (from u in context.Users
orderby u.Id descending).FirstOrDefault()
You could use lambda expressions:
var dbUser = context.Users.First(u => u.Id== (context.Users.Select(u2
=> u2.Id).Max()));
or:
var dbUser = context.Users.OrderByDescending(u => u.Id).FirstOrDefault();

LINQ GroupBy month

I am having trouble getting an IQueryable list of a (subsonic) object grouped by Month and Year.
Basic view of the object...
public partial class DatabaseObject
{
[SubSonicPrimaryKey]
public int objectID { get; set; }
public string Description { get; set; }
public decimal Value { get; set; }
public string Category { get; set; }
public DateTime DateOccurred { get; set; }
}
Method to get IQueryable in my Database repository...
public IQueryable GetData(string DataType)
{
return (from t in db.All<DatabaseObject>()
orderby t.DateOccurred descending
select t)
.Where(e => e.Category == DataType);
}
My question is, how can I return the dates grouped by Month? I have tried the below, but this results in compiler warnings regarding anonymous types...
public IQueryable GetData(string DataType)
{
var datalist = (from t in db.All<FinancialTransaction>().Where(e => e.Category == DataType);
let m = new
{
month = t.DateOccurred.Month,
year = t.DateOccurred.Year
}
group t by m into l select new
{
Description = string.Format("{0}/{1}", l.Key.month, l.Key.year),
Value = l.Sum(v => v.Value), // Sum(v => v.Value),
Category = "Grouped"
DateOccurred = l.Last(v => v.DateOccurred)
}
return datalist;
}
Any ideas?
Try this couple issues i found, but you basically need to select a Database object versus anonymous type?
IQueryable<DatabaseObject> datalist = (
from t in db.All<FinancialTransaction>().Where(e => e.Category == DataType)
let m = new
{
month = t.DateOccurred.Month,
year = t.DateOccurred.Year
}
group t by m into l
select new DatabaseObject()
{
Description = string.Format("{0}/{1}", l.Key.month, l.Key.year),
Value = l.Sum(v => v.Value), //Sum(v => v.Value),
Category = "Grouped",
DateOccurred = l.Max(v => v.DateOccurred)
}).AsQueryable();
Let me know if my solution is now what you want. I also noticed you were using Last? The extension you were using I do not have so I replaced it with Max. I don't have subsonic installed so it might come with the libraries.
Any way don't combine LINQ in query syntax and LINQ in extension methods syntax. Use next:
from t in db.All<DatabaseObject>()
where e.Category equals DataType
orderby t.DateOccurred descending
select t;
The issue is apparantly to do with the way Subsonic interprests certain linq statements and is a known bug.
IEnumerable<DatabaseObject> datalist = (
from t in db.All<FinancialTransaction>().Where(e => e.Category == DataType).ToList()
let m = new
{
month = t.DateOccurred.Month,
year = t.DateOccurred.Year
}
group t by m into l
select new DatabaseObject()
{
Description = string.Format("{0}/{1}", l.Key.month, l.Key.year),
Value = l.Sum(v => v.Value), //Sum(v => v.Value),
Category = "Grouped",
DateOccurred = l.Max(v => v.DateOccurred)
}).AsQueryable();
I have fixed this by declaring an list of type IEnumerable and using ToList() to cast the database interaction, finally the query is then recast AsQueryable()

Resources