list in entity framework and webapi - entity-framework

I am trying to return employee with three column in .net webapi with entity framework but return gives error saying cannot convert type pf anonymous to emp ..what I am missing
public List<EMPLOYEE_DTLS> GetLoginInfo(string UserId)
{
var result = (from emp in db.EMPLOYEE_DTLS
where emp.UserId == UserId
select new
{
emp.FullName,
emp.Role,
emp.Designation
}).ToList();
return result;
}

You should use a DTO to return the list.
public class EmployeeDTO
{
public string FullName {get; set;}
public string Role {get; set;}
public string Designation {get; set;}
}
public List<EmployeeDTO> GetLoginInfo(string UserId)
{
var result = (from emp in db.EMPLOYEE_DTLS
where emp.UserId == UserId
select new EmployeeDTO
{
FullName = emp.FullName,
Role = emp.Role,
Designation = emp.Designation
}).ToList();
return result;
}

Your method returns List<EMPLOYEE_DTLS>, but you are trying to return List of anonymous type.
Assuming you EMPLOYEE_DTLS class has properties FullName, Role and Designation change the type you are selecting:
public List<EMPLOYEE_DTLS> GetLoginInfo(string UserId)
{
var result = (from emp in db.EMPLOYEE_DTLS
where emp.UserId == UserId
select new EMPLOYEE_DTLS
{
FullName = emp.FullName,
Role = emp.Role,
Designation = emp.Designation
}).ToList();
return result;
}

Related

Inlining collections with EF Projection

I have the following classes:
public class Customer {
public int Id {get;set;}
public string Name {get;set;}
public List<Order> Orders {get;set;}
//other attributes
}
public class Order{
public int Id {get;set;}
public string Name {get;set;}
public decimal Value {get;set;}
}
Given a customerId I wish to only select the customer name and the order Id using projection in EF.
I am doing the following:
IQueryable<Customer> customer = DataContextFactory.GetDataContext().Set<Customer>();
var tempCustomer = customer.Where(x => x.Id == customerId).Select( c=>
new
{
Name = c.Name
}
)
This gives me the customer name. Which I can then pass back to the entity like so:
var customerToReturn = tempCustomer.ToList().Select(x => new Customer
{ Name = x.Name});
If I include the order on the query like this:
var tempCustomer = customer.Where(x => x.Id == customerId).Select( c=>
new
{
Name = c.Name,
Orders = new {
Id = c.Orders.Id
}
}
)
Then I get a duplicate customer per order line (as per the SQL generated by EF). Is there a way I can inline this generation into a single SQL call?
Currently I am getting around this by calling each child object separately.

Context SqlQuery<>() without detailing all columns

Let's say I have a Person entity with 3 columns:
public PERSON {
public int OID { get; set; }
public string NAME { get; set; }
public string SURNAME { get; set; }
}
I want to query it with raw SQL but without specifying all columns so I write:
var query = "select NAME, SURNAME from PERSON";
var list = context.SqlQuery<PERSON>(query).ToList();
But it throws Exception:
System.Data.Entity.Core.EntityCommandExecutionException : The data reader is incompatible with the specified '...'. A member of the type, 'OID', does not have a corresponding column in the data reader with the same name.
So it seems like it tries to map all columns, and, if some are missing, it throws.
Is there a way to make it ignore columns that are not present in raw SQL query and map just the columns that are accessible?
The reason is, I have a lot of columns for some entities and sometimes I just want to query partial columns. I don't want to create new class with just the necessary columns for each query.
I can think of 3 options off the top of my head that could work for you.
Option 1: Rewrite your queries and use a standard Linq query:
var persons = from p in context.Persons
select new PERSON
{
NAME = p.NAME,
SURNAME = p.SURNAME
};
Option 2: Return a dummy value for columns you don't need
var query = "select 0 AS OID, NAME, SURNAME from PERSON";
var list = context.SqlQuery<AlmostPERSON>(query).ToList();
Option 3: Create your own intermediate classes with the columns you need from the database:
public class AlmostPERSON
{
public string NAME { get; set; }
public string SURNAME { get; set; }
}
var query = "select NAME, SURNAME from PERSON";
var list = context.SqlQuery<AlmostPERSON>(query).ToList();
You could even project this intermediate class onto your standard entity like this:
var list = context.SqlQuery<AlmostPERSON>(query)
.Select(ap => new PERSON
{
NAME = ap.NAME,
SURNAME = ap.SURNAME
})
.ToList();
Found one more possible solution: using ADO.NET IDataReader with AutoMapper
public List<T> ExecuteFor<T>(string sql)
{
using (_connection = new OracleConnection(_connectionString))
{
_connection.Open();
using (var command = new OracleCommand(sql, _connection))
{
using (OracleDataReader reader = command.ExecuteReader())
{
Mapper.CreateMap<IDataReader, List<T>>();
return Mapper.Map<IDataReader, List<T>>(reader);
}
}
}
}

Converting ESQL to LINQ to Entities. Sort by related entities

