mvc3 best way to convert anonymous type to an ienumerable - asp.net-mvc-3

I have a model that uses an IEnumerable to return multiple rows using a foreach statement in the view. The issue is that I am using a Join because I need data from 2 different tables which turns the ienumerable into an anonymous type and is causing errors; whats the best way I can fix this?
var Ieposts = (from t in db.Threadposts join p in db.profiles on t.profileID equals p.profileID where t.threadID == id select new
{
firstname = p.firstname,
lastname = p.lastname,
articles = p.articlecount,
city = p.city,
state = p.state,
post = t.post
}).ToList();
I am only getting out the fields that I need because that increases database performance. Any suggestions would be great

I think you really need to learn a bit more about Entity Framework and Linq in general.
Joins do not create anonymous types, nor is there any problem with getting an enumerable from an anonymous type. Just call .AsEnumerable() from the query.
However, I suspect this is not what you're trying to do. What you actually want is a concrete return type. In That case, you probably want to create a type for this:
public class IEPost {
public string FirstName {get;set;}
public string LastName {get;set;}
public int Articles {get;set;}
public string City {get;set;}
public string State {get;set:}
public Post Post {get;set;}
}
Then you create your query like so (note the "new IEPost" part):
var Ieposts = (from t in db.Threadposts
join p in db.profiles on t.profileID equals p.profileID
where t.threadID == id select new IEPost
{
FirstName = p.firstname,
LastName = p.lastname,
Articles = p.articlecount,
City = p.city,
State = p.state,
Post = t.post
}).ToList();

Related

Can I declare a function inside a LINQ select clause?

I'm studying for MS Exam 70-483 (C#) and this idea occurred to me.
Is it possible to do something like this:
class Person
{
public string Name { get; set; }
public int CityId { get; set; }
}
class City
{
public string Name { get; set; }
public int Id { get; set; }
}
/* assume code to populate List people and List cities */
var personsByCity = from p in people join c in cities
on p.CityId equals c.Id
select new { PersonName = p.Name, CityName = c.Name,
ToString = Func<string>( () => { return PersonName + "/" +
CityName; })};
The compiler error that occurs is "[CS0119] Expression denotes a type' where avariable' or `method group' was expected.
Resharper is a bit clearer: Delegate name is not valid at this point (i.e. where Func occurs).
So, is there a way to accomplish adding a function to an anonymous type in a LINQ query?
Yes, you can declare a function, but you can't define it to return a property of the anonymous type that is currently being declared-- if you were to use this, for example, the lambda would capture the value of this in the declaring context (the class that contains the code that is executing the LINQ). You can however capture the values that are being used to initialize the anonymous class (as I do in the example below).
Note that this is not the same as giving the anonymous class a method. Anonymous classes can only have read-only, immutable properties. In this case, your anonymous class will still have the original ToString() method inherited from object. This may make it tricky to distinguish the function held in the ToString property from the ToString() method, so maybe you should use a different name.
Also, you forgot the new keyword before Func.
var personsByCity = from p in people join c in cities on p.CityId equals c.Id
select new
{
PersonName = p.Name,
CityName = c.Name,
ToString = new Func<string>( () => {
return c.Name + "/" + p.Name;
})
};

Realm Xamarin LINQ Object

What is the correct way to query Realm with LINQ where the query includes fields from other Realm objects? For example:
public class Department : RealmObject
{
[Primary Key]
public string UniqueId { get; set; }
}
public class Employee : RealmObject
{
[Primary Key]
public string Name { get; set; }
// Parent
public Department Department { get; set; }
}
Then I would expect to be able to do something like:
var employee = realm.All<Employee>().SingleOrDefault( e => e.Department.UniqueId == fooId && e.Name == fooName );
But this always returns no matches. Where() also returns no matches. However, eliminating the e.Department and searching only on employee name works fine but obviously does not scope to Department as intended.
This is with the latest Realm Xamarin 0.80.
What am I doing wrong?
Querying by nested RealmObjects attributes is not currently supported:
Just to clarify here, we don't yet support queries on related objects like this. We will in the future, but there is no timeline at the moment.
The following is also not currently supported:
var deptFilter = theRealm.ObjectForPrimaryKey<Department>("HR");
var employeesByDept = theRealm.All<Employee>().Where((Employee emp) => emp.Department == deptFilter & emp.Name == "StackOverflow");
The left-hand side of the And operator must be a direct access to a persisted property in Realm.
Unable to process '(emp.Department == value(Realm080.App+c__AnonStorey1).deptFilter)'.
You can do direct RealmObject equalities, just not in the same Linq expression, so break it down further into a sub-query.
Example of how I currently do it:
var deptFilter = theRealm.ObjectForPrimaryKey<Department>("HR");
var employeesByDept = theRealm.All<Employee>().Where((Employee emp) => emp.Department == deptFilter);
var employees = employeesByDept.Where((Employee emp) => emp.Name == "StackOverflow");
foreach (var emp in employees)
{
D.WriteLine(emp.Name);
}
Note: https://github.com/realm/realm-dotnet/issues/723

