LINQ to Entities Special Database Query not working - c#

I have a database with two tables (UserData) and (UserDetails). I use the LINQtoEntities.
The issue here is that in the LINQ query is not accepted:
Details = c.ToList<UserDetails>()
Error is:
Instance argument: cannot convert from 'System.Collections.Generic.IEnumerable<mynamespace.UserDetails>' to 'System.Collections.Generic.IEnumerable<System.Collections.IEnumerable>'
public class UserData
{
public int Index{ get; set; }
public string Name{ get; set; }
public string PersonalNo { get; set; }
public <List<UserDetails>> Details { get; set; }
}
public struct UserDetails
{
public int Age;
public string profession;
public string gender;
}
public IEnumerable<Userdata> GetUserData()
{
var context = new DatabaseEntities();
var Results =
from a in context.UserData
join b in context.UserDetails on a.Index equals b.Index into c
select new UserData{ Index = a.Index, Name = a.Name, PersonalNo = a.PersonalNo,
Details= c.ToList<UserDetails>() };
return Results;
}
Is there anybody who can help me out. In case more infos needed, please ask.
Thanks.

The following example is working. To get it working you can use object. See below the example:
public class UserData
{
public int Index{ get; set; }
public string Name{ get; set; }
public string PersonalNo { get; set; }
public List<object> Details { get; set; }
}
public class UserDetails
{
public int Age;
public string profession;
public string gender;
}
public IEnumerable<Userdata> GetUserData()
{
var context = new DatabaseEntities();
var Results =
from a in context.UserData
join b in context.UserDetails on a.Index equals b.Index into c
select new UserData{ Index = a.Index, Name = a.Name, PersonalNo = a.PersonalNo,
Details= c.ToList<object>() };
return Results;
}
The Type in the Watch windows is names as "object {MyTestApp.UserDetails}"
So basically it is working as I did it. But I need to cast it appropriate. Possibly now it is easier to help me.
Any suggestions?

Related

How can I merge duplicate objects with Linq while concatenating a property?

I have an object:
private class User
{
public string fullname { get; set; }
public string manager { get; set; }
public string businessunit { get; set; }
public string employeeid { get; set; }
public string mainphone { get; set; }
public string fax { get; set; }
public string mobile { get; set; }
public string email { get; set; }
public string street3 { get; set; }
public string street2 { get; set; }
public string street1 { get; set; }
public string city { get; set; }
public string stateorprovince { get; set; }
public string ziporpostalcode { get; set; }
public string department { get; set; }
public string countryorregion { get; set; }
public string salesarea { get; set; }
public string title { get; set; }
public string username { get; set; }
public string companyname { get; set; }
public string securityroles { get; set; }
public User()
{
}
}
I also have a list of that object:
List<User> users = new List<User>();
What I'd like to do is merge all Users in the list with the same fullname while concatenating all of their different securityroles into the same securityroles property.
I was thinking something along the lines of this would work:
users = (from user in users
group user by user.fullname
/*not sure what to put here*/).ToList();
I would write a function that merges a collection of Users into one and call that from your query:
private User Merge(IEnumerable<User> users)
{
User user = new User();
if(!users.Any()) return user; // or null, whatever you think is appropriate
user.fullname = users.First().fullname;
user.securityroles = string.Join(", ", users.Select(u => u.securityroles));
// similar rules/queries for other properties.
}
Then just call it from the main query:
users = (from user in users
group user by user.fullname into g
select Merge(g)
).ToList();
If you don't like having multiple queries in the Merge function, then re-write it as a foreach loop, or use whatever construct you see fit.
The point is to get something that works and defines your rules for "merge" outside of your Linq query, then make it better.
Using D Stanley answer, I ran the code on online compiler, with some mods. Needs to add the others properties in merge function, like Stanley said.
http://rextester.com/YJV50083
The user list (the 'A,B,C,D,E' are securityroles):
Users:
Test1 A
Test1 B
Test2 C
Test2 D
Test3 E
After linq:
New users:
Test1 A, B
Test2 C, D
Test3 E
Thank you D Stanley and mzaverez. This function works but I might change it since the merge function executes multiple queries:
private User Merge(IEnumerable<User> users)
{
User u = new User();
if (!users.Any())
{
return u;
}
else
{
u.fullname = users.First().fullname;
u.manager = users.First().manager;
u.businessunit = users.First().businessunit;
u.employeeid = users.First().employeeid;
u.mainphone = users.First().mainphone;
u.fax = users.First().fax;
u.mobile = users.First().mobile;
u.email = users.First().email;
u.street1 = users.First().street1;
u.street2 = users.First().street2;
u.street3 = users.First().street3;
u.city = users.First().city;
u.stateorprovince = users.First().stateorprovince;
u.ziporpostalcode = users.First().ziporpostalcode;
u.department = users.First().department;
u.countryorregion = users.First().countryorregion;
u.salesarea = users.First().salesarea;
u.title = users.First().title;
u.username = users.First().username;
u.companyname = users.First().companyname;
u.securityroles = string.Join(", ", users.Select(x => x.securityroles));
return u;
}
}
That function is called by the very helpful Linq code D Stanley suggested below:
users = (from user in users
group user by user.fullname into g
select Merge(g)
).ToList();