I am using EF + RIA and unfortunately meet some problems with sorting by related entities.
For such purpose there is ESQL query that I implemented (found only this solution):
var queryESQL = string.Format(
#" select VALUE ent from SomeEntities as ent
join Attributes as ea ON ea.EntityId = ent.Id
where ea.AttributeTypeId = #typeId
order by ea.{0} {1}", columnName, descending ? "desc" : "asc");
var query = ObjectContext.CreateQuery<SomeEntity>(queryESQL, new ObjectParameter("typeId", attributeTypeId));
Tables have following structure:
<Attribute>:
int Id;
decimal DecimalColumn;
string StringColumn;
int EntityId;
int AttributeTypeId;
<SomeEntity>:
int Id;
string Name;
Is there any way to rewrite this stuff(sorting), using LINQ to Entities approach?
Here's my attempt, I can't guarantee it will work. I need to think more on how to get a dynamic column name, I'm not sure on that one. EDIT: you can use a string for the order column.
int typeId = 1115;
bool orderAscending = false;
string columnName = "StringColumn";
var query = from ent in SomeEntities
join ea in Attributes on ea.EntityId = ent.Id
where ea.AttributeTypeId = typeId;
if(orderAscending)
{
query = query.OrderBy(ea => columnName).Select(ea => ea.Value);
}
else
{
query = query.OrderByDescending(ea => columnName).Select(ea => ea.Value);
}
var results = query.ToList(); // call toList or enumerate to execute the query, since LINQ has deferred execution.
EDIT: I think that ordering after the select stops is from ordering by. I moved the select statement to after the order by. I also added the "query =", but I'm not sure if that is needed. I don't have a way to test this at the moment.
EDIT 3: I fired up LINQPad today and made a few tweaks to what I had before. I modeled your data in a Code-first approach to using EF and it should be close to what you have.
This approach works better if you're just trying to get a list of Attributes (which you aren't). To get around that I added an Entity property to the MyAttribute class.
This code works in LINQPAD.
void Main()
{
// add test entities as needed. I'm assuming you have an Attibutes collection on your Entity based on your tables.
List<MyEntity> SomeEntities = new List<MyEntity>();
MyEntity e1 = new MyEntity();
MyAttribute a1 = new MyAttribute(){ StringColumn="One", DecimalColumn=25.6M, Id=1, EntityId=1, AttributeTypeId = 1, Entity=e1 };
e1.Attributes.Add(a1);
e1.Id = 1;
e1.Name= "E1";
SomeEntities.Add(e1);
MyEntity e2 = new MyEntity();
MyAttribute a2 = new MyAttribute(){ StringColumn="Two", DecimalColumn=198.7M, Id=2, EntityId=2, AttributeTypeId = 1, Entity=e2 };
e2.Attributes.Add(a2);
e2.Id = 2;
e2.Name = "E2";
SomeEntities.Add(e2);
MyEntity e3 = new MyEntity();
MyAttribute a3 = new MyAttribute(){ StringColumn="Three", DecimalColumn=65.9M, Id=3, EntityId=3, AttributeTypeId = 1, Entity=e3 };
e3.Attributes.Add(a3);
e3.Id = 3;
e3.Name = "E3";
SomeEntities.Add(e3);
List<MyAttribute> attributes = new List<MyAttribute>();
attributes.Add(a1);
attributes.Add(a2);
attributes.Add(a3);
int typeId = 1;
bool orderAscending = true;
string columnName = "StringColumn";
var query = (from ent in SomeEntities
where ent.Attributes.Any(a => a.AttributeTypeId == typeId)
select ent.Attributes).SelectMany(a => a).AsQueryable();
query.Dump("Pre Ordering");
if(orderAscending)
{
// query = is needed
query = query.OrderBy(att => MyEntity.GetPropertyValue(att, columnName));
}
else
{
query = query.OrderByDescending(att => MyEntity.GetPropertyValue(att, columnName));
}
// returns a list of MyAttributes. If you need to get a list of attributes, add a MyEntity property to the MyAttribute class and populate it
var results = query.Select(att => att.Entity).ToList().Dump();
}
// Define other methods and classes here
}
class MyAttribute
{
public int Id { get; set; }
public decimal DecimalColumn { get; set; }
public string StringColumn { get; set; }
public int EntityId { get; set; }
public int AttributeTypeId { get; set; }
// having this property will require an Include in EF to return it then query, which is less effecient than the original ObjectQuery< for the question
public MyEntity Entity { get; set; }
}
class MyEntity
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<MyAttribute> Attributes { get; set; }
public MyEntity()
{
this.Attributes = new List<MyAttribute>();
}
// this could have been on any class, I stuck it here for ease of use in LINQPad
// caution reflection may be slow
public static object GetPropertyValue(object obj, string property)
{
// from Kjetil Watnedal on http://stackoverflow.com/questions/41244/dynamic-linq-orderby
System.Reflection.PropertyInfo propertyInfo=obj.GetType().GetProperty(property);
return propertyInfo.GetValue(obj, null);
}