Linq Group by, Concatenate and load child entities on a list

I'm going to simplify a little bit my model in order to show what I want to do. I know perfectly how do that using SQLbut I'm having problems with EF and LINQ.
Sorry for the long post.
I have the next POCO's:
public class Order
{
public int Id {get; set;}
public double Quantity {get; set;}
public List<Status> StatusChanges{get; set;}
}
public class Status
{
public int Id {get; set;}
public DateTime StatusDate {get; set;}
public StatusType StatusType {get; set;}
}
public class StatusType
{
public int Id {get; set;}
public string Code {get; set;}
public string Description {get; get;}
}
An Order have multiple Status and one Status have only one StatusType
My questions:
1) How to select in a LINQ query a list containg all the orders with the loaded StatusType
I try with
var results= (from o in db.Orders
select new {o.Id,o.Quantity,o.StatusChanges})
.Include(o=>o.StatusChanges.Select(s=>s.StatusType));
But that's not that I want, I want a list which contains, Order, Status and StatusType (even if the Order info is repetead) I know I can make a double foreach but I would like to know if is a single query way (or a double query one to the db and another using linq to entities)
2) How make a list which contains the Order Id and the Codes of all the status concatenated. Example
Orders:
Id Quantity
1 2
Status
Id StatusDate StatusTypeId
1 01-10-2014 1
2 02-10-2014 2
StatusType
Id Code Description
1 E Entered
2 C Confirmed
3 D Deleted
Result:
OrderId Quantity StatusResume
1 2 E,C
I know I can use this question but I don't know how have access to the loaded elements in the list.
The first one from Ilija Dimov's answer should work. The second one is a little bit more tricky, because Aggregate extension method is not supported by LINQ to Entities. That's why you have to download necessary data to memory and perform string concatenation in-memory as LINQ to Objects query.
var results = (from o in db.Orders
select new
{
o.Id,
o.Quantity,
o.StatusCodes.Select(c => c.StatusType.Code)
}).AsEnumerable()
.Select(x => new {
x.Id,
x.Quantity,
StatusResume = string.Join(',', x.StatusCodes)
}).ToList();
}).ToList();
Try the following queries:
1) How to select in a LINQ query a list containg all the orders with the loaded StatusType
var results = (from o in db.Orders
from s in o.StatusChanges
select new
{
OrderId = o.Id,
Quantity = o.Quantity,
StatusId = s.Id,
StatusDate = s.StatusDate,
StatusCode = s.StatusType != null ? s.StatusType.Code : null
}).ToList();
2) How make a list which contains the Order Id and the Codes of all the status concatenated
var results = (from o in db.Orders
select new
{
o.Id,
o.Quantity,
StatusCodes =
o.StatusChanges.Where(c => c.StatusType != null).Select(c => c.StatusType.Code)
}).ToList().Select(x => new
{
x.Id,
x.Quantity,
StatusResume = string.Join(",", x.StatusCodes)
}).ToList();

Join LINQ queries from multiple contexts

