Linq to list, select only four columns from DB? - c#

My table has over 15 columns and I only want to retrieve four of those columns to store in memory. However trying the below method, gives the error cannot explicitly convert List to IEnumerable. Is this also the correct approach? Have a feeling I am missing a where clause or something? CompanyID is the index.
IEnumerable<Company> company = _db.Company.Select(a => new
{
CompanyId = Convert.ToString(a.CompanyId),
CompanyType = a.CompanyType,
CompanyName = a.CompanyName,
Email = a.Email
}).ToList();

You create an Anonymous Type with your Select statement and you can not convert List<definedAnonymousType> to IEnumerable<Company>.
Use var instead of IEnumerable<Company>.
var company = _db.Company.Select(a => new
{
CompanyId = Convert.ToString(a.CompanyId),
CompanyType = a.CompanyType,
CompanyName = a.CompanyName,
Email = a.Email
}).ToList();
then your company type will be List<definedAnonymousType>.

you can create CompanyLite dto with the exact properties you want and convert data to that
var companyLite = _db.Company.Select(a => new CompanyLite
{
CompanyId = Convert.ToString(a.CompanyId),
CompanyType = a.CompanyType,
CompanyName = a.CompanyName,
Email = a.Email
}).ToList();

Related

Query Entity Framework using C# and Navigation Properties

First of all I am new to both C# and EF.
I have created a number of entities with the the Model designer in VS 2015 CE and set the relationships.
I would like to query the entities to return all the customers for a specific Contract (e.g. Contract_ID = 1), along with related properties from the CustomerLocker and ContractCustomer entities (For the CustomerLocker Entity if they are present, or null if they are not). I also have the LockerNumber value from the Contract entity (e.g. 100).
I would be grateful if someone can help with the LINQ query required to select the properties I require. I would prefer to be able to use navigation properties if possible.
So far I am able to select the customers but not able to select properties from the CustomerLocker entity.
var myCustomers = (from cc in context.ContractCustomers
where cc.Contract_ID.Equals(contractID)
select new
{
Licencee = cc.IsLicencee,
Added = cc.AddedDate,
Firstname = cc.Customer.FirstName,
Lastname = cc.Customer.LastName,
DOB = cc.Customer.DateOfBirth,
Postcode = cc.Customer.PostCode,
CustomerNumber = cc.CustomerNumber
}
)
entities shown in VS Model Designer
You could get the HasCard from CustomerLockers by filtering on LockerNumber;
CustomerLockers = cc.Customer.CustomerLockers
The query;
var myCustomers = (from cc in context.ContractCustomers
where cc.Contract_ID.Equals(contractID)
select new
{
Licencee = cc.IsLicencee,
Added = cc.AddedDate,
Firstname = cc.Customer.FirstName,
Lastname = cc.Customer.LastName,
DOB = cc.Customer.DateOfBirth,
Postcode = cc.Customer.PostCode,
CustomerNumber = cc.CustomerNumber,
CustomerLockerHasCard = cc.Customer.CustomerLockers
.Where(x => x.LockerNumber == 1000)
.Select(x => x.HasCard)
}
)
Also, I suggest you to define model classes as known type instead of using anonymous type.
An option would be to get the list of customers instead of just the customer's number :
var myCustomers = (from cc in context.ContractCustomers
where cc.Contract_ID.Equals(contractID)
select new
{
Licencee = cc.IsLicencee,
Added = cc.AddedDate,
Firstname = cc.Customer.FirstName,
Lastname = cc.Customer.LastName,
DOB = cc.Customer.DateOfBirth,
Postcode = cc.Customer.PostCode,
CustomerNumber = cc.CustomerNumber,
listOfCustomers = cc.Customer.ToList() // <-Here, a list
}
)
Then you can use a loop :
foreach(var customer in myCustomers.listOfCustomers)
{
var listOfLockers = customer.CustomerLockers.ToList();
}
But this is more a beginner's way, remember it's always better to take everything you need in a single query, like Stormcloack's answer.
This answer is just to show you how you can dig in the entitys the easy way.