Problems with selecting 2 column values in Linq to Entity

Hi I am trying to select the values of two columns which are second driver and price but I am getting error: Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Linq.IQueryable'. An explicit conversion exists (are you missing a cast?)
Below is the code:
public IQueryable<Event> GetSecondDriverOption(int eventID)
{
ApextrackdaysEntities entity = new ApextrackdaysEntities();
IQueryable<Event> SecondDriver = from p in entity.Events
where p.ID == eventID
select new{ p.SecondDriver,
p.SecondDriverPrice};
return SecondDriver;
}
Any help or suggestions will be appreciated thnx
You cannot use projection when you expect IQueryable<Event> where Event is your mapped type. You must either select Event :
IQueryable<Event> SecondDriver = from p in entity.Events
where p.ID == eventID
select p;
Or you must create new type and project data to a new type:
public class EventDto
{
public Driver SecondDriver { get; set; }
public Price SecondDriverPrice { get; set; }
}
and redefine your method:
public IQueryable<EventDto> GetSecondDriverOption(int eventID)
{
ApextrackdaysEntities entity = new ApextrackdaysEntities();
IQueryable<EventDto> SecondDriver = from p in entity.Events
where p.ID == eventID
select new EventDto
{
SecondDriver = p.SecondDriver,
SecondDriverPrice = p.SecondDriverPrice
};
return SecondDriver;
}
You cannot return anonymous objects. Try like this:
public IQueryable<Event> GetSecondDriverOption(int eventID)
{
ApextrackdaysEntities entity = new ApextrackdaysEntities();
var seconDriver =
from p in entity.Events
where p.ID == eventID;
select p;
return secondDriver;
}

Parse string to poco class enum in linq query MVC 2.0

I have the following enum and POCO class
public enum Gender
{
Male,
Female,
Unknown
}
public class Person
{
public int PersonId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public Gender? Gender { get; set; }
}
I would like to perform a "get all people" query in my repository such that it would look something like this:
return from p in _db.People
select new Model.Person
{
PersonId = p.PersonId,
LastName = p.LastName,
FirstName = p.FirstName,
Gender = p.Gender,
};
Unfortunately I get an error "Cannot implicitly convert type 'string' to 'Model.Gender'"
I would like to convert the string which is being queried from the entity framework to my Gender enum and assign it to my POCO class.
Enums are not supported in Entity Framework. There is a workaround by Alex James, but it's quite involved.
Instead, i prefer to do this:
public enum Gender : byte
{
Male = 1,
Female,
Unknown
}
public class Person
{
public int PersonId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public byte Gender { get; set; } // this is the EF model property
public Gender GenderType // this is an additional custom property
{
get { return (Gender) Gender; }
set { Gender = (byte)value; }
}
}
It's basically a hook/wrapper for the actual value. In your database, store Gender as a tinyint (which maps to byte on the conceptual side).
Then you can use a byte enum to map to and from the model property:
return from p in _db.People
select new Model.Person
{
PersonId = p.PersonId,
LastName = p.LastName,
FirstName = p.FirstName,
Gender = p.Gender, // sets byte
};
But then if you access that ViewModel, because your setting the byte field for Gender, you will also have access to the enum property GenderType.
Does that solve your problem?
The Entity Framework that I am familiar with does not provide support for enums. EF uses your query expression to create an SQL statement that it then sends to the server, if it cannot create the SQL equivalent of some operation it will throw a NotSupportedException for that operation. If you are expecting to return a small set of data you can separate from the Entity Framework by creating an object in memory using the ToArray method.
var myEntities = (from entity in _db.Entities
where /* condition */
select entity)
.ToArray();
This will create a sequence of entities in memory. Any further query statements will then be in the realm of LINQ to Objects which allows parsing of strings into enums:
return from myEntity in myEntities
select new MyDataContract
{
ID = myEntity.ID,
Gender g = (Gender)Enum.Parse(typeof(Gender), myEntity.Gender, true)
};
Or you could even break it out into a foreach loop:
List<MyDataContract> myDataContracts = new List<MyDataContract>();
foreach (var myEntity in myEntities)
{
var dataContract = new MyDataContract { ID = myEntity.ID };
if (Enum.IsDefined(typeof(Gender), myEntity.Gender))
dataContract.Gender = (Gender)Enum.Parse(typeof(Gender), myEntity.Gender, true);
myDataContracts.Add(dataContract);
}
return myDataContracts.AsEnumerable();
if (Enum.IsDefined(typeof(Gender), genderstring))
Gender g = (Gender) Enum.Parse(typeof(Gender), genderstring, true);
else
//Deal with invalid string.
try
Gender = p.Gender != null ? (Gender)Enum.Parse(typeof(Gender), p.Gender) : (Gender?)null;
To parse the string as one of the enums
here's a workaround but it means changing your nice and clean POCO
http://blogs.msdn.com/b/alexj/archive/2009/06/05/tip-23-how-to-fake-enums-in-ef-4.aspx