I am trying to create a ViewModel for data that I want to display in my view. The issue is, the data being displayed is spread across 2 databases and multiple tables within each. I've read that you cannot join Linq queries across multiple contexts, which makes sense, and I've also read that we can't use Code-First in EF5 to use Stored Procedures....which led me to using 3 different Linq queries and attempt to combine them into 1 ViewModel...I'm just not sure how to get there.
Here's my Linq queries:
var csdContext = new CSDContext(CustomerCode);
var masterContext = new MasterContext();
//Only returns 1 row - which is what we want.
List<Site> sites = (from s in csdContext.Sites
join sa in csdContext.SiteAddresses
on s.SiteID equals sa.SiteID
join a in csdContext.Addresses
on sa.AddressID equals a.AddressID
join spv in csdContext.SiteProductVersions
on s.SiteID equals spv.ProductVersionID
where s.SiteID == id
select s).ToList();
//List
List<States> states = (from s in masterContext.StatesTable
select s).ToList();
My ViewModel looks like this:
public class SiteDetailsViewModel
{
public string Address { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string StateCode { get; set; }
public string ZipCode { get; set; }
public string OfficePhone { get; set; }
public string MobilePhone { get; set; }
public string AlternativePhone { get; set; }
public int ProductVersionID { get; set; }
}
Basically, I need the following data from these tables:
csdContext - Address
Address
Address2
City
ZipCode
csdContext - Sites
OfficePhone
MobilePhone
AlternativePhone
csdContext - SiteProductVersions
ProductVersionID
masterContext - States
StateCode
Here's how the tables are joined in SQL:
SELECT csd_a.Address, csd_a.Address2, csd_a.City, mstr_st.StateCode, csd_a.ZipCode, csd_s.OfficePhone, csd_s.MobilePhone,
csd_s.AlternativePhone, csd_spv.ProductVersionID
FROM CSD.dbo.Sites AS csd_s
INNER JOIN CSD.dbo.SiteAddress AS csd_sa ON csd_sa.SiteID = csd_s.SiteID
INNER JOIN CSD.dbo.Address AS csd_a ON csd_a.AddressID = csd_sa.AddressID
INNER JOIN CSD.dbo.SiteProductVersions AS csd_spv ON csd_s.SiteID = csd_spv.SiteID
INNER JOIN MasterDB.dbo.States AS mstr_st ON mstr_st.StateID = csd_a.StateID
I can't figure out how to merge these 3 results to create the ViewModel data for SiteDetailsViewModel. Can anyone help?
If you materialize your queries as described in OP you can use this:
var query = sites.Join(
states,
si => si.StateID,
st => st.StateID,
(si, st) => new SiteDetailsViewModel
{
Address = si.Address,
Address2 = si.Address2,
City = si.City,
StateCode = st.StateCode,
ZipCode = si.ZipCode,
OfficePhone = si.OfficePhone,
MobilePhone = si.MobilePhone,
AlternativePhone = si.AlternativePhone,
ProductVersionID = siProductVersionID
});
One possible alternate solution is to create views in DB #2 of the tables in DB #1. Then you can model/map those views in EF for DB #2. You would of course still need a context for DB #1 if you need to update any of the tables. But the benefit of this solution is that you can do all of your read access on a single context and get joins at the server instead of in memory.
So why don't you write it like this:
from ...
...
where s.SiteID == id
select new SiteDetailsViewModel()
{
Address = sa.Address,
Address2 = as.Address2,
..
}

How can I pass any id to a linq join in [HttpGet] ActionResult for Edit

I am making a web application on MVC3, and I am using linq to communicate with the database.
I made a checkboxlist, where a user can select some options according to their choice and it gets saved in the databse table. The problem is in the Edit part.
The whole scenario is something like this:
The user can register as a restaurant owner or a Motel owner, I have assigned different Business_Type_Id as 1 and 2 for differentiating these two, I have assigned '2' for the Restaurant Business Type, and mapped the cuisines with the perticular business type in the same "Cuisines" table, by adding the "BusinessType" column into the table. the user will be assigned a Business_Id for their Business. I am providing a checkboxlist which generates its options from the database table "Cuisines" where I have given the cuisine list. From the front end the user can choose multiple cuisines according to their chioce what ever they provide in their restaurant. The choices may vary from one restaurant owner to the other, so I am storing the selected values for each and every Restaurant owner in a "BusinessCuisinesMapping" table, where I map the perticular BusinessId with the selected CuisineId by that perticular user.
Now to populate that cuisine list for edit or update I wrote a linq join, but I need to compare it with the Business_Id which is passed to the [HttpGet] ActionResult Edit. And this is point where I got stuck.
This is my linq join code which I am using in the controller:
[HttpGet]
public ActionResult Edit(int id)
{
using (var chkl = new BusinessEntities())
{
var data = (from CuisinesData in chkl.Cuisines
join BusinessCuisineMappingData in chkl.BusinessCuisineMapping
on new { CuisinesData.Id, id } equals new { BusinessCuisineMappingData.CuisinesId, BusinessCuisineMappingData.BusinessId }
where CuisinesData.BusinessTypeId == 2
select new CusinesDTO
{
Id = CuisinesData.Id,
Name = CuisinesData.Name,
IsSelected = BusinessCuisineMappingData.CuisinesId == null ? false : true
}).Distinct().ToList();
ViewBag.CuisineList = data;
}
return View();
}
This is my DTO class:
public class CusinesDTO
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
I want to comape the "id" with the "BusinessCuisineMappingData.BusinessId" field in my LINQ join, which I am getting through the [HttpGet] Actionresult Edit(int id). It prompts me an error while I try to implement it.
You cannot use a local variable in the join. However, you can use it in a Where clause. So if you do
join ...
on CuisinesData.Id equals BusinessCuisineMappingData.CuisinesId
...
where BusinessCuisineMappingData.BusinessId == id
you'll have the same effect.
"The type of the expressions in join clause is incorrect. Type inference failed in the call to 'Join'"
This suggests the types on either side of your JOIN are not equal. You are getting a compiler error; should be relatively easy to check the types on either side of your JOIN clause.
edit: rereading what you have put, I think something like the below is what you want to do:
[HttpGet]
public ActionResult Edit(int id)
{
using (var chkl = new BusinessEntities())
{
var data = (from CuisinesData in chkl.Cuisines
join BusinessCuisineMappingData in chkl.BusinessCuisineMapping
on CuisinesData.Id equals BusinessCuisineMappingData.CuisinesId
where CuisinesData.BusinessTypeId == id
select new CusinesDTO
{
Id = CuisinesData.Id,
Name = CuisinesData.Name,
IsSelected = BusinessCuisineMappingData.CuisinesId == null ? false : true
}).Distinct().ToList();
ViewBag.CuisineList = data;
}
return View();
}

Resources