MVC error "requires ienumerable instead of list"

Trying to display values from 2 tables, staff and department so i tried to perform a linq sql query but it doesn't work when i open my application in the web browser. New to MVC and this is my first time using linq to sql so I'm not sure whats wrong!
My error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[<>f__AnonymousType74[System.String,System.String,StaffDetails.Models.Department,StaffDetails.Models.Site]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[StaffDetails.Models.Staff]'.
Index view
public ActionResult Index()
{
IList<Staff> staffList = new List<Staff>();
var query = (from s in db.Staffs
from d in db.Departments
where s.DeptID == d.DeptID
select new
{
name = s.Name,
email = s.Email,
department = s.Department,
site = d.Site
}
).ToList();
return View(query);
}
Tables
The problem is you are passing an anonymous type but your view expects IEnumerable<Staff>, so while projecting your LINQ query you need to project Staff type like this:-
List<Staff> query = (from s in db.Staffs
from d in db.Departments
where s.DeptID == d.DeptID
select new Staff //here
{
Name = s.Name,
Email= s.Email,
Department = s.Department,
Site = d.Site
}).ToList();
Update:
Okay so your Staff is a mapped entity so in that case you should not be able to map it directly. You either need a DTO or alternatively you can first project the anonymous type and bring the operation in linq-to-objects using AsEnumerable() and then project from there like this:-
IEnumerable<Staff> staffList = (from s in db.Staffs
from d in db.Departments
where s.DeptID == d.DeptID
select new
{
name = s.Name,
email = s.Email,
department = s.Department,
site = d.Site
}).AsEnumerable()
.Select(x => new new Staff
{
Name = x.name,
Email= x.email,
Department = x.department,
Site = x.site
});

Logic Method From a LINQ to SQL expression

What is the best practice for the following scenario:
I have a LINQ to SQL expression where in its projection I want to call a private method.
I understand that my method cannot be translated into SQL, but I do need the logic.
Changing the property after getting the query result is not possible since you cannot change a projected property (it is read only).
10x
var projectedOrders = from order in orders
select new
{
orderId = order.Id,
orderName = order.FriendlyName,
OrderDate = order.OrderDate,
CustomerName = helper.GetUserNameByUserId(order.UserId)
};
You'll have to do it in 2 steps
query the raw data from the database, and materialize it
project onwards using your logic
var projectedOrders = (from order in orders
select new
{
orderId = order.Id,
orderName = order.FriendlyName,
OrderDate = order.OrderDate,
UserId= order.UserId
})
.ToArray()
.Select(o =>
new{
o.orderId,
o.orderName,
o.OrderDate,
CustomerName = helper.GetUserNameByUserId(o.UserId)
});
You can store the UserId temporarily into a property and set CustomerNames to null, then use a loop after your query and change the value of CustomerNames:
var projectedOrders = (from order in orders
select new
{
orderId = order.Id,
orderName = order.FriendlyName,
OrderDate = order.OrderDate,
UserId = order.UserId,
CustomerName = null
}).ToList();
foreach(var order in projectedOrders)
order.CustomerName = helper.GetUserNameByUserId(order.UserId);

Can't reference variable from anonymous type

I am grabbing a value and want it to appear in the BatchId of every anonymous type created via a linq statement.
Here is the code:
var batchId = context.Request["batchid"];
using (var db = new StarterSiteEntities())
{ // Get data
var transactions = (from t in db.Transactions
join td in db.TransactionDetails on t.TransactionID equals td.TransactionID
join p in db.Products on td.ProductID equals p.ProductID
where t.Exported == false
select new
{
BatchId = batchId,
t.FirstName,
t.LastName,
t.Address1,
t.Address2,
t.City,
t.State,
t.Zip_Code,
t.Email,
t.Phone,
t.TotalAmount,
t.MonthlyGift,
t.DateCreated,
p.Fund,
ProductFirstName = p.FirstName,
ProductLastName = p.LastName,
ProductUniversity = p.University,
ProductState = p.State,
ProductEmail = p.Email,
ProductAmount = td.Amount
}).ToList();
}
When I do this, I get the error message:
"A parameter is not allowed in this location. Ensure that the '#' sign is in a valid location or that parameters are valid at all in this SQL statement."
How do I reference the batchId variable from within the anonymous type declaration, or should I accomplish this another way?
It looks like you ran into a known bug in the SQL Server CE data access libraries. You should be able to fix it by applying this hotfix to the machine(s) that are accessing the database.
While I think Adam Maras answered my question. Because I did not want to install a hot-fix on the server, I ended up solving the problem using a different method.
Since the Linq query would not allow me to use a string variable and I could not edit the property value of an anonymous type. I stopped using an anonymous type and created an entity class to hold my "transaction summary" data.
Once I have a collection of TransactionSummary objects, I can use the Select() method to update the BatchId property value in each record.
Here is the resulting code:
// Define a custom type to hold the data
private class TransactionSummary
{
public string BatchId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
//...removed lines for brevity...
}
//...here is the updated code snippet...
using (var db = new StarterSiteEntities())
{ // Get data
var transactions = (from t in db.Transactions
join td in db.TransactionDetails on t.TransactionID equals td.TransactionID
join p in db.Products on td.ProductID equals p.ProductID
where t.Exported == false
select new TransactionSummary
{
FirstName = t.FirstName,
LastName = t.LastName,
//...removed lines for brevity...
}).ToList();
// The client would like a batchID added to each record that we return.
var batchId = context.Request["batchid"];
transactions.Select(t => { t.BatchId = batchId; return t; }).ToList();
}

Getting Specific Columns in Entity Framework

I would like to get the list of users from the database, but I want only 5 columns instead of all (it has about 35 columns). When I wrote like the following, it shows me no error at the compile time but the error at the runtime.
bksb_Users is the table name in my database as well as object name in the Entity Model.
public List<bksb_Users> SearchStudents(string reference, string firstname, string lastname)
{
return (from u in context.bksb_Users
where u.userName.Contains(reference)
&& u.FirstName.Contains(firstname)
&& u.LastName.Contains(lastname)
orderby u.FirstName, u.LastName
select new bksb_Users
{
user_id = u.user_id,
userName = u.userName,
FirstName = u.FirstName,
LastName = u.LastName,
DOB = u.DOB
}).Take(100).ToList<bksb_Users>();
}
The error is...
The entity or complex type 'bksbModel.bksb_Users' cannot be constructed in a LINQ to Entities query.
Does below work?
public List<bksb_Users> SearchStudents(string reference, string firstname, string lastname)
{
var anon = (from u in context.bksb_Users
where u.userName.Contains(reference)
&& u.FirstName.Contains(firstname)
&& u.LastName.Contains(lastname)
orderby u.FirstName, u.LastName
select new
{
user_id = u.user_id,
userName = u.userName,
FirstName = u.FirstName,
LastName = u.LastName,
DOB = u.DOB
}).Take(100).ToList();
return anon.Select(z => new bksb_Users()
{
user_id = z.user_id, userName = z.userName, FirstName = z.FirstName, DOB = z.DOB
}).ToList();
}
All I have done is split the task into two steps:
Get the data out (into an anonymous type) using LINQ to Entities.
Convert the anonymous type into the desired type using LINQ to
Objects.
Note a better option would be to create a new type (class) that contains just the fields/properties you need - that would remove the need for step 2, and will make it clear to the callers of your function which columns are 'populated' and which aren't. It also means you are less likely to 'accidentally' try and persist these half populated entities back to the database.
for some reason i quess that field DOB looks something like this
public object DOB { get { return fieldX + fieldY } }
Entity framework does not understand that. All fields in query must be mapped with certain columns in DB

Categories

Resources