SQL multiple results with entity

I want to merge result of two SQL select statements into one.
Here is sample :
// class
public class _Product
{
public long ProductId { get; set; }
public string Description { get; set; }
}
public class _Company
{
public long CompanyId { get; set; }
public int posotion{ get; set; }
}
// C# entity
void runQyery()
{
string MultiQuery = "select ProductId, Description from product;"+
" select CompanyId, posotion from Company;";
_Product objPro = new _Product();
_Company objCom = new _Company();
// Is this right? What should I do now?
var result = _entities.Database.ExecuteSqlCommand(MultiQuery);
objPro = ...
objCom = ...
}
How can I finish my code? Is there any way to read some select on one trying?
Thanks for your attention

Complex Linq expression with a stored procedure

I am fairly new to MVC4 and I am working on a complex model: a model that contains a property of type IList along with properties of primitive types (strings and ints). The property of type IList should use a stored procedure and the primitive types uses a regular link query. Here is the code for the model:
public class EditUserModel
{
public IList<UserTranscript> UserTranscripts { get; set; }
public int? PersonID { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string StateCode { get; set; }
public string PostalCode { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
Here is the code for the UserTranscript class:
public class UserTranscript
{
public decimal Score { get; set; }
public DateTime CompletionDate { get; set; }
public string Status { get; set; }
}
Here is my method:
public EditUserModel GetUserRecord(int personid)
{
//using (var db = new TceoModel.TceoContext())
//{
MyContext db = new MyContext();
var user = (from p in db.People
from pu in db.PersonUsernames.Where(f => f.PersonID == p.UPID).DefaultIfEmpty()
from pe in db.PersonEmails.Where(a => a.PersonID == p.UPID).DefaultIfEmpty()
from pa in db.Addresses.Where(c => c.PersonID == p.UPID).DefaultIfEmpty()
from lnr in db.Activities.Where(y => y.ActivityID == un.ActivityID).DefaultIfEmpty()
from tr in db.uspTranscripts(personid)
where p.UPID == personid
select new EditUserModel
{
PersonID = p.UPID,
UserName = pu.Username,
Email = pe.Email,
FirstName = p.FirstName,
MiddleName = p.MiddleName,
LastName = p.LastName,
Address = pa.Address1,
City = pa.City,
StateCode = sc.StateAbbr,
PostalCode = pa.Zip,
Phone = pp.PhoneNumber
}).AsEnumerable().Select(s => new UserTranscript() {
**How to return a list of UserTranscripts using the stored procedure db.uspTranscripts(personid)**
});
My question is, how can I return the user list of transcripts on the second query using the db.uspTranscripts(personid) stored procedure?
Thanks.
I'm no expert with stored procedures in EF, but I've seen 2 ways to do this.
For example take a peek at https://msdn.microsoft.com/en-us/library/bb399357(v=vs.110).aspx. They have their example stored procedure written as a function so you could then use it like
// Usage
.AsEnumerable().Select(s => db.uspTranscripts(s));
// Stored Procedure
[Function(Name="dbo.CustOrderTotal")] //probably dbo.uspTranscripts in your case
[return: Parameter(DbType="Int")]
public int CustOrderTotal([Parameter(Name="CustomerID", DbType="NChar(5)")] string customerID, [Parameter(Name="TotalSales", DbType="Money")] ref System.Nullable<decimal> totalSales)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), customerID, totalSales);
totalSales = ((System.Nullable<decimal>)(result.GetParameterValue(1)));
return ((int)(result.ReturnValue));
}
Or you might be able to do it like the last line of code in this guy's answer where you actually reach in and grab the stored procedure to use it https://stackoverflow.com/a/20973919/4875338
The first appears to be the best way to do it if you are willing to rewrite the stored procedure in c#. Good luck!
First of all, try to use below link.
https://www.linqpad.net
It helped me a lot.
Secondly, I think that List have to stay inside
new EditUserModel() { UserTranscripts = tr }

Entity Framework to json - grouping data

I have a class named Client which looks like this:
public class Client
{
[Key, ForeignKey("BaseAssignments")]
public int ClientId { get; set; }
public string Owner { get; set; }
public string CompanyName { get; set; }
public virtual ICollection<BaseAssignment> BaseAssignments { get; set; }
}
And a class named Base looking like this:
public class Base
{
[Key, ForeignKey("BaseAssignments")]
public int BaseId { get; set; }
public string BaseName { get; set; }
public DateTime BaseStart { get; set; }
public DateTime BaseEnd { get; set; }
public virtual ICollection<BaseAssignment> BaseAssignments { get; set; }
}
They are to be joined with another class called BaseAssignment:
public class BaseAssignment
{
[Key]
public int BaseAssignmentId { get; set; }
public int BaseId { get; set; }
public int ClientId { get; set; }
public virtual Base Base { get; set; }
public virtual Client Client { get; set; }
}
The idea is that a client can be assigned to many bases, and one base can contain many clients.
Moving forward, I am trying to serialize base entitites in such way that a json representation of a base would have a collection of all it's clients as a subobject. A Web Api method that I'm trying to achieve this is:
db.Configuration.ProxyCreationEnabled = false;
var query = from b in db.Bases
group b by b.BaseId into nb
join ba in db.BaseAssignments on nb.FirstOrDefault().BaseId equals ba.BaseId
join c in db.Clients on ba.ClientId equals c.ClientId
select new BaseDTO
{
BaseName = nb.FirstOrDefault().BaseName,
BaseStart = nb.FirstOrDefault().BaseStart,
BaseEnd = nb.FirstOrDefault().BaseEnd,
Clients = from c1 in db.Clients select new ClientDTO
{
ClientId = c1.ClientId,
CompanyName = c1.CompanyName,
Owner = c1.Owner
}
};
return query;
where a BaseDTO looks like:
public class BaseDTO
{
public String BaseName { get; set; }
public DateTime BaseStart { get; set; }
public DateTime BaseEnd { get; set; }
public IQueryable<ClientDTO> Clients { get; set; }
}
and ClientDTO looks like:
public class ClientDTO
{
public int ClientId { get; set; }
public string Owner { get; set; }
public string CompanyName { get; set; }
}
As of now I'm getting an error stating that ClientDTO is an unexpected type. What can I do to fix this, or maybe the way that I've chosen is completely wrong? Thanks in advance for any insight on this.
EDIT
I've made some changes to the Web Api controller method, so it looks like:
db.Configuration.ProxyCreationEnabled = false;
var query = from b in db.Bases
group b by b.BaseId into nb
join ba in db.BaseAssignments on nb.FirstOrDefault().BaseId equals ba.BaseId
join c in db.Clients on ba.ClientId equals c.ClientId
select new BaseDTO
{
BaseName = nb.FirstOrDefault().BaseName,
BaseStart = nb.FirstOrDefault().BaseStart,
BaseEnd = nb.FirstOrDefault().BaseEnd,
Clients = new ClientDTO
{
ClientId = c.ClientId,
CompanyName = c.CompanyName,
Owner = c.Owner
}
};
return query;
This makes the Api produce a JSON, but it still contains a single object for every client, not every base.
You shouldn't have to group or join anything by hand for this, just use a sub-select and have LINQ to the heavy lifting.
from b in db.Bases
select new BaseDTO
{
BaseName = b.BaseName,
BaseStart = b.BaseStart,
BaseEnd = b.BaseEnd,
Clients =
from ba in b.BaseAssignments
from c in ba.Client
select new ClientDTO
{
ClientId = c.ClientId,
CompanyName = c.CompanyName,
Owner = c.Owner
}
}
Based on StriplingWarrior's suggestion, mixing best of both worlds into:
from b in db.Bases
select new BaseDTO
{
BaseName = b.BaseName,
BaseStart = b.BaseStart,
BaseEnd = b.BaseEnd,
Clients =
from ba in b.BaseAssignments
join c in db.Clients on ba.ClientId equals c.ClientId
select new ClientDTO
{
ClientId = c.ClientId,
CompanyName = c.CompanyName,
Owner = c.Owner
}
};
got the JSON I wanted - thanks.

Linq query results to List collection

I use the code below to get records from two tables but I want to have the result in a List. I used the code below, but this error occured:
Cannot implicitly convert type
System.Collections.Generic.List<AnonymousType#1> to
System.Collections.Generic.List<QuickRoutes.DAL.Route>
public List<Route> GetAllForUser(Guid userId)
{
// var result = new List<Route>();
aspnetdbDataContext aspdb = new aspnetdbDataContext();
List<Route> result = (from r in aspdb.Routes
where r.UserId == userId
join t in aspdb.TrackPoints on r.RouteId equals t.RouteFK
select t.TrackPointId,t.RouteFK,t.TrackTime,t.Longitude,t.Latitude,t.Elevation, r.SourceName).ToList();
return result;
}
EDIT:
I want to match my query with this class:
namespace QuickRoutes.Entities
{
public enum RouteType
{
Route, Waypoints, Track
}
public sealed class Route
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Time { get; set; }
public List<TrackPoint> TrackPoints { get; set; }
public Guid UserId { get; set; }
public string GpxData { get; set; }
public RouteType RouteType { get; set; }
public Route(int id)
{
Id = id;
TrackPoints = new List<TrackPoint>();
}
......
but if I change my code to this one,It doesn't work too
List<Route> result = (from r in aspdb.RouteLinqs
where r.UserId == userId
join t in aspdb.TrackPointlinqs on r.RouteId equals t.RouteFK
select r).ToList();
to be honest I want to change this function that is written with SQL to LINQ,have any better idee?
namespace QuickRoutes.Entities
{
public enum RouteType
{
Route, Waypoints, Track
}
public sealed class Route
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Time { get; set; }
public List<TrackPoint> TrackPoints { get; set; }
public Guid UserId { get; set; }
public string GpxData { get; set; }
public RouteType RouteType { get; set; }
public Route(int id)
{
Id = id;
TrackPoints = new List<TrackPoint>();
}
......
It's because your projection (what you're selecting) isn't the same as a Route (what you're trying to return);
If you wish to return a Route Change your select to:
select r
If you wish to return your joined projection, you'l have to create a new type, and return that:
e.g:
public class RouteTrack
{
public TrackPointId ...
public RouteFK ...
public TrackTime ...
}
And return a List<RouteTrack> from your method, and change your select to:
select new RouteTrack { TrackPointId = t.TrackPointId .... }
Since your query selects properties from two different tables, it obviously no longer returns objects of type Route, but a new type of object (an anonymous type).
If you want to return this new type, you need to define it explicitly, then return the data using this type.
public class MyClass
{
public MyClass(int trackPointId, DateTime trackTime, ...)
{
TrackPointId = trackPointId;
TrackTime = trackTime;
...
}
public int TrackPointId { get; set; }
public DateTime TrackTime { get; set }
...
}
List<MyClass> result = (from r in aspdb.Routes
where r.UserId == userId
join t in aspdb.TrackPoints on r.RouteId equals t.RouteFK
select new MyClass(t.TrackPointId,t.RouteFK,t.TrackTime,t.Longitude,t.Latitude,t.Elevation, r.SourceName);
I have faced the same. The issue here is that you are creating an anonymous type that contains fields from both the Route and aspdb.TrackPoints.
Hence you cannot cast this to List.
This is a mapping problem.
To resolve this you need to create a newcustom class that contains all the fields/properties that you are getting out from the query.
Let's say you create a custom class say RouteMapper then map using code like
select new RouterMapper
{
RouteMapper.TrackPointId = t.TrackPointId, RouteMapper.RouteFK=t.RouteFK, RouteMapper.SourceName = r.SourceName
}
This way now you return List< RouteMapper>.

